1 // Copyright 2014 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/xfa_textlayout.h"
8 
9 #include <algorithm>
10 
11 #include "core/fxcrt/include/fx_ext.h"
12 #include "xfa/fde/cfde_path.h"
13 #include "xfa/fde/css/fde_csscache.h"
14 #include "xfa/fde/css/fde_cssstyleselector.h"
15 #include "xfa/fde/fde_gedevice.h"
16 #include "xfa/fde/fde_object.h"
17 #include "xfa/fde/xml/fde_xml_imp.h"
18 #include "xfa/fgas/crt/fgas_codepage.h"
19 #include "xfa/fxfa/app/xfa_ffwidgetacc.h"
20 #include "xfa/fxfa/include/xfa_ffapp.h"
21 #include "xfa/fxfa/include/xfa_ffdoc.h"
22 #include "xfa/fxfa/include/xfa_fontmgr.h"
23 
CXFA_CSSTagProvider()24 CXFA_CSSTagProvider::CXFA_CSSTagProvider()
25     : m_bTagAvailable(FALSE), m_bContent(FALSE) {}
26 
~CXFA_CSSTagProvider()27 CXFA_CSSTagProvider::~CXFA_CSSTagProvider() {}
28 
XFA_TextPiece()29 XFA_TextPiece::XFA_TextPiece()
30     : pszText(nullptr), pFont(nullptr), pLinkData(nullptr) {}
31 
~XFA_TextPiece()32 XFA_TextPiece::~XFA_TextPiece() {
33   if (pLinkData)
34     pLinkData->Release();
35 }
36 
CXFA_TextParseContext()37 CXFA_TextParseContext::CXFA_TextParseContext()
38     : m_pParentStyle(nullptr),
39       m_ppMatchedDecls(nullptr),
40       m_dwMatchedDecls(0),
41       m_eDisplay(FDE_CSSDISPLAY_None) {}
42 
~CXFA_TextParseContext()43 CXFA_TextParseContext::~CXFA_TextParseContext() {
44   if (m_pParentStyle)
45     m_pParentStyle->Release();
46   FX_Free(m_ppMatchedDecls);
47 }
48 
SetDecls(const CFDE_CSSDeclaration ** ppDeclArray,int32_t iDeclCount)49 void CXFA_TextParseContext::SetDecls(const CFDE_CSSDeclaration** ppDeclArray,
50                                      int32_t iDeclCount) {
51   if (iDeclCount <= 0 || !ppDeclArray)
52     return;
53 
54   m_dwMatchedDecls = iDeclCount;
55   m_ppMatchedDecls = FX_Alloc(CFDE_CSSDeclaration*, iDeclCount);
56   FXSYS_memcpy(m_ppMatchedDecls, ppDeclArray,
57                iDeclCount * sizeof(CFDE_CSSDeclaration*));
58 }
59 
CXFA_TextParser()60 CXFA_TextParser::CXFA_TextParser() : m_pUASheet(nullptr) {}
61 
~CXFA_TextParser()62 CXFA_TextParser::~CXFA_TextParser() {
63   if (m_pUASheet)
64     m_pUASheet->Release();
65 
66   FX_POSITION ps = m_mapXMLNodeToParseContext.GetStartPosition();
67   while (ps) {
68     CFDE_XMLNode* pXMLNode;
69     CXFA_TextParseContext* pParseContext;
70     m_mapXMLNodeToParseContext.GetNextAssoc(ps, pXMLNode, pParseContext);
71     if (pParseContext)
72       FXTARGET_DeleteWith(CXFA_TextParseContext, m_pAllocator.get(),
73                           pParseContext);
74   }
75   m_mapXMLNodeToParseContext.RemoveAll();
76 }
Reset()77 void CXFA_TextParser::Reset() {
78   FX_POSITION ps = m_mapXMLNodeToParseContext.GetStartPosition();
79   while (ps) {
80     CFDE_XMLNode* pXMLNode;
81     CXFA_TextParseContext* pParseContext;
82     m_mapXMLNodeToParseContext.GetNextAssoc(ps, pXMLNode, pParseContext);
83     if (pParseContext)
84       FXTARGET_DeleteWith(CXFA_TextParseContext, m_pAllocator.get(),
85                           pParseContext);
86   }
87   m_mapXMLNodeToParseContext.RemoveAll();
88   m_pAllocator.reset();
89 }
InitCSSData(CXFA_TextProvider * pTextProvider)90 void CXFA_TextParser::InitCSSData(CXFA_TextProvider* pTextProvider) {
91   if (!pTextProvider)
92     return;
93 
94   if (!m_pSelector) {
95     CXFA_FFDoc* pDoc = pTextProvider->GetDocNode();
96     IFGAS_FontMgr* pFontMgr = pDoc->GetApp()->GetFDEFontMgr();
97     ASSERT(pFontMgr);
98     m_pSelector.reset(new CFDE_CSSStyleSelector);
99     m_pSelector->SetFontMgr(pFontMgr);
100     FX_FLOAT fFontSize = 10;
101     CXFA_Font font = pTextProvider->GetFontNode();
102     if (font) {
103       fFontSize = font.GetFontSize();
104     }
105     m_pSelector->SetDefFontSize(fFontSize);
106   }
107   if (!m_pUASheet) {
108     m_pUASheet = LoadDefaultSheetStyle();
109     m_pSelector->SetStyleSheet(FDE_CSSSTYLESHEETGROUP_UserAgent, m_pUASheet);
110     m_pSelector->UpdateStyleIndex(FDE_CSSMEDIATYPE_ALL);
111   }
112 }
113 
CXFA_LoaderContext()114 CXFA_LoaderContext::CXFA_LoaderContext()
115     : m_bSaveLineHeight(FALSE),
116       m_fWidth(0),
117       m_fHeight(0),
118       m_fLastPos(0),
119       m_fStartLineOffset(0),
120       m_iChar(0),
121       m_iTotalLines(-1),
122       m_pXMLNode(nullptr),
123       m_pNode(nullptr),
124       m_pParentStyle(nullptr),
125       m_dwFlags(0) {}
126 
~CXFA_LoaderContext()127 CXFA_LoaderContext::~CXFA_LoaderContext() {}
128 
LoadDefaultSheetStyle()129 IFDE_CSSStyleSheet* CXFA_TextParser::LoadDefaultSheetStyle() {
130   static const FX_WCHAR s_pStyle[] =
131       L"html,body,ol,p,ul{display:block}"
132       L"li{display:list-item}"
133       L"ol,ul{padding-left:33px}ol{list-style-type:decimal}ol,ul{margin-top:0;"
134       L"margin-bottom:0}ul,ol{margin:1.12em 0}"
135       L"a{color:#0000ff;text-decoration:underline}b{font-weight:bolder}i{font-"
136       L"style:italic}"
137       L"sup{vertical-align:+15em;font-size:.66em}sub{vertical-align:-15em;font-"
138       L"size:.66em}";
139   return IFDE_CSSStyleSheet::LoadFromBuffer(
140       CFX_WideString(), s_pStyle, FXSYS_wcslen(s_pStyle), FX_CODEPAGE_UTF8);
141 }
CreateRootStyle(CXFA_TextProvider * pTextProvider)142 IFDE_CSSComputedStyle* CXFA_TextParser::CreateRootStyle(
143     CXFA_TextProvider* pTextProvider) {
144   CXFA_Font font = pTextProvider->GetFontNode();
145   CXFA_Para para = pTextProvider->GetParaNode();
146   IFDE_CSSComputedStyle* pStyle = m_pSelector->CreateComputedStyle(nullptr);
147   IFDE_CSSFontStyle* pFontStyle = pStyle->GetFontStyles();
148   IFDE_CSSParagraphStyle* pParaStyle = pStyle->GetParagraphStyles();
149   FX_FLOAT fLineHeight = 0, fFontSize = 10;
150   if (para) {
151     fLineHeight = para.GetLineHeight();
152     FDE_CSSLENGTH indent;
153     indent.Set(FDE_CSSLENGTHUNIT_Point, para.GetTextIndent());
154     pParaStyle->SetTextIndent(indent);
155     FDE_CSSTEXTALIGN hAlign = FDE_CSSTEXTALIGN_Left;
156     switch (para.GetHorizontalAlign()) {
157       case XFA_ATTRIBUTEENUM_Center:
158         hAlign = FDE_CSSTEXTALIGN_Center;
159         break;
160       case XFA_ATTRIBUTEENUM_Right:
161         hAlign = FDE_CSSTEXTALIGN_Right;
162         break;
163       case XFA_ATTRIBUTEENUM_Justify:
164         hAlign = FDE_CSSTEXTALIGN_Justify;
165         break;
166       case XFA_ATTRIBUTEENUM_JustifyAll:
167         hAlign = FDE_CSSTEXTALIGN_JustifyAll;
168         break;
169     }
170     pParaStyle->SetTextAlign(hAlign);
171     FDE_CSSRECT rtMarginWidth;
172     rtMarginWidth.left.Set(FDE_CSSLENGTHUNIT_Point, para.GetMarginLeft());
173     rtMarginWidth.top.Set(FDE_CSSLENGTHUNIT_Point, para.GetSpaceAbove());
174     rtMarginWidth.right.Set(FDE_CSSLENGTHUNIT_Point, para.GetMarginRight());
175     rtMarginWidth.bottom.Set(FDE_CSSLENGTHUNIT_Point, para.GetSpaceBelow());
176     pStyle->GetBoundaryStyles()->SetMarginWidth(rtMarginWidth);
177   }
178   if (font) {
179     pFontStyle->SetColor(font.GetColor());
180     pFontStyle->SetFontStyle(font.IsItalic() ? FDE_CSSFONTSTYLE_Italic
181                                              : FDE_CSSFONTSTYLE_Normal);
182     pFontStyle->SetFontWeight(font.IsBold() ? FXFONT_FW_BOLD
183                                             : FXFONT_FW_NORMAL);
184     pParaStyle->SetNumberVerticalAlign(-font.GetBaselineShift());
185     fFontSize = font.GetFontSize();
186     FDE_CSSLENGTH letterSpacing;
187     letterSpacing.Set(FDE_CSSLENGTHUNIT_Point, font.GetLetterSpacing());
188     pParaStyle->SetLetterSpacing(letterSpacing);
189     uint32_t dwDecoration = 0;
190     if (font.GetLineThrough() > 0) {
191       dwDecoration |= FDE_CSSTEXTDECORATION_LineThrough;
192     }
193     if (font.GetUnderline() > 1) {
194       dwDecoration |= FDE_CSSTEXTDECORATION_Double;
195     } else if (font.GetUnderline() > 0) {
196       dwDecoration |= FDE_CSSTEXTDECORATION_Underline;
197     }
198     pParaStyle->SetTextDecoration(dwDecoration);
199   }
200   pParaStyle->SetLineHeight(fLineHeight);
201   pFontStyle->SetFontSize(fFontSize);
202   return pStyle;
203 }
CreateStyle(IFDE_CSSComputedStyle * pParentStyle)204 IFDE_CSSComputedStyle* CXFA_TextParser::CreateStyle(
205     IFDE_CSSComputedStyle* pParentStyle) {
206   IFDE_CSSComputedStyle* pNewStyle =
207       m_pSelector->CreateComputedStyle(pParentStyle);
208   ASSERT(pNewStyle);
209   if (pParentStyle) {
210     IFDE_CSSParagraphStyle* pParaStyle = pParentStyle->GetParagraphStyles();
211     uint32_t dwDecoration = pParaStyle->GetTextDecoration();
212     FX_FLOAT fBaseLine = 0;
213     if (pParaStyle->GetVerticalAlign() == FDE_CSSVERTICALALIGN_Number) {
214       fBaseLine = pParaStyle->GetNumberVerticalAlign();
215     }
216     pParaStyle = pNewStyle->GetParagraphStyles();
217     pParaStyle->SetTextDecoration(dwDecoration);
218     pParaStyle->SetNumberVerticalAlign(fBaseLine);
219     IFDE_CSSBoundaryStyle* pBoundarytyle = pParentStyle->GetBoundaryStyles();
220     const FDE_CSSRECT* pRect = pBoundarytyle->GetMarginWidth();
221     if (pRect) {
222       pBoundarytyle = pNewStyle->GetBoundaryStyles();
223       pBoundarytyle->SetMarginWidth(*pRect);
224     }
225   }
226   return pNewStyle;
227 }
ComputeStyle(CFDE_XMLNode * pXMLNode,IFDE_CSSComputedStyle * pParentStyle)228 IFDE_CSSComputedStyle* CXFA_TextParser::ComputeStyle(
229     CFDE_XMLNode* pXMLNode,
230     IFDE_CSSComputedStyle* pParentStyle) {
231   CXFA_TextParseContext* pContext = static_cast<CXFA_TextParseContext*>(
232       m_mapXMLNodeToParseContext.GetValueAt(pXMLNode));
233   if (!pContext)
234     return nullptr;
235   pContext->m_pParentStyle = pParentStyle;
236   pParentStyle->Retain();
237   CXFA_CSSTagProvider tagProvider;
238   ParseTagInfo(pXMLNode, tagProvider);
239   if (tagProvider.m_bContent)
240     return nullptr;
241   IFDE_CSSComputedStyle* pStyle = CreateStyle(pParentStyle);
242   CFDE_CSSAccelerator* pCSSAccel = m_pSelector->InitAccelerator();
243   pCSSAccel->OnEnterTag(&tagProvider);
244   m_pSelector->ComputeStyle(&tagProvider, pContext->GetDecls(),
245                             pContext->CountDecls(), pStyle);
246   pCSSAccel->OnLeaveTag(&tagProvider);
247   return pStyle;
248 }
DoParse(CFDE_XMLNode * pXMLContainer,CXFA_TextProvider * pTextProvider)249 void CXFA_TextParser::DoParse(CFDE_XMLNode* pXMLContainer,
250                               CXFA_TextProvider* pTextProvider) {
251   if (!pXMLContainer || !pTextProvider || m_pAllocator) {
252     return;
253   }
254   m_pAllocator.reset(IFX_MemoryAllocator::Create(FX_ALLOCTYPE_Fixed, 32,
255                                                  sizeof(CXFA_CSSTagProvider)));
256   InitCSSData(pTextProvider);
257   IFDE_CSSComputedStyle* pRootStyle = CreateRootStyle(pTextProvider);
258   ParseRichText(pXMLContainer, pRootStyle);
259   pRootStyle->Release();
260 }
ParseRichText(CFDE_XMLNode * pXMLNode,IFDE_CSSComputedStyle * pParentStyle)261 void CXFA_TextParser::ParseRichText(CFDE_XMLNode* pXMLNode,
262                                     IFDE_CSSComputedStyle* pParentStyle) {
263   if (!pXMLNode)
264     return;
265 
266   CXFA_CSSTagProvider tagProvider;
267   ParseTagInfo(pXMLNode, tagProvider);
268   if (!tagProvider.m_bTagAvailable)
269     return;
270 
271   IFDE_CSSComputedStyle* pNewStyle = nullptr;
272   if ((tagProvider.GetTagName() != FX_WSTRC(L"body")) ||
273       (tagProvider.GetTagName() != FX_WSTRC(L"html"))) {
274     CXFA_TextParseContext* pTextContext =
275         FXTARGET_NewWith(m_pAllocator.get()) CXFA_TextParseContext;
276     FDE_CSSDISPLAY eDisplay = FDE_CSSDISPLAY_Inline;
277     if (!tagProvider.m_bContent) {
278       pNewStyle = CreateStyle(pParentStyle);
279       CFDE_CSSAccelerator* pCSSAccel = m_pSelector->InitAccelerator();
280       pCSSAccel->OnEnterTag(&tagProvider);
281       CFDE_CSSDeclarationArray DeclArray;
282       int32_t iMatchedDecls =
283           m_pSelector->MatchDeclarations(&tagProvider, DeclArray);
284       const CFDE_CSSDeclaration** ppMatchDecls =
285           const_cast<const CFDE_CSSDeclaration**>(DeclArray.GetData());
286       m_pSelector->ComputeStyle(&tagProvider, ppMatchDecls, iMatchedDecls,
287                                 pNewStyle);
288       pCSSAccel->OnLeaveTag(&tagProvider);
289       if (iMatchedDecls > 0) {
290         pTextContext->SetDecls(ppMatchDecls, iMatchedDecls);
291       }
292       eDisplay = pNewStyle->GetPositionStyles()->GetDisplay();
293     }
294     pTextContext->SetDisplay(eDisplay);
295     m_mapXMLNodeToParseContext.SetAt(pXMLNode, pTextContext);
296   }
297   for (CFDE_XMLNode* pXMLChild =
298            pXMLNode->GetNodeItem(CFDE_XMLNode::FirstChild);
299        pXMLChild;
300        pXMLChild = pXMLChild->GetNodeItem(CFDE_XMLNode::NextSibling)) {
301     ParseRichText(pXMLChild, pNewStyle);
302   }
303   if (pNewStyle)
304     pNewStyle->Release();
305 }
306 
TagValidate(const CFX_WideString & wsName) const307 bool CXFA_TextParser::TagValidate(const CFX_WideString& wsName) const {
308   static const uint32_t s_XFATagName[] = {
309       0x61,        // a
310       0x62,        // b
311       0x69,        // i
312       0x70,        // p
313       0x0001f714,  // br
314       0x00022a55,  // li
315       0x000239bb,  // ol
316       0x00025881,  // ul
317       0x0bd37faa,  // sub
318       0x0bd37fb8,  // sup
319       0xa73e3af2,  // span
320       0xb182eaae,  // body
321       0xdb8ac455,  // html
322   };
323   static const int32_t s_iCount = FX_ArraySize(s_XFATagName);
324 
325   return std::binary_search(s_XFATagName, s_XFATagName + s_iCount,
326                             FX_HashCode_GetW(wsName.AsStringC(), true));
327 }
328 
ParseTagInfo(CFDE_XMLNode * pXMLNode,CXFA_CSSTagProvider & tagProvider)329 void CXFA_TextParser::ParseTagInfo(CFDE_XMLNode* pXMLNode,
330                                    CXFA_CSSTagProvider& tagProvider) {
331   CFX_WideString wsName;
332   if (pXMLNode->GetType() == FDE_XMLNODE_Element) {
333     CFDE_XMLElement* pXMLElement = static_cast<CFDE_XMLElement*>(pXMLNode);
334     pXMLElement->GetLocalTagName(wsName);
335     tagProvider.SetTagNameObj(wsName);
336     tagProvider.m_bTagAvailable = TagValidate(wsName);
337 
338     CFX_WideString wsValue;
339     pXMLElement->GetString(L"style", wsValue);
340     if (!wsValue.IsEmpty()) {
341       tagProvider.SetAttribute(L"style", wsValue);
342     }
343   } else if (pXMLNode->GetType() == FDE_XMLNODE_Text) {
344     tagProvider.m_bTagAvailable = TRUE;
345     tagProvider.m_bContent = TRUE;
346   }
347 }
348 
GetVAlign(CXFA_TextProvider * pTextProvider) const349 int32_t CXFA_TextParser::GetVAlign(CXFA_TextProvider* pTextProvider) const {
350   CXFA_Para para = pTextProvider->GetParaNode();
351   return para ? para.GetVerticalAlign() : XFA_ATTRIBUTEENUM_Top;
352 }
353 
GetTabInterval(IFDE_CSSComputedStyle * pStyle) const354 FX_FLOAT CXFA_TextParser::GetTabInterval(IFDE_CSSComputedStyle* pStyle) const {
355   CFX_WideString wsValue;
356   if (pStyle && pStyle->GetCustomStyle(FX_WSTRC(L"tab-interval"), wsValue))
357     return CXFA_Measurement(wsValue.AsStringC()).ToUnit(XFA_UNIT_Pt);
358   return 36;
359 }
360 
CountTabs(IFDE_CSSComputedStyle * pStyle) const361 int32_t CXFA_TextParser::CountTabs(IFDE_CSSComputedStyle* pStyle) const {
362   CFX_WideString wsValue;
363   if (pStyle && pStyle->GetCustomStyle(FX_WSTRC(L"xfa-tab-count"), wsValue))
364     return wsValue.GetInteger();
365   return 0;
366 }
367 
IsSpaceRun(IFDE_CSSComputedStyle * pStyle) const368 FX_BOOL CXFA_TextParser::IsSpaceRun(IFDE_CSSComputedStyle* pStyle) const {
369   CFX_WideString wsValue;
370   if (pStyle && pStyle->GetCustomStyle(FX_WSTRC(L"xfa-spacerun"), wsValue)) {
371     wsValue.MakeLower();
372     return wsValue == FX_WSTRC(L"yes");
373   }
374   return FALSE;
375 }
GetFont(CXFA_TextProvider * pTextProvider,IFDE_CSSComputedStyle * pStyle) const376 CFGAS_GEFont* CXFA_TextParser::GetFont(CXFA_TextProvider* pTextProvider,
377                                        IFDE_CSSComputedStyle* pStyle) const {
378   CFX_WideStringC wsFamily = FX_WSTRC(L"Courier");
379   uint32_t dwStyle = 0;
380   CXFA_Font font = pTextProvider->GetFontNode();
381   if (font) {
382     font.GetTypeface(wsFamily);
383     if (font.IsBold()) {
384       dwStyle |= FX_FONTSTYLE_Bold;
385     }
386     if (font.IsItalic()) {
387       dwStyle |= FX_FONTSTYLE_Italic;
388     }
389   }
390   if (pStyle) {
391     IFDE_CSSFontStyle* pFontStyle = pStyle->GetFontStyles();
392     int32_t iCount = pFontStyle->CountFontFamilies();
393     if (iCount > 0) {
394       wsFamily = pFontStyle->GetFontFamily(iCount - 1);
395     }
396     dwStyle = 0;
397     if (pFontStyle->GetFontWeight() > FXFONT_FW_NORMAL) {
398       dwStyle |= FX_FONTSTYLE_Bold;
399     }
400     if (pFontStyle->GetFontStyle() == FDE_CSSFONTSTYLE_Italic) {
401       dwStyle |= FX_FONTSTYLE_Italic;
402     }
403   }
404   CXFA_FFDoc* pDoc = pTextProvider->GetDocNode();
405   CXFA_FontMgr* pFontMgr = pDoc->GetApp()->GetXFAFontMgr();
406   return pFontMgr->GetFont(pDoc, wsFamily, dwStyle);
407 }
GetFontSize(CXFA_TextProvider * pTextProvider,IFDE_CSSComputedStyle * pStyle) const408 FX_FLOAT CXFA_TextParser::GetFontSize(CXFA_TextProvider* pTextProvider,
409                                       IFDE_CSSComputedStyle* pStyle) const {
410   if (pStyle)
411     return pStyle->GetFontStyles()->GetFontSize();
412 
413   CXFA_Font font = pTextProvider->GetFontNode();
414   if (font) {
415     return font.GetFontSize();
416   }
417   return 10;
418 }
GetHorScale(CXFA_TextProvider * pTextProvider,IFDE_CSSComputedStyle * pStyle,CFDE_XMLNode * pXMLNode) const419 int32_t CXFA_TextParser::GetHorScale(CXFA_TextProvider* pTextProvider,
420                                      IFDE_CSSComputedStyle* pStyle,
421                                      CFDE_XMLNode* pXMLNode) const {
422   if (pStyle) {
423     CFX_WideString wsValue;
424     if (pStyle->GetCustomStyle(FX_WSTRC(L"xfa-font-horizontal-scale"),
425                                wsValue)) {
426       return wsValue.GetInteger();
427     }
428     while (pXMLNode) {
429       CXFA_TextParseContext* pContext = static_cast<CXFA_TextParseContext*>(
430           m_mapXMLNodeToParseContext.GetValueAt(pXMLNode));
431       if (pContext && pContext->m_pParentStyle &&
432           pContext->m_pParentStyle->GetCustomStyle(
433               FX_WSTRC(L"xfa-font-horizontal-scale"), wsValue)) {
434         return wsValue.GetInteger();
435       }
436       pXMLNode = pXMLNode->GetNodeItem(CFDE_XMLNode::Parent);
437     }
438   }
439   if (CXFA_Font font = pTextProvider->GetFontNode()) {
440     return static_cast<int32_t>(font.GetHorizontalScale());
441   }
442   return 100;
443 }
GetVerScale(CXFA_TextProvider * pTextProvider,IFDE_CSSComputedStyle * pStyle) const444 int32_t CXFA_TextParser::GetVerScale(CXFA_TextProvider* pTextProvider,
445                                      IFDE_CSSComputedStyle* pStyle) const {
446   if (pStyle) {
447     CFX_WideString wsValue;
448     if (pStyle->GetCustomStyle(FX_WSTRC(L"xfa-font-vertical-scale"), wsValue)) {
449       return wsValue.GetInteger();
450     }
451   }
452   if (CXFA_Font font = pTextProvider->GetFontNode()) {
453     return (int32_t)font.GetVerticalScale();
454   }
455   return 100;
456 }
GetUnderline(CXFA_TextProvider * pTextProvider,IFDE_CSSComputedStyle * pStyle,int32_t & iUnderline,int32_t & iPeriod) const457 void CXFA_TextParser::GetUnderline(CXFA_TextProvider* pTextProvider,
458                                    IFDE_CSSComputedStyle* pStyle,
459                                    int32_t& iUnderline,
460                                    int32_t& iPeriod) const {
461   iUnderline = 0;
462   iPeriod = XFA_ATTRIBUTEENUM_All;
463   if (pStyle) {
464     uint32_t dwDecoration = pStyle->GetParagraphStyles()->GetTextDecoration();
465     if (dwDecoration & FDE_CSSTEXTDECORATION_Double) {
466       iUnderline = 2;
467     } else if (dwDecoration & FDE_CSSTEXTDECORATION_Underline) {
468       iUnderline = 1;
469     }
470     CFX_WideString wsValue;
471     if (pStyle->GetCustomStyle(FX_WSTRC(L"underlinePeriod"), wsValue)) {
472       if (wsValue == FX_WSTRC(L"word")) {
473         iPeriod = XFA_ATTRIBUTEENUM_Word;
474       }
475     } else if (CXFA_Font font = pTextProvider->GetFontNode()) {
476       iPeriod = font.GetUnderlinePeriod();
477     }
478   } else {
479     CXFA_Font font = pTextProvider->GetFontNode();
480     if (font) {
481       iUnderline = font.GetUnderline();
482       iPeriod = font.GetUnderlinePeriod();
483     }
484   }
485 }
GetLinethrough(CXFA_TextProvider * pTextProvider,IFDE_CSSComputedStyle * pStyle,int32_t & iLinethrough) const486 void CXFA_TextParser::GetLinethrough(CXFA_TextProvider* pTextProvider,
487                                      IFDE_CSSComputedStyle* pStyle,
488                                      int32_t& iLinethrough) const {
489   if (pStyle) {
490     uint32_t dwDecoration = pStyle->GetParagraphStyles()->GetTextDecoration();
491     iLinethrough = (dwDecoration & FDE_CSSTEXTDECORATION_LineThrough) ? 1 : 0;
492   } else {
493     CXFA_Font font = pTextProvider->GetFontNode();
494     if (font) {
495       iLinethrough = font.GetLineThrough();
496     }
497   }
498 }
GetColor(CXFA_TextProvider * pTextProvider,IFDE_CSSComputedStyle * pStyle) const499 FX_ARGB CXFA_TextParser::GetColor(CXFA_TextProvider* pTextProvider,
500                                   IFDE_CSSComputedStyle* pStyle) const {
501   if (pStyle)
502     return pStyle->GetFontStyles()->GetColor();
503 
504   if (CXFA_Font font = pTextProvider->GetFontNode())
505     return font.GetColor();
506 
507   return 0xFF000000;
508 }
GetBaseline(CXFA_TextProvider * pTextProvider,IFDE_CSSComputedStyle * pStyle) const509 FX_FLOAT CXFA_TextParser::GetBaseline(CXFA_TextProvider* pTextProvider,
510                                       IFDE_CSSComputedStyle* pStyle) const {
511   if (pStyle) {
512     IFDE_CSSParagraphStyle* pParaStyle = pStyle->GetParagraphStyles();
513     if (pParaStyle->GetVerticalAlign() == FDE_CSSVERTICALALIGN_Number) {
514       return pParaStyle->GetNumberVerticalAlign();
515     }
516   } else if (CXFA_Font font = pTextProvider->GetFontNode()) {
517     return font.GetBaselineShift();
518   }
519   return 0;
520 }
GetLineHeight(CXFA_TextProvider * pTextProvider,IFDE_CSSComputedStyle * pStyle,FX_BOOL bFirst,FX_FLOAT fVerScale) const521 FX_FLOAT CXFA_TextParser::GetLineHeight(CXFA_TextProvider* pTextProvider,
522                                         IFDE_CSSComputedStyle* pStyle,
523                                         FX_BOOL bFirst,
524                                         FX_FLOAT fVerScale) const {
525   FX_FLOAT fLineHeight = 0;
526   if (pStyle) {
527     fLineHeight = pStyle->GetParagraphStyles()->GetLineHeight();
528   } else if (CXFA_Para para = pTextProvider->GetParaNode()) {
529     fLineHeight = para.GetLineHeight();
530   }
531   if (bFirst) {
532     FX_FLOAT fFontSize = GetFontSize(pTextProvider, pStyle);
533     if (fLineHeight < 0.1f) {
534       fLineHeight = fFontSize;
535     } else {
536       fLineHeight = std::min(fLineHeight, fFontSize);
537     }
538   } else if (fLineHeight < 0.1f) {
539     fLineHeight = GetFontSize(pTextProvider, pStyle) * 1.2f;
540   }
541   fLineHeight *= fVerScale;
542   return fLineHeight;
543 }
GetEmbbedObj(CXFA_TextProvider * pTextProvider,CFDE_XMLNode * pXMLNode,CFX_WideString & wsValue)544 FX_BOOL CXFA_TextParser::GetEmbbedObj(CXFA_TextProvider* pTextProvider,
545                                       CFDE_XMLNode* pXMLNode,
546                                       CFX_WideString& wsValue) {
547   wsValue.clear();
548   if (!pXMLNode) {
549     return FALSE;
550   }
551   FX_BOOL bRet = FALSE;
552   if (pXMLNode->GetType() == FDE_XMLNODE_Element) {
553     CFDE_XMLElement* pElement = static_cast<CFDE_XMLElement*>(pXMLNode);
554     CFX_WideString wsAttr;
555     pElement->GetString(L"xfa:embed", wsAttr);
556     if (wsAttr.IsEmpty()) {
557       return FALSE;
558     }
559     if (wsAttr.GetAt(0) == L'#') {
560       wsAttr.Delete(0);
561     }
562     CFX_WideString ws;
563     pElement->GetString(L"xfa:embedType", ws);
564     if (ws.IsEmpty()) {
565       ws = L"som";
566     } else {
567       ws.MakeLower();
568     }
569     FX_BOOL bURI = (ws == FX_WSTRC(L"uri"));
570     if (!bURI && ws != FX_WSTRC(L"som")) {
571       return FALSE;
572     }
573     ws.clear();
574     pElement->GetString(L"xfa:embedMode", ws);
575     if (ws.IsEmpty()) {
576       ws = L"formatted";
577     } else {
578       ws.MakeLower();
579     }
580     FX_BOOL bRaw = (ws == FX_WSTRC(L"raw"));
581     if (!bRaw && ws != FX_WSTRC(L"formatted")) {
582       return FALSE;
583     }
584     bRet = pTextProvider->GetEmbbedObj(bURI, bRaw, wsAttr, wsValue);
585   }
586   return bRet;
587 }
GetParseContextFromMap(CFDE_XMLNode * pXMLNode)588 CXFA_TextParseContext* CXFA_TextParser::GetParseContextFromMap(
589     CFDE_XMLNode* pXMLNode) {
590   return (CXFA_TextParseContext*)m_mapXMLNodeToParseContext.GetValueAt(
591       pXMLNode);
592 }
593 enum XFA_TABSTOPSSTATUS {
594   XFA_TABSTOPSSTATUS_Error,
595   XFA_TABSTOPSSTATUS_EOS,
596   XFA_TABSTOPSSTATUS_None,
597   XFA_TABSTOPSSTATUS_Alignment,
598   XFA_TABSTOPSSTATUS_StartLeader,
599   XFA_TABSTOPSSTATUS_Leader,
600   XFA_TABSTOPSSTATUS_Location,
601 };
GetTabstops(IFDE_CSSComputedStyle * pStyle,CXFA_TextTabstopsContext * pTabstopContext)602 FX_BOOL CXFA_TextParser::GetTabstops(
603     IFDE_CSSComputedStyle* pStyle,
604     CXFA_TextTabstopsContext* pTabstopContext) {
605   if (!pStyle || !pTabstopContext) {
606     return FALSE;
607   }
608   CFX_WideString wsValue;
609   if (!pStyle->GetCustomStyle(FX_WSTRC(L"xfa-tab-stops"), wsValue) &&
610       !pStyle->GetCustomStyle(FX_WSTRC(L"tab-stops"), wsValue)) {
611     return FALSE;
612   }
613   int32_t iLength = wsValue.GetLength();
614   const FX_WCHAR* pTabStops = wsValue.c_str();
615   int32_t iCur = 0;
616   int32_t iLast = 0;
617   CFX_WideString wsAlign;
618   XFA_TABSTOPSSTATUS eStatus = XFA_TABSTOPSSTATUS_None;
619   FX_WCHAR ch;
620   while (iCur < iLength) {
621     ch = pTabStops[iCur];
622     switch (eStatus) {
623       case XFA_TABSTOPSSTATUS_None:
624         if (ch <= ' ') {
625           iCur++;
626         } else {
627           eStatus = XFA_TABSTOPSSTATUS_Alignment;
628           iLast = iCur;
629         }
630         break;
631       case XFA_TABSTOPSSTATUS_Alignment:
632         if (ch == ' ') {
633           wsAlign = CFX_WideStringC(pTabStops + iLast, iCur - iLast);
634           eStatus = XFA_TABSTOPSSTATUS_StartLeader;
635           iCur++;
636           while (iCur < iLength && pTabStops[iCur] <= ' ') {
637             iCur++;
638           }
639           iLast = iCur;
640         } else {
641           iCur++;
642         }
643         break;
644       case XFA_TABSTOPSSTATUS_StartLeader:
645         if (ch != 'l') {
646           eStatus = XFA_TABSTOPSSTATUS_Location;
647         } else {
648           int32_t iCount = 0;
649           while (iCur < iLength) {
650             ch = pTabStops[iCur];
651             iCur++;
652             if (ch == '(') {
653               iCount++;
654             } else if (ch == ')') {
655               iCount--;
656               if (iCount == 0) {
657                 break;
658               }
659             }
660           }
661           while (iCur < iLength && pTabStops[iCur] <= ' ') {
662             iCur++;
663           }
664           iLast = iCur;
665           eStatus = XFA_TABSTOPSSTATUS_Location;
666         }
667         break;
668       case XFA_TABSTOPSSTATUS_Location:
669         if (ch == ' ') {
670           uint32_t dwHashCode = FX_HashCode_GetW(wsAlign.AsStringC(), true);
671           CXFA_Measurement ms(CFX_WideStringC(pTabStops + iLast, iCur - iLast));
672           FX_FLOAT fPos = ms.ToUnit(XFA_UNIT_Pt);
673           pTabstopContext->Append(dwHashCode, fPos);
674           wsAlign.clear();
675           eStatus = XFA_TABSTOPSSTATUS_None;
676         }
677         iCur++;
678         break;
679       default:
680         break;
681     }
682   }
683   if (!wsAlign.IsEmpty()) {
684     uint32_t dwHashCode = FX_HashCode_GetW(wsAlign.AsStringC(), true);
685     CXFA_Measurement ms(CFX_WideStringC(pTabStops + iLast, iCur - iLast));
686     FX_FLOAT fPos = ms.ToUnit(XFA_UNIT_Pt);
687     pTabstopContext->Append(dwHashCode, fPos);
688   }
689   return TRUE;
690 }
CXFA_TextLayout(CXFA_TextProvider * pTextProvider)691 CXFA_TextLayout::CXFA_TextLayout(CXFA_TextProvider* pTextProvider)
692     : m_bHasBlock(FALSE),
693       m_pTextProvider(pTextProvider),
694       m_pTextDataNode(nullptr),
695       m_bRichText(FALSE),
696       m_iLines(0),
697       m_fMaxWidth(0),
698       m_bBlockContinue(TRUE) {
699   ASSERT(m_pTextProvider);
700 }
~CXFA_TextLayout()701 CXFA_TextLayout::~CXFA_TextLayout() {
702   m_textParser.Reset();
703   Unload();
704 }
Unload()705 void CXFA_TextLayout::Unload() {
706   int32_t iCount = m_pieceLines.GetSize();
707   for (int32_t i = 0; i < iCount; i++) {
708     CXFA_PieceLine* pLine = m_pieceLines.GetAt(i);
709     FXTARGET_DeleteWith(CXFA_PieceLine, m_pAllocator.get(), pLine);
710   }
711   m_pieceLines.RemoveAll();
712   m_pBreak.reset();
713   m_pAllocator.reset();
714 }
GetPieceLines()715 const CXFA_PieceLineArray* CXFA_TextLayout::GetPieceLines() {
716   return &m_pieceLines;
717 }
GetTextDataNode()718 void CXFA_TextLayout::GetTextDataNode() {
719   if (!m_pTextProvider) {
720     return;
721   }
722   CXFA_Node* pNode = m_pTextProvider->GetTextNode(m_bRichText);
723   if (pNode && m_bRichText) {
724     m_textParser.Reset();
725   }
726   m_pTextDataNode = pNode;
727 }
GetXMLContainerNode()728 CFDE_XMLNode* CXFA_TextLayout::GetXMLContainerNode() {
729   CFDE_XMLNode* pXMLContainer = nullptr;
730   if (m_bRichText) {
731     CFDE_XMLNode* pXMLRoot = m_pTextDataNode->GetXMLMappingNode();
732     if (!pXMLRoot) {
733       return pXMLContainer;
734     }
735     for (CFDE_XMLNode* pXMLChild =
736              pXMLRoot->GetNodeItem(CFDE_XMLNode::FirstChild);
737          pXMLChild;
738          pXMLChild = pXMLChild->GetNodeItem(CFDE_XMLNode::NextSibling)) {
739       if (pXMLChild->GetType() == FDE_XMLNODE_Element) {
740         CFDE_XMLElement* pXMLElement = static_cast<CFDE_XMLElement*>(pXMLChild);
741         CFX_WideString wsTag;
742         pXMLElement->GetLocalTagName(wsTag);
743         if (wsTag == FX_WSTRC(L"body") || wsTag == FX_WSTRC(L"html")) {
744           pXMLContainer = pXMLChild;
745           break;
746         }
747       }
748     }
749   }
750   return pXMLContainer;
751 }
CreateBreak(FX_BOOL bDefault)752 CFX_RTFBreak* CXFA_TextLayout::CreateBreak(FX_BOOL bDefault) {
753   uint32_t dwStyle = FX_RTFLAYOUTSTYLE_ExpandTab;
754   if (!bDefault) {
755     dwStyle |= FX_RTFLAYOUTSTYLE_Pagination;
756   }
757   CFX_RTFBreak* pBreak = new CFX_RTFBreak(0);
758   pBreak->SetLayoutStyles(dwStyle);
759   pBreak->SetLineBreakChar(L'\n');
760   pBreak->SetLineBreakTolerance(1);
761   pBreak->SetFont(m_textParser.GetFont(m_pTextProvider, nullptr));
762   pBreak->SetFontSize(m_textParser.GetFontSize(m_pTextProvider, nullptr));
763   return pBreak;
764 }
InitBreak(FX_FLOAT fLineWidth)765 void CXFA_TextLayout::InitBreak(FX_FLOAT fLineWidth) {
766   CXFA_Font font = m_pTextProvider->GetFontNode();
767   CXFA_Para para = m_pTextProvider->GetParaNode();
768   FX_FLOAT fStart = 0;
769   FX_FLOAT fStartPos = 0;
770   if (para) {
771     int32_t iAlign = FX_RTFLINEALIGNMENT_Left;
772     switch (para.GetHorizontalAlign()) {
773       case XFA_ATTRIBUTEENUM_Center:
774         iAlign = FX_RTFLINEALIGNMENT_Center;
775         break;
776       case XFA_ATTRIBUTEENUM_Right:
777         iAlign = FX_RTFLINEALIGNMENT_Right;
778         break;
779       case XFA_ATTRIBUTEENUM_Justify:
780         iAlign = FX_RTFLINEALIGNMENT_Justified;
781         break;
782       case XFA_ATTRIBUTEENUM_JustifyAll:
783         iAlign = FX_RTFLINEALIGNMENT_Distributed;
784         break;
785     }
786     m_pBreak->SetAlignment(iAlign);
787     fStart = para.GetMarginLeft();
788     if (m_pTextProvider->IsCheckButtonAndAutoWidth()) {
789       if (iAlign != FX_RTFLINEALIGNMENT_Left) {
790         fLineWidth -= para.GetMarginRight();
791       }
792     } else {
793       fLineWidth -= para.GetMarginRight();
794     }
795     if (fLineWidth < 0) {
796       fLineWidth = fStart;
797     }
798     fStartPos = fStart;
799     FX_FLOAT fIndent = para.GetTextIndent();
800     if (fIndent > 0) {
801       fStartPos += fIndent;
802     }
803   }
804   m_pBreak->SetLineBoundary(fStart, fLineWidth);
805   m_pBreak->SetLineStartPos(fStartPos);
806   if (font) {
807     m_pBreak->SetHorizontalScale((int32_t)font.GetHorizontalScale());
808     m_pBreak->SetVerticalScale((int32_t)font.GetVerticalScale());
809     m_pBreak->SetCharSpace(font.GetLetterSpacing());
810   }
811   FX_FLOAT fFontSize = m_textParser.GetFontSize(m_pTextProvider, nullptr);
812   m_pBreak->SetFontSize(fFontSize);
813   m_pBreak->SetFont(m_textParser.GetFont(m_pTextProvider, nullptr));
814   m_pBreak->SetLineBreakTolerance(fFontSize * 0.2f);
815 }
InitBreak(IFDE_CSSComputedStyle * pStyle,FDE_CSSDISPLAY eDisplay,FX_FLOAT fLineWidth,CFDE_XMLNode * pXMLNode,IFDE_CSSComputedStyle * pParentStyle)816 void CXFA_TextLayout::InitBreak(IFDE_CSSComputedStyle* pStyle,
817                                 FDE_CSSDISPLAY eDisplay,
818                                 FX_FLOAT fLineWidth,
819                                 CFDE_XMLNode* pXMLNode,
820                                 IFDE_CSSComputedStyle* pParentStyle) {
821   if (!pStyle) {
822     InitBreak(fLineWidth);
823     return;
824   }
825   IFDE_CSSParagraphStyle* pParaStyle = pStyle->GetParagraphStyles();
826   if (eDisplay == FDE_CSSDISPLAY_Block || eDisplay == FDE_CSSDISPLAY_ListItem) {
827     int32_t iAlign = FX_RTFLINEALIGNMENT_Left;
828     switch (pParaStyle->GetTextAlign()) {
829       case FDE_CSSTEXTALIGN_Right:
830         iAlign = FX_RTFLINEALIGNMENT_Right;
831         break;
832       case FDE_CSSTEXTALIGN_Center:
833         iAlign = FX_RTFLINEALIGNMENT_Center;
834         break;
835       case FDE_CSSTEXTALIGN_Justify:
836         iAlign = FX_RTFLINEALIGNMENT_Justified;
837         break;
838       case FDE_CSSTEXTALIGN_JustifyAll:
839         iAlign = FX_RTFLINEALIGNMENT_Distributed;
840         break;
841       default:
842         break;
843     }
844     m_pBreak->SetAlignment(iAlign);
845     FX_FLOAT fStart = 0;
846     const FDE_CSSRECT* pRect = pStyle->GetBoundaryStyles()->GetMarginWidth();
847     const FDE_CSSRECT* pPaddingRect =
848         pStyle->GetBoundaryStyles()->GetPaddingWidth();
849     if (pRect) {
850       fStart = pRect->left.GetValue();
851       fLineWidth -= pRect->right.GetValue();
852       if (pPaddingRect) {
853         fStart += pPaddingRect->left.GetValue();
854         fLineWidth -= pPaddingRect->right.GetValue();
855       }
856       if (eDisplay == FDE_CSSDISPLAY_ListItem) {
857         const FDE_CSSRECT* pParRect =
858             pParentStyle->GetBoundaryStyles()->GetMarginWidth();
859         const FDE_CSSRECT* pParPaddingRect =
860             pParentStyle->GetBoundaryStyles()->GetPaddingWidth();
861         if (pParRect) {
862           fStart += pParRect->left.GetValue();
863           fLineWidth -= pParRect->right.GetValue();
864           if (pParPaddingRect) {
865             fStart += pParPaddingRect->left.GetValue();
866             fLineWidth -= pParPaddingRect->right.GetValue();
867           }
868         }
869         FDE_CSSRECT pNewRect;
870         pNewRect.left.Set(FDE_CSSLENGTHUNIT_Point, fStart);
871         pNewRect.right.Set(FDE_CSSLENGTHUNIT_Point, pRect->right.GetValue());
872         pNewRect.top.Set(FDE_CSSLENGTHUNIT_Point, pRect->top.GetValue());
873         pNewRect.bottom.Set(FDE_CSSLENGTHUNIT_Point, pRect->bottom.GetValue());
874         pStyle->GetBoundaryStyles()->SetMarginWidth(pNewRect);
875       }
876     }
877     m_pBreak->SetLineBoundary(fStart, fLineWidth);
878     FX_FLOAT fIndent = pParaStyle->GetTextIndent().GetValue();
879     if (fIndent > 0) {
880       fStart += fIndent;
881     }
882     m_pBreak->SetLineStartPos(fStart);
883     m_pBreak->SetTabWidth(m_textParser.GetTabInterval(pStyle));
884     if (!m_pTabstopContext)
885       m_pTabstopContext.reset(new CXFA_TextTabstopsContext);
886     m_textParser.GetTabstops(pStyle, m_pTabstopContext.get());
887     for (int32_t i = 0; i < m_pTabstopContext->m_iTabCount; i++) {
888       XFA_TABSTOPS* pTab = m_pTabstopContext->m_tabstops.GetDataPtr(i);
889       m_pBreak->AddPositionedTab(pTab->fTabstops);
890     }
891   }
892   FX_FLOAT fFontSize = m_textParser.GetFontSize(m_pTextProvider, pStyle);
893   m_pBreak->SetFontSize(fFontSize);
894   m_pBreak->SetLineBreakTolerance(fFontSize * 0.2f);
895   m_pBreak->SetFont(m_textParser.GetFont(m_pTextProvider, pStyle));
896   m_pBreak->SetHorizontalScale(
897       m_textParser.GetHorScale(m_pTextProvider, pStyle, pXMLNode));
898   m_pBreak->SetVerticalScale(m_textParser.GetVerScale(m_pTextProvider, pStyle));
899   m_pBreak->SetCharSpace(pParaStyle->GetLetterSpacing().GetValue());
900 }
GetText(CFX_WideString & wsText)901 int32_t CXFA_TextLayout::GetText(CFX_WideString& wsText) {
902   GetTextDataNode();
903   wsText.clear();
904   if (m_bRichText) {
905   } else {
906     wsText = m_pTextDataNode->GetContent();
907   }
908   return wsText.GetLength();
909 }
GetLayoutHeight()910 FX_FLOAT CXFA_TextLayout::GetLayoutHeight() {
911   if (!m_pLoader) {
912     return 0;
913   }
914   int32_t iCount = m_pLoader->m_lineHeights.GetSize();
915   if (iCount == 0 && m_pLoader->m_fWidth > 0) {
916     CFX_SizeF szMax(m_pLoader->m_fWidth, m_pLoader->m_fHeight);
917     CFX_SizeF szDef;
918     m_pLoader->m_bSaveLineHeight = TRUE;
919     m_pLoader->m_fLastPos = 0;
920     CalcSize(szMax, szMax, szDef);
921     m_pLoader->m_bSaveLineHeight = FALSE;
922     return szDef.y;
923   }
924   FX_FLOAT fHeight = m_pLoader->m_fHeight;
925   if (fHeight < 0.1f) {
926     fHeight = 0;
927     for (int32_t i = 0; i < iCount; i++) {
928       fHeight += m_pLoader->m_lineHeights.ElementAt(i);
929     }
930   }
931   return fHeight;
932 }
StartLayout(FX_FLOAT fWidth)933 FX_FLOAT CXFA_TextLayout::StartLayout(FX_FLOAT fWidth) {
934   if (!m_pLoader)
935     m_pLoader.reset(new CXFA_LoaderContext);
936 
937   if (fWidth < 0 || (m_pLoader->m_fWidth > -1 &&
938                      FXSYS_fabs(fWidth - m_pLoader->m_fWidth) > 0)) {
939     m_pLoader->m_lineHeights.RemoveAll();
940     m_Blocks.RemoveAll();
941     Unload();
942     m_pLoader->m_fStartLineOffset = 0;
943   }
944   m_pLoader->m_fWidth = fWidth;
945   if (fWidth < 0) {
946     CFX_SizeF szMax;
947     CFX_SizeF szDef;
948     m_pLoader->m_bSaveLineHeight = TRUE;
949     m_pLoader->m_fLastPos = 0;
950     CalcSize(szMax, szMax, szDef);
951     m_pLoader->m_bSaveLineHeight = FALSE;
952     fWidth = szDef.x;
953   }
954   return fWidth;
955 }
DoLayout(int32_t iBlockIndex,FX_FLOAT & fCalcHeight,FX_FLOAT fContentAreaHeight,FX_FLOAT fTextHeight)956 FX_BOOL CXFA_TextLayout::DoLayout(int32_t iBlockIndex,
957                                   FX_FLOAT& fCalcHeight,
958                                   FX_FLOAT fContentAreaHeight,
959                                   FX_FLOAT fTextHeight) {
960   if (!m_pLoader) {
961     return FALSE;
962   }
963   int32_t iBlockCount = m_Blocks.GetSize();
964   FX_FLOAT fHeight = fTextHeight;
965   if (fHeight < 0) {
966     fHeight = GetLayoutHeight();
967   }
968   m_pLoader->m_fHeight = fHeight;
969   if (fContentAreaHeight < 0) {
970     return FALSE;
971   }
972   m_bHasBlock = TRUE;
973   if (iBlockCount == 0 && fHeight > 0) {
974     fHeight = fTextHeight - GetLayoutHeight();
975     if (fHeight > 0) {
976       int32_t iAlign = m_textParser.GetVAlign(m_pTextProvider);
977       if (iAlign == XFA_ATTRIBUTEENUM_Middle) {
978         fHeight /= 2.0f;
979       } else if (iAlign != XFA_ATTRIBUTEENUM_Bottom) {
980         fHeight = 0;
981       }
982       m_pLoader->m_fStartLineOffset = fHeight;
983     }
984   }
985   FX_FLOAT fLinePos = m_pLoader->m_fStartLineOffset;
986   int32_t iLineIndex = 0;
987   if (iBlockCount > 1) {
988     if (iBlockCount >= (iBlockIndex + 1) * 2) {
989       iLineIndex = m_Blocks.ElementAt(iBlockIndex * 2);
990     } else {
991       iLineIndex = m_Blocks.ElementAt(iBlockCount - 1) +
992                    m_Blocks.ElementAt(iBlockCount - 2);
993     }
994     if (m_pLoader->m_BlocksHeight.GetSize() > 0) {
995       for (int32_t i = 0; i < iBlockIndex; i++) {
996         fLinePos -= m_pLoader->m_BlocksHeight.ElementAt(i * 2 + 1);
997       }
998     }
999   }
1000   int32_t iCount = m_pLoader->m_lineHeights.GetSize();
1001   int32_t i = 0;
1002   for (i = iLineIndex; i < iCount; i++) {
1003     FX_FLOAT fLineHeight = m_pLoader->m_lineHeights.ElementAt(i);
1004     if ((i == iLineIndex) && (fLineHeight - fContentAreaHeight > 0.001)) {
1005       fCalcHeight = 0;
1006       return TRUE;
1007     }
1008     if (fLinePos + fLineHeight - fContentAreaHeight > 0.001) {
1009       if (iBlockCount >= (iBlockIndex + 1) * 2) {
1010         m_Blocks.SetAt(iBlockIndex * 2, iLineIndex);
1011         m_Blocks.SetAt(iBlockIndex * 2 + 1, i - iLineIndex);
1012       } else {
1013         m_Blocks.Add(iLineIndex);
1014         m_Blocks.Add(i - iLineIndex);
1015       }
1016       if (i == iLineIndex) {
1017         if (fCalcHeight <= fLinePos) {
1018           if (m_pLoader->m_BlocksHeight.GetSize() > iBlockIndex * 2 &&
1019               (m_pLoader->m_BlocksHeight.GetAt(iBlockIndex * 2) ==
1020                iBlockIndex)) {
1021             m_pLoader->m_BlocksHeight.SetAt(iBlockIndex * 2 + 1, fCalcHeight);
1022           } else {
1023             m_pLoader->m_BlocksHeight.Add((FX_FLOAT)iBlockIndex);
1024             m_pLoader->m_BlocksHeight.Add(fCalcHeight);
1025           }
1026         }
1027         return TRUE;
1028       }
1029       fCalcHeight = fLinePos;
1030       return TRUE;
1031     }
1032     fLinePos += fLineHeight;
1033   }
1034   return FALSE;
1035 }
CountBlocks() const1036 int32_t CXFA_TextLayout::CountBlocks() const {
1037   int32_t iCount = m_Blocks.GetSize() / 2;
1038   return iCount > 0 ? iCount : 1;
1039 }
1040 
CalcSize(const CFX_SizeF & minSize,const CFX_SizeF & maxSize,CFX_SizeF & defaultSize)1041 FX_BOOL CXFA_TextLayout::CalcSize(const CFX_SizeF& minSize,
1042                                   const CFX_SizeF& maxSize,
1043                                   CFX_SizeF& defaultSize) {
1044   defaultSize.x = maxSize.x;
1045   if (defaultSize.x < 1)
1046     defaultSize.x = 0xFFFF;
1047 
1048   m_pBreak.reset(CreateBreak(FALSE));
1049   FX_FLOAT fLinePos = 0;
1050   m_iLines = 0;
1051   m_fMaxWidth = 0;
1052   Loader(defaultSize, fLinePos, FALSE);
1053   if (fLinePos < 0.1f)
1054     fLinePos = m_textParser.GetFontSize(m_pTextProvider, nullptr);
1055 
1056   m_pTabstopContext.reset();
1057   defaultSize = CFX_SizeF(m_fMaxWidth, fLinePos);
1058   return TRUE;
1059 }
1060 
Layout(const CFX_SizeF & size,FX_FLOAT * fHeight)1061 FX_BOOL CXFA_TextLayout::Layout(const CFX_SizeF& size, FX_FLOAT* fHeight) {
1062   if (size.x < 1)
1063     return FALSE;
1064 
1065   Unload();
1066   m_pBreak.reset(CreateBreak(TRUE));
1067   if (m_pLoader) {
1068     m_pLoader->m_iTotalLines = -1;
1069     m_pLoader->m_iChar = 0;
1070   }
1071   m_iLines = 0;
1072   FX_FLOAT fLinePos = 0;
1073   Loader(size, fLinePos, TRUE);
1074   UpdateAlign(size.y, fLinePos);
1075   m_pTabstopContext.reset();
1076   if (fHeight)
1077     *fHeight = fLinePos;
1078   return TRUE;
1079 }
1080 
Layout(int32_t iBlock)1081 FX_BOOL CXFA_TextLayout::Layout(int32_t iBlock) {
1082   if (!m_pLoader || iBlock < 0 || iBlock >= CountBlocks())
1083     return FALSE;
1084   if (m_pLoader->m_fWidth < 1)
1085     return FALSE;
1086 
1087   m_pLoader->m_iTotalLines = -1;
1088   m_iLines = 0;
1089   FX_FLOAT fLinePos = 0;
1090   CXFA_Node* pNode = nullptr;
1091   CFX_SizeF szText(m_pLoader->m_fWidth, m_pLoader->m_fHeight);
1092   int32_t iCount = m_Blocks.GetSize();
1093   int32_t iBlocksHeightCount = m_pLoader->m_BlocksHeight.GetSize();
1094   iBlocksHeightCount /= 2;
1095   if (iBlock < iBlocksHeightCount)
1096     return TRUE;
1097   if (iBlock == iBlocksHeightCount) {
1098     Unload();
1099     m_pBreak.reset(CreateBreak(TRUE));
1100     fLinePos = m_pLoader->m_fStartLineOffset;
1101     for (int32_t i = 0; i < iBlocksHeightCount; i++) {
1102       fLinePos -= m_pLoader->m_BlocksHeight.ElementAt(i * 2 + 1);
1103     }
1104     m_pLoader->m_iChar = 0;
1105     if (iCount > 1)
1106       m_pLoader->m_iTotalLines = m_Blocks.ElementAt(iBlock * 2 + 1);
1107     Loader(szText, fLinePos, TRUE);
1108     if (iCount == 0 && m_pLoader->m_fStartLineOffset < 0.1f)
1109       UpdateAlign(szText.y, fLinePos);
1110   } else if (m_pTextDataNode) {
1111     iBlock *= 2;
1112     if (iBlock < iCount - 2)
1113       m_pLoader->m_iTotalLines = m_Blocks.ElementAt(iBlock + 1);
1114     m_pBreak->Reset();
1115     if (m_bRichText) {
1116       CFDE_XMLNode* pContainerNode = GetXMLContainerNode();
1117       if (!pContainerNode) {
1118         return TRUE;
1119       }
1120       CFDE_XMLNode* pXMLNode = m_pLoader->m_pXMLNode;
1121       if (!pXMLNode)
1122         return TRUE;
1123       CFDE_XMLNode* pSaveXMLNode = m_pLoader->m_pXMLNode;
1124       for (; pXMLNode;
1125            pXMLNode = pXMLNode->GetNodeItem(CFDE_XMLNode::NextSibling)) {
1126         if (!LoadRichText(pXMLNode, szText, fLinePos, m_pLoader->m_pParentStyle,
1127                           TRUE)) {
1128           break;
1129         }
1130       }
1131       while (!pXMLNode) {
1132         pXMLNode = pSaveXMLNode->GetNodeItem(CFDE_XMLNode::Parent);
1133         if (pXMLNode == pContainerNode)
1134           break;
1135         if (!LoadRichText(pXMLNode, szText, fLinePos, m_pLoader->m_pParentStyle,
1136                           TRUE, nullptr, FALSE)) {
1137           break;
1138         }
1139         pSaveXMLNode = pXMLNode;
1140         pXMLNode = pXMLNode->GetNodeItem(CFDE_XMLNode::NextSibling);
1141         if (!pXMLNode)
1142           continue;
1143         for (; pXMLNode;
1144              pXMLNode = pXMLNode->GetNodeItem(CFDE_XMLNode::NextSibling)) {
1145           if (!LoadRichText(pXMLNode, szText, fLinePos,
1146                             m_pLoader->m_pParentStyle, TRUE)) {
1147             break;
1148           }
1149         }
1150       }
1151     } else {
1152       pNode = m_pLoader->m_pNode;
1153       if (!pNode)
1154         return TRUE;
1155       LoadText(pNode, szText, fLinePos, TRUE);
1156     }
1157   }
1158   if (iBlock == iCount) {
1159     m_pTabstopContext.reset();
1160     m_pLoader.reset();
1161   }
1162   return TRUE;
1163 }
ItemBlocks(const CFX_RectF & rtText,int32_t iBlockIndex)1164 void CXFA_TextLayout::ItemBlocks(const CFX_RectF& rtText, int32_t iBlockIndex) {
1165   if (!m_pLoader) {
1166     return;
1167   }
1168   int32_t iCountHeight = m_pLoader->m_lineHeights.GetSize();
1169   if (iCountHeight == 0) {
1170     return;
1171   }
1172   FX_BOOL bEndItem = TRUE;
1173   int32_t iBlockCount = m_Blocks.GetSize();
1174   FX_FLOAT fLinePos = m_pLoader->m_fStartLineOffset;
1175   int32_t iLineIndex = 0;
1176   if (iBlockIndex > 0) {
1177     int32_t iBlockHeightCount = m_pLoader->m_BlocksHeight.GetSize();
1178     iBlockHeightCount /= 2;
1179     if (iBlockHeightCount >= iBlockIndex) {
1180       for (int32_t i = 0; i < iBlockIndex; i++) {
1181         fLinePos -= m_pLoader->m_BlocksHeight.ElementAt(i * 2 + 1);
1182       }
1183     } else {
1184       fLinePos = 0;
1185     }
1186     iLineIndex = m_Blocks.ElementAt(iBlockCount - 1) +
1187                  m_Blocks.ElementAt(iBlockCount - 2);
1188   }
1189   int32_t i = 0;
1190   for (i = iLineIndex; i < iCountHeight; i++) {
1191     FX_FLOAT fLineHeight = m_pLoader->m_lineHeights.ElementAt(i);
1192     if (fLinePos + fLineHeight - rtText.height > 0.001) {
1193       m_Blocks.Add(iLineIndex);
1194       m_Blocks.Add(i - iLineIndex);
1195       bEndItem = FALSE;
1196       break;
1197     }
1198     fLinePos += fLineHeight;
1199   }
1200   if (iCountHeight > 0 && (i - iLineIndex) > 0 && bEndItem) {
1201     m_Blocks.Add(iLineIndex);
1202     m_Blocks.Add(i - iLineIndex);
1203   }
1204 }
DrawString(CFX_RenderDevice * pFxDevice,const CFX_Matrix & tmDoc2Device,const CFX_RectF & rtClip,int32_t iBlock)1205 FX_BOOL CXFA_TextLayout::DrawString(CFX_RenderDevice* pFxDevice,
1206                                     const CFX_Matrix& tmDoc2Device,
1207                                     const CFX_RectF& rtClip,
1208                                     int32_t iBlock) {
1209   if (!pFxDevice)
1210     return FALSE;
1211 
1212   std::unique_ptr<CFDE_RenderDevice> pDevice(
1213       new CFDE_RenderDevice(pFxDevice, FALSE));
1214   pDevice->SaveState();
1215   pDevice->SetClipRect(rtClip);
1216 
1217   std::unique_ptr<CFDE_Brush> pSolidBrush(new CFDE_Brush);
1218   std::unique_ptr<CFDE_Pen> pPen(new CFDE_Pen);
1219   if (m_pieceLines.GetSize() == 0) {
1220     int32_t iBlockCount = CountBlocks();
1221     for (int32_t i = 0; i < iBlockCount; i++) {
1222       Layout(i);
1223     }
1224   }
1225   FXTEXT_CHARPOS* pCharPos = nullptr;
1226   int32_t iCharCount = 0;
1227   int32_t iLineStart = 0;
1228   int32_t iPieceLines = m_pieceLines.GetSize();
1229   int32_t iCount = m_Blocks.GetSize();
1230   if (iCount > 0) {
1231     iBlock *= 2;
1232     if (iBlock < iCount) {
1233       iLineStart = m_Blocks.ElementAt(iBlock);
1234       iPieceLines = m_Blocks.ElementAt(iBlock + 1);
1235     } else {
1236       iPieceLines = 0;
1237     }
1238   }
1239   for (int32_t i = 0; i < iPieceLines; i++) {
1240     if (i + iLineStart >= m_pieceLines.GetSize()) {
1241       break;
1242     }
1243     CXFA_PieceLine* pPieceLine = m_pieceLines.GetAt(i + iLineStart);
1244     int32_t iPieces = pPieceLine->m_textPieces.GetSize();
1245     int32_t j = 0;
1246     for (j = 0; j < iPieces; j++) {
1247       const XFA_TextPiece* pPiece = pPieceLine->m_textPieces.GetAt(j);
1248       int32_t iChars = pPiece->iChars;
1249       if (iCharCount < iChars) {
1250         FX_Free(pCharPos);
1251         pCharPos = FX_Alloc(FXTEXT_CHARPOS, iChars);
1252         iCharCount = iChars;
1253       }
1254       FXSYS_memset(pCharPos, 0, iCharCount * sizeof(FXTEXT_CHARPOS));
1255       RenderString(pDevice.get(), pSolidBrush.get(), pPieceLine, j, pCharPos,
1256                    tmDoc2Device);
1257     }
1258     for (j = 0; j < iPieces; j++) {
1259       RenderPath(pDevice.get(), pPen.get(), pPieceLine, j, pCharPos,
1260                  tmDoc2Device);
1261     }
1262   }
1263   pDevice->RestoreState();
1264   FX_Free(pCharPos);
1265   return iPieceLines;
1266 }
UpdateAlign(FX_FLOAT fHeight,FX_FLOAT fBottom)1267 void CXFA_TextLayout::UpdateAlign(FX_FLOAT fHeight, FX_FLOAT fBottom) {
1268   fHeight -= fBottom;
1269   if (fHeight < 0.1f) {
1270     return;
1271   }
1272   switch (m_textParser.GetVAlign(m_pTextProvider)) {
1273     case XFA_ATTRIBUTEENUM_Middle:
1274       fHeight /= 2.0f;
1275       break;
1276     case XFA_ATTRIBUTEENUM_Bottom:
1277       break;
1278     default:
1279       return;
1280   }
1281   int32_t iCount = m_pieceLines.GetSize();
1282   for (int32_t i = 0; i < iCount; i++) {
1283     CXFA_PieceLine* pPieceLine = m_pieceLines.GetAt(i);
1284     int32_t iPieces = pPieceLine->m_textPieces.GetSize();
1285     for (int32_t j = 0; j < iPieces; j++) {
1286       XFA_TextPiece* pPiece = pPieceLine->m_textPieces.GetAt(j);
1287       CFX_RectF& rect = pPiece->rtPiece;
1288       rect.top += fHeight;
1289     }
1290   }
1291 }
Loader(const CFX_SizeF & szText,FX_FLOAT & fLinePos,FX_BOOL bSavePieces)1292 FX_BOOL CXFA_TextLayout::Loader(const CFX_SizeF& szText,
1293                                 FX_FLOAT& fLinePos,
1294                                 FX_BOOL bSavePieces) {
1295   if (!m_pAllocator) {
1296     m_pAllocator.reset(
1297         IFX_MemoryAllocator::Create(FX_ALLOCTYPE_Static, 256, 0));
1298   }
1299   GetTextDataNode();
1300   if (!m_pTextDataNode)
1301     return TRUE;
1302 
1303   if (m_bRichText) {
1304     CFDE_XMLNode* pXMLContainer = GetXMLContainerNode();
1305     if (pXMLContainer) {
1306       if (!m_textParser.IsParsed()) {
1307         m_textParser.DoParse(pXMLContainer, m_pTextProvider);
1308       }
1309       IFDE_CSSComputedStyle* pRootStyle =
1310           m_textParser.CreateRootStyle(m_pTextProvider);
1311       LoadRichText(pXMLContainer, szText, fLinePos, pRootStyle, bSavePieces);
1312       pRootStyle->Release();
1313     }
1314   } else {
1315     LoadText(m_pTextDataNode, szText, fLinePos, bSavePieces);
1316   }
1317   return TRUE;
1318 }
LoadText(CXFA_Node * pNode,const CFX_SizeF & szText,FX_FLOAT & fLinePos,FX_BOOL bSavePieces)1319 void CXFA_TextLayout::LoadText(CXFA_Node* pNode,
1320                                const CFX_SizeF& szText,
1321                                FX_FLOAT& fLinePos,
1322                                FX_BOOL bSavePieces) {
1323   InitBreak(szText.x);
1324   CXFA_Para para = m_pTextProvider->GetParaNode();
1325   FX_FLOAT fSpaceAbove = 0;
1326   if (para) {
1327     fSpaceAbove = para.GetSpaceAbove();
1328     if (fSpaceAbove < 0.1f) {
1329       fSpaceAbove = 0;
1330     }
1331     int32_t verAlign = para.GetVerticalAlign();
1332     switch (verAlign) {
1333       case XFA_ATTRIBUTEENUM_Top:
1334       case XFA_ATTRIBUTEENUM_Middle:
1335       case XFA_ATTRIBUTEENUM_Bottom: {
1336         fLinePos += fSpaceAbove;
1337         break;
1338       }
1339     }
1340   }
1341   CFX_WideString wsText = pNode->GetContent();
1342   wsText.TrimRight(L" ");
1343   FX_BOOL bRet = AppendChar(wsText, fLinePos, fSpaceAbove, bSavePieces);
1344   if (bRet && m_pLoader) {
1345     m_pLoader->m_pNode = pNode;
1346   } else {
1347     EndBreak(FX_RTFBREAK_ParagraphBreak, fLinePos, bSavePieces);
1348   }
1349 }
LoadRichText(CFDE_XMLNode * pXMLNode,const CFX_SizeF & szText,FX_FLOAT & fLinePos,IFDE_CSSComputedStyle * pParentStyle,FX_BOOL bSavePieces,CXFA_LinkUserData * pLinkData,FX_BOOL bEndBreak,FX_BOOL bIsOl,int32_t iLiCount)1350 FX_BOOL CXFA_TextLayout::LoadRichText(CFDE_XMLNode* pXMLNode,
1351                                       const CFX_SizeF& szText,
1352                                       FX_FLOAT& fLinePos,
1353                                       IFDE_CSSComputedStyle* pParentStyle,
1354                                       FX_BOOL bSavePieces,
1355                                       CXFA_LinkUserData* pLinkData,
1356                                       FX_BOOL bEndBreak,
1357                                       FX_BOOL bIsOl,
1358                                       int32_t iLiCount) {
1359   if (!pXMLNode) {
1360     return FALSE;
1361   }
1362   CXFA_TextParseContext* pContext =
1363       m_textParser.GetParseContextFromMap(pXMLNode);
1364   FDE_CSSDISPLAY eDisplay = FDE_CSSDISPLAY_None;
1365   FX_BOOL bContentNode = FALSE;
1366   FX_FLOAT fSpaceBelow = 0;
1367   IFDE_CSSComputedStyle* pStyle = nullptr;
1368   CFX_WideString wsName;
1369   if (bEndBreak) {
1370     FX_BOOL bCurOl = FALSE;
1371     FX_BOOL bCurLi = FALSE;
1372     CFDE_XMLElement* pElement = nullptr;
1373     if (pContext) {
1374       if (m_bBlockContinue ||
1375           (m_pLoader && pXMLNode == m_pLoader->m_pXMLNode)) {
1376         m_bBlockContinue = TRUE;
1377       }
1378       if (pXMLNode->GetType() == FDE_XMLNODE_Text) {
1379         bContentNode = TRUE;
1380       } else if (pXMLNode->GetType() == FDE_XMLNODE_Element) {
1381         pElement = static_cast<CFDE_XMLElement*>(pXMLNode);
1382         pElement->GetLocalTagName(wsName);
1383       }
1384       if (wsName == FX_WSTRC(L"ol")) {
1385         bIsOl = TRUE;
1386         bCurOl = TRUE;
1387       }
1388       if (m_bBlockContinue || bContentNode == FALSE) {
1389         eDisplay = pContext->GetDisplay();
1390         if (eDisplay != FDE_CSSDISPLAY_Block &&
1391             eDisplay != FDE_CSSDISPLAY_Inline &&
1392             eDisplay != FDE_CSSDISPLAY_ListItem) {
1393           return TRUE;
1394         }
1395         pStyle = m_textParser.ComputeStyle(pXMLNode, pParentStyle);
1396         InitBreak(bContentNode ? pParentStyle : pStyle, eDisplay, szText.x,
1397                   pXMLNode, pParentStyle);
1398         if ((eDisplay == FDE_CSSDISPLAY_Block ||
1399              eDisplay == FDE_CSSDISPLAY_ListItem) &&
1400             pStyle &&
1401             (wsName.IsEmpty() ||
1402              (wsName != FX_WSTRC(L"body") && wsName != FX_WSTRC(L"html") &&
1403               wsName != FX_WSTRC(L"ol") && wsName != FX_WSTRC(L"ul")))) {
1404           const FDE_CSSRECT* pRect =
1405               pStyle->GetBoundaryStyles()->GetMarginWidth();
1406           if (pRect) {
1407             fLinePos += pRect->top.GetValue();
1408             fSpaceBelow = pRect->bottom.GetValue();
1409           }
1410         }
1411         if (wsName == FX_WSTRC(L"a")) {
1412           CFX_WideString wsLinkContent;
1413           ASSERT(pElement);
1414           pElement->GetString(L"href", wsLinkContent);
1415           if (!wsLinkContent.IsEmpty()) {
1416             pLinkData = FXTARGET_NewWith(m_pAllocator.get()) CXFA_LinkUserData(
1417                 m_pAllocator.get(),
1418                 wsLinkContent.GetBuffer(wsLinkContent.GetLength()));
1419             wsLinkContent.ReleaseBuffer(wsLinkContent.GetLength());
1420           }
1421         }
1422         int32_t iTabCount =
1423             m_textParser.CountTabs(bContentNode ? pParentStyle : pStyle);
1424         FX_BOOL bSpaceRun =
1425             m_textParser.IsSpaceRun(bContentNode ? pParentStyle : pStyle);
1426         CFX_WideString wsText;
1427         if (bContentNode && iTabCount == 0) {
1428           static_cast<CFDE_XMLText*>(pXMLNode)->GetText(wsText);
1429         } else if (wsName == FX_WSTRC(L"br")) {
1430           wsText = L'\n';
1431         } else if (wsName == FX_WSTRC(L"li")) {
1432           bCurLi = TRUE;
1433           if (bIsOl) {
1434             wsText.Format(L"%d.  ", iLiCount);
1435           } else {
1436             wsText = 0x00B7 + FX_WSTRC(L"  ");
1437           }
1438         } else if (!bContentNode) {
1439           if (iTabCount > 0) {
1440             while (iTabCount-- > 0)
1441               wsText += L'\t';
1442           } else {
1443             m_textParser.GetEmbbedObj(m_pTextProvider, pXMLNode, wsText);
1444           }
1445         }
1446         int32_t iLength = wsText.GetLength();
1447         if (iLength > 0 && bContentNode && !bSpaceRun) {
1448           ProcessText(wsText);
1449         }
1450         if (m_pLoader) {
1451           if (wsText.GetLength() > 0 &&
1452               (m_pLoader->m_dwFlags & XFA_LOADERCNTXTFLG_FILTERSPACE)) {
1453             wsText.TrimLeft(0x20);
1454           }
1455           if (FDE_CSSDISPLAY_Block == eDisplay) {
1456             m_pLoader->m_dwFlags |= XFA_LOADERCNTXTFLG_FILTERSPACE;
1457           } else if (FDE_CSSDISPLAY_Inline == eDisplay &&
1458                      (m_pLoader->m_dwFlags & XFA_LOADERCNTXTFLG_FILTERSPACE)) {
1459             m_pLoader->m_dwFlags &= ~XFA_LOADERCNTXTFLG_FILTERSPACE;
1460           } else if (wsText.GetLength() > 0 &&
1461                      (0x20 == wsText.GetAt(wsText.GetLength() - 1))) {
1462             m_pLoader->m_dwFlags |= XFA_LOADERCNTXTFLG_FILTERSPACE;
1463           } else if (wsText.GetLength() != 0) {
1464             m_pLoader->m_dwFlags &= ~XFA_LOADERCNTXTFLG_FILTERSPACE;
1465           }
1466         }
1467         if (wsText.GetLength() > 0) {
1468           if (!m_pLoader || m_pLoader->m_iChar == 0) {
1469             if (pLinkData) {
1470               pLinkData->Retain();
1471             }
1472             CXFA_TextUserData* pUserData = FXTARGET_NewWith(m_pAllocator.get())
1473                 CXFA_TextUserData(m_pAllocator.get(),
1474                                   bContentNode ? pParentStyle : pStyle,
1475                                   pLinkData);
1476             m_pBreak->SetUserData(pUserData);
1477           }
1478           if (AppendChar(wsText, fLinePos, 0, bSavePieces)) {
1479             if (m_pLoader) {
1480               m_pLoader->m_dwFlags &= ~XFA_LOADERCNTXTFLG_FILTERSPACE;
1481             }
1482             if (IsEnd(bSavePieces)) {
1483               if (m_pLoader && m_pLoader->m_iTotalLines > -1) {
1484                 m_pLoader->m_pXMLNode = pXMLNode;
1485                 m_pLoader->m_pParentStyle = pParentStyle;
1486               }
1487               if (pStyle)
1488                 pStyle->Release();
1489               return FALSE;
1490             }
1491             return TRUE;
1492           }
1493         }
1494       }
1495     }
1496     FX_BOOL ret = TRUE;
1497     for (CFDE_XMLNode* pChildNode =
1498              pXMLNode->GetNodeItem(CFDE_XMLNode::FirstChild);
1499          pChildNode;
1500          pChildNode = pChildNode->GetNodeItem(CFDE_XMLNode::NextSibling)) {
1501       if (bCurOl) {
1502         iLiCount++;
1503       }
1504       ret = LoadRichText(pChildNode, szText, fLinePos,
1505                          pContext ? pStyle : pParentStyle, bSavePieces,
1506                          pLinkData, TRUE, bIsOl, iLiCount);
1507       if (ret == FALSE) {
1508         return FALSE;
1509       }
1510     }
1511     if (m_pLoader) {
1512       if (FDE_CSSDISPLAY_Block == eDisplay) {
1513         m_pLoader->m_dwFlags |= XFA_LOADERCNTXTFLG_FILTERSPACE;
1514       }
1515     }
1516     if (bCurLi) {
1517       EndBreak(FX_RTFBREAK_LineBreak, fLinePos, bSavePieces);
1518     }
1519   } else {
1520     if (pContext) {
1521       eDisplay = pContext->GetDisplay();
1522     }
1523   }
1524   if (m_bBlockContinue) {
1525     if (pContext && !bContentNode) {
1526       uint32_t dwStatus = (eDisplay == FDE_CSSDISPLAY_Block)
1527                               ? FX_RTFBREAK_ParagraphBreak
1528                               : FX_RTFBREAK_PieceBreak;
1529       EndBreak(dwStatus, fLinePos, bSavePieces);
1530       if (eDisplay == FDE_CSSDISPLAY_Block) {
1531         fLinePos += fSpaceBelow;
1532         if (m_pTabstopContext) {
1533           m_pTabstopContext->RemoveAll();
1534         }
1535       }
1536       if (wsName == FX_WSTRC(L"a")) {
1537         if (pLinkData) {
1538           pLinkData->Release();
1539           pLinkData = nullptr;
1540         }
1541       }
1542       if (IsEnd(bSavePieces)) {
1543         if (pStyle) {
1544           pStyle->Release();
1545         }
1546         if (m_pLoader && m_pLoader->m_iTotalLines > -1) {
1547           m_pLoader->m_pXMLNode =
1548               pXMLNode->GetNodeItem(CFDE_XMLNode::NextSibling);
1549           m_pLoader->m_pParentStyle = pParentStyle;
1550         }
1551         return FALSE;
1552       }
1553     }
1554   }
1555   if (pStyle)
1556     pStyle->Release();
1557   return TRUE;
1558 }
AppendChar(const CFX_WideString & wsText,FX_FLOAT & fLinePos,FX_FLOAT fSpaceAbove,FX_BOOL bSavePieces)1559 FX_BOOL CXFA_TextLayout::AppendChar(const CFX_WideString& wsText,
1560                                     FX_FLOAT& fLinePos,
1561                                     FX_FLOAT fSpaceAbove,
1562                                     FX_BOOL bSavePieces) {
1563   uint32_t dwStatus = 0;
1564   int32_t iChar = 0;
1565   if (m_pLoader) {
1566     iChar = m_pLoader->m_iChar;
1567   }
1568   int32_t iLength = wsText.GetLength();
1569   for (int32_t i = iChar; i < iLength; i++) {
1570     FX_WCHAR wch = wsText.GetAt(i);
1571     if (wch == 0xA0) {
1572       wch = 0x20;
1573     }
1574     if ((dwStatus = m_pBreak->AppendChar(wch)) > FX_RTFBREAK_PieceBreak) {
1575       AppendTextLine(dwStatus, fLinePos, bSavePieces);
1576       if (IsEnd(bSavePieces)) {
1577         if (m_pLoader)
1578           m_pLoader->m_iChar = i;
1579         return TRUE;
1580       }
1581       if (dwStatus == FX_RTFBREAK_ParagraphBreak && m_bRichText) {
1582         fLinePos += fSpaceAbove;
1583       }
1584     }
1585   }
1586   if (m_pLoader) {
1587     m_pLoader->m_iChar = 0;
1588   }
1589   return FALSE;
1590 }
IsEnd(FX_BOOL bSavePieces)1591 FX_BOOL CXFA_TextLayout::IsEnd(FX_BOOL bSavePieces) {
1592   if (!bSavePieces) {
1593     return FALSE;
1594   }
1595   if (m_pLoader && m_pLoader->m_iTotalLines > 0) {
1596     return m_iLines >= m_pLoader->m_iTotalLines;
1597   }
1598   return FALSE;
1599 }
ProcessText(CFX_WideString & wsText)1600 void CXFA_TextLayout::ProcessText(CFX_WideString& wsText) {
1601   int32_t iLen = wsText.GetLength();
1602   if (iLen == 0) {
1603     return;
1604   }
1605   FX_WCHAR* psz = wsText.GetBuffer(iLen);
1606   int32_t iTrimLeft = 0;
1607   FX_WCHAR wch = 0, wPrev = 0;
1608   for (int32_t i = 0; i < iLen; i++) {
1609     wch = psz[i];
1610     if (wch < 0x20) {
1611       wch = 0x20;
1612     }
1613     if (wch == 0x20 && wPrev == 0x20) {
1614       continue;
1615     }
1616     wPrev = wch;
1617     psz[iTrimLeft++] = wch;
1618   }
1619   wsText.ReleaseBuffer(iLen);
1620   wsText = wsText.Left(iTrimLeft);
1621 }
EndBreak(uint32_t dwStatus,FX_FLOAT & fLinePos,FX_BOOL bSavePieces)1622 void CXFA_TextLayout::EndBreak(uint32_t dwStatus,
1623                                FX_FLOAT& fLinePos,
1624                                FX_BOOL bSavePieces) {
1625   dwStatus = m_pBreak->EndBreak(dwStatus);
1626   if (dwStatus > FX_RTFBREAK_PieceBreak) {
1627     AppendTextLine(dwStatus, fLinePos, bSavePieces, TRUE);
1628   }
1629 }
DoTabstops(IFDE_CSSComputedStyle * pStyle,CXFA_PieceLine * pPieceLine)1630 void CXFA_TextLayout::DoTabstops(IFDE_CSSComputedStyle* pStyle,
1631                                  CXFA_PieceLine* pPieceLine) {
1632   if (!m_pTabstopContext || m_pTabstopContext->m_iTabCount == 0) {
1633     return;
1634   }
1635   if (!pStyle || !pPieceLine) {
1636     return;
1637   }
1638   int32_t iPieces = pPieceLine->m_textPieces.GetSize();
1639   if (iPieces == 0) {
1640     return;
1641   }
1642   XFA_TextPiece* pPiece = pPieceLine->m_textPieces.GetAt(iPieces - 1);
1643   int32_t& iTabstopsIndex = m_pTabstopContext->m_iTabIndex;
1644   int32_t iCount = m_textParser.CountTabs(pStyle);
1645   if (iTabstopsIndex > m_pTabstopContext->m_iTabCount - 1) {
1646     return;
1647   }
1648   if (iCount > 0) {
1649     iTabstopsIndex++;
1650     m_pTabstopContext->m_bTabstops = TRUE;
1651     FX_FLOAT fRight = 0;
1652     if (iPieces > 1) {
1653       XFA_TextPiece* p = pPieceLine->m_textPieces.GetAt(iPieces - 2);
1654       fRight = p->rtPiece.right();
1655     }
1656     m_pTabstopContext->m_fTabWidth =
1657         pPiece->rtPiece.width + pPiece->rtPiece.left - fRight;
1658   } else if (iTabstopsIndex > -1) {
1659     FX_FLOAT fLeft = 0;
1660     if (m_pTabstopContext->m_bTabstops) {
1661       XFA_TABSTOPS* pTabstops =
1662           m_pTabstopContext->m_tabstops.GetDataPtr(iTabstopsIndex);
1663       uint32_t dwAlign = pTabstops->dwAlign;
1664       if (dwAlign == FX_HashCode_GetW(L"center", false)) {
1665         fLeft = pPiece->rtPiece.width / 2.0f;
1666       } else if (dwAlign == FX_HashCode_GetW(L"right", false) ||
1667                  dwAlign == FX_HashCode_GetW(L"before", false)) {
1668         fLeft = pPiece->rtPiece.width;
1669       } else if (dwAlign == FX_HashCode_GetW(L"decimal", false)) {
1670         int32_t iChars = pPiece->iChars;
1671         for (int32_t i = 0; i < iChars; i++) {
1672           if (pPiece->pszText[i] == L'.') {
1673             break;
1674           }
1675           fLeft += pPiece->pWidths[i] / 20000.0f;
1676         }
1677       }
1678       m_pTabstopContext->m_fLeft =
1679           std::min(fLeft, m_pTabstopContext->m_fTabWidth);
1680       m_pTabstopContext->m_bTabstops = FALSE;
1681       m_pTabstopContext->m_fTabWidth = 0;
1682     }
1683     pPiece->rtPiece.left -= m_pTabstopContext->m_fLeft;
1684   }
1685 }
AppendTextLine(uint32_t dwStatus,FX_FLOAT & fLinePos,FX_BOOL bSavePieces,FX_BOOL bEndBreak)1686 void CXFA_TextLayout::AppendTextLine(uint32_t dwStatus,
1687                                      FX_FLOAT& fLinePos,
1688                                      FX_BOOL bSavePieces,
1689                                      FX_BOOL bEndBreak) {
1690   int32_t iPieces = m_pBreak->CountBreakPieces();
1691   if (iPieces < 1) {
1692     return;
1693   }
1694   IFDE_CSSComputedStyle* pStyle = nullptr;
1695   if (bSavePieces) {
1696     CXFA_PieceLine* pPieceLine =
1697         FXTARGET_NewWith(m_pAllocator.get()) CXFA_PieceLine;
1698     m_pieceLines.Add(pPieceLine);
1699     if (m_pTabstopContext) {
1700       m_pTabstopContext->Reset();
1701     }
1702     FX_FLOAT fLineStep = 0, fBaseLine = 0;
1703     int32_t i = 0;
1704     for (i = 0; i < iPieces; i++) {
1705       const CFX_RTFPiece* pPiece = m_pBreak->GetBreakPiece(i);
1706       CXFA_TextUserData* pUserData = (CXFA_TextUserData*)pPiece->m_pUserData;
1707       if (pUserData)
1708         pStyle = pUserData->m_pStyle;
1709       FX_FLOAT fVerScale = pPiece->m_iVerticalScale / 100.0f;
1710       XFA_TextPiece* pTP = FXTARGET_NewWith(m_pAllocator.get()) XFA_TextPiece();
1711       pTP->pszText =
1712           (FX_WCHAR*)m_pAllocator->Alloc(pPiece->m_iChars * sizeof(FX_WCHAR));
1713       pTP->pWidths =
1714           (int32_t*)m_pAllocator->Alloc(pPiece->m_iChars * sizeof(int32_t));
1715       pTP->iChars = pPiece->m_iChars;
1716       pPiece->GetString(pTP->pszText);
1717       pPiece->GetWidths(pTP->pWidths);
1718       pTP->iBidiLevel = pPiece->m_iBidiLevel;
1719       pTP->iHorScale = pPiece->m_iHorizontalScale;
1720       pTP->iVerScale = pPiece->m_iVerticalScale;
1721       m_textParser.GetUnderline(m_pTextProvider, pStyle, pTP->iUnderline,
1722                                 pTP->iPeriod);
1723       m_textParser.GetLinethrough(m_pTextProvider, pStyle, pTP->iLineThrough);
1724       pTP->dwColor = m_textParser.GetColor(m_pTextProvider, pStyle);
1725       pTP->pFont = m_textParser.GetFont(m_pTextProvider, pStyle);
1726       pTP->fFontSize = m_textParser.GetFontSize(m_pTextProvider, pStyle);
1727       pTP->rtPiece.left = pPiece->m_iStartPos / 20000.0f;
1728       pTP->rtPiece.width = pPiece->m_iWidth / 20000.0f;
1729       pTP->rtPiece.height = (FX_FLOAT)pPiece->m_iFontSize * fVerScale / 20.0f;
1730       FX_FLOAT fBaseLineTemp =
1731           m_textParser.GetBaseline(m_pTextProvider, pStyle);
1732       pTP->rtPiece.top = fBaseLineTemp;
1733       pPieceLine->m_textPieces.Add(pTP);
1734       FX_FLOAT fLineHeight = m_textParser.GetLineHeight(
1735           m_pTextProvider, pStyle, m_iLines == 0, fVerScale);
1736       if (fBaseLineTemp > 0) {
1737         FX_FLOAT fLineHeightTmp = fBaseLineTemp + pTP->rtPiece.height;
1738         if (fLineHeight < fLineHeightTmp) {
1739           fLineHeight = fLineHeightTmp;
1740         } else {
1741           fBaseLineTemp = 0;
1742         }
1743       } else if (fBaseLine < -fBaseLineTemp) {
1744         fBaseLine = -fBaseLineTemp;
1745       }
1746       fLineStep = std::max(fLineStep, fLineHeight);
1747       if (pUserData && pUserData->m_pLinkData) {
1748         pUserData->m_pLinkData->Retain();
1749         pTP->pLinkData = pUserData->m_pLinkData;
1750       } else {
1751         pTP->pLinkData = nullptr;
1752       }
1753       DoTabstops(pStyle, pPieceLine);
1754     }
1755     for (i = 0; i < iPieces; i++) {
1756       XFA_TextPiece* pTP = pPieceLine->m_textPieces.GetAt(i);
1757       FX_FLOAT& fTop = pTP->rtPiece.top;
1758       FX_FLOAT fBaseLineTemp = fTop;
1759       fTop = fLinePos + fLineStep - pTP->rtPiece.height - fBaseLineTemp;
1760       fTop = std::max(0.0f, fTop);
1761     }
1762     fLinePos += fLineStep + fBaseLine;
1763   } else {
1764     FX_FLOAT fLineStep = 0;
1765     FX_FLOAT fLineWidth = 0;
1766     for (int32_t i = 0; i < iPieces; i++) {
1767       const CFX_RTFPiece* pPiece = m_pBreak->GetBreakPiece(i);
1768       CXFA_TextUserData* pUserData = (CXFA_TextUserData*)pPiece->m_pUserData;
1769       if (pUserData)
1770         pStyle = pUserData->m_pStyle;
1771       FX_FLOAT fVerScale = pPiece->m_iVerticalScale / 100.0f;
1772       FX_FLOAT fBaseLine = m_textParser.GetBaseline(m_pTextProvider, pStyle);
1773       FX_FLOAT fLineHeight = m_textParser.GetLineHeight(
1774           m_pTextProvider, pStyle, m_iLines == 0, fVerScale);
1775       if (fBaseLine > 0) {
1776         FX_FLOAT fLineHeightTmp =
1777             fBaseLine + (FX_FLOAT)pPiece->m_iFontSize * fVerScale / 20.0f;
1778         if (fLineHeight < fLineHeightTmp) {
1779           fLineHeight = fLineHeightTmp;
1780         }
1781       }
1782       fLineStep = std::max(fLineStep, fLineHeight);
1783       fLineWidth += pPiece->m_iWidth / 20000.0f;
1784     }
1785     fLinePos += fLineStep;
1786     m_fMaxWidth = std::max(m_fMaxWidth, fLineWidth);
1787     if (m_pLoader && m_pLoader->m_bSaveLineHeight) {
1788       FX_FLOAT fHeight = fLinePos - m_pLoader->m_fLastPos;
1789       m_pLoader->m_fLastPos = fLinePos;
1790       m_pLoader->m_lineHeights.Add(fHeight);
1791     }
1792   }
1793   if (pStyle) {
1794     pStyle->Retain();
1795   }
1796   m_pBreak->ClearBreakPieces();
1797   if (dwStatus == FX_RTFBREAK_ParagraphBreak) {
1798     m_pBreak->Reset();
1799     if (!pStyle && bEndBreak) {
1800       CXFA_Para para = m_pTextProvider->GetParaNode();
1801       if (para) {
1802         FX_FLOAT fStartPos = para.GetMarginLeft();
1803         FX_FLOAT fIndent = para.GetTextIndent();
1804         if (fIndent > 0) {
1805           fStartPos += fIndent;
1806         }
1807         FX_FLOAT fSpaceBelow = para.GetSpaceBelow();
1808         if (fSpaceBelow < 0.1f) {
1809           fSpaceBelow = 0;
1810         }
1811         m_pBreak->SetLineStartPos(fStartPos);
1812         fLinePos += fSpaceBelow;
1813       }
1814     }
1815   }
1816   if (pStyle) {
1817     FX_FLOAT fStart = 0;
1818     const FDE_CSSRECT* pRect = pStyle->GetBoundaryStyles()->GetMarginWidth();
1819     if (pRect) {
1820       fStart = pRect->left.GetValue();
1821     }
1822     FX_FLOAT fTextIndent =
1823         pStyle->GetParagraphStyles()->GetTextIndent().GetValue();
1824     if (fTextIndent < 0) {
1825       fStart -= fTextIndent;
1826     }
1827     m_pBreak->SetLineStartPos(fStart);
1828     pStyle->Release();
1829   }
1830   m_iLines++;
1831 }
RenderString(CFDE_RenderDevice * pDevice,CFDE_Brush * pBrush,CXFA_PieceLine * pPieceLine,int32_t iPiece,FXTEXT_CHARPOS * pCharPos,const CFX_Matrix & tmDoc2Device)1832 void CXFA_TextLayout::RenderString(CFDE_RenderDevice* pDevice,
1833                                    CFDE_Brush* pBrush,
1834                                    CXFA_PieceLine* pPieceLine,
1835                                    int32_t iPiece,
1836                                    FXTEXT_CHARPOS* pCharPos,
1837                                    const CFX_Matrix& tmDoc2Device) {
1838   const XFA_TextPiece* pPiece = pPieceLine->m_textPieces.GetAt(iPiece);
1839   int32_t iCount = GetDisplayPos(pPiece, pCharPos);
1840   if (iCount > 0) {
1841     pBrush->SetColor(pPiece->dwColor);
1842     pDevice->DrawString(pBrush, pPiece->pFont, pCharPos, iCount,
1843                         pPiece->fFontSize, &tmDoc2Device);
1844   }
1845   pPieceLine->m_charCounts.Add(iCount);
1846 }
1847 
RenderPath(CFDE_RenderDevice * pDevice,CFDE_Pen * pPen,CXFA_PieceLine * pPieceLine,int32_t iPiece,FXTEXT_CHARPOS * pCharPos,const CFX_Matrix & tmDoc2Device)1848 void CXFA_TextLayout::RenderPath(CFDE_RenderDevice* pDevice,
1849                                  CFDE_Pen* pPen,
1850                                  CXFA_PieceLine* pPieceLine,
1851                                  int32_t iPiece,
1852                                  FXTEXT_CHARPOS* pCharPos,
1853                                  const CFX_Matrix& tmDoc2Device) {
1854   XFA_TextPiece* pPiece = pPieceLine->m_textPieces.GetAt(iPiece);
1855   FX_BOOL bNoUnderline = pPiece->iUnderline < 1 || pPiece->iUnderline > 2;
1856   FX_BOOL bNoLineThrough = pPiece->iLineThrough < 1 || pPiece->iLineThrough > 2;
1857   if (bNoUnderline && bNoLineThrough) {
1858     return;
1859   }
1860   pPen->SetColor(pPiece->dwColor);
1861   std::unique_ptr<CFDE_Path> pPath(new CFDE_Path);
1862   int32_t iChars = GetDisplayPos(pPiece, pCharPos);
1863   if (iChars > 0) {
1864     CFX_PointF pt1, pt2;
1865     FX_FLOAT fEndY = pCharPos[0].m_OriginY + 1.05f;
1866     if (pPiece->iPeriod == XFA_ATTRIBUTEENUM_Word) {
1867       for (int32_t i = 0; i < pPiece->iUnderline; i++) {
1868         for (int32_t j = 0; j < iChars; j++) {
1869           pt1.x = pCharPos[j].m_OriginX;
1870           pt2.x =
1871               pt1.x + pCharPos[j].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
1872           pt1.y = pt2.y = fEndY;
1873           pPath->AddLine(pt1, pt2);
1874         }
1875         fEndY += 2.0f;
1876       }
1877     } else {
1878       pt1.x = pCharPos[0].m_OriginX;
1879       pt2.x =
1880           pCharPos[iChars - 1].m_OriginX +
1881           pCharPos[iChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
1882       for (int32_t i = 0; i < pPiece->iUnderline; i++) {
1883         pt1.y = pt2.y = fEndY;
1884         pPath->AddLine(pt1, pt2);
1885         fEndY += 2.0f;
1886       }
1887     }
1888     fEndY = pCharPos[0].m_OriginY - pPiece->rtPiece.height * 0.25f;
1889     pt1.x = pCharPos[0].m_OriginX;
1890     pt2.x = pCharPos[iChars - 1].m_OriginX +
1891             pCharPos[iChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
1892     for (int32_t i = 0; i < pPiece->iLineThrough; i++) {
1893       pt1.y = pt2.y = fEndY;
1894       pPath->AddLine(pt1, pt2);
1895       fEndY += 2.0f;
1896     }
1897   } else {
1898     if (bNoLineThrough &&
1899         (bNoUnderline || pPiece->iPeriod != XFA_ATTRIBUTEENUM_All)) {
1900       return;
1901     }
1902     int32_t iCharsTmp = 0;
1903     int32_t iPiecePrev = iPiece, iPieceNext = iPiece;
1904     while (iPiecePrev > 0) {
1905       iPiecePrev--;
1906       iCharsTmp = pPieceLine->m_charCounts.GetAt(iPiecePrev);
1907       if (iCharsTmp > 0) {
1908         break;
1909       }
1910     }
1911     if (iCharsTmp == 0) {
1912       return;
1913     }
1914     iCharsTmp = 0;
1915     int32_t iPieces = pPieceLine->m_textPieces.GetSize();
1916     while (iPieceNext < iPieces - 1) {
1917       iPieceNext++;
1918       iCharsTmp = pPieceLine->m_charCounts.GetAt(iPieceNext);
1919       if (iCharsTmp > 0) {
1920         break;
1921       }
1922     }
1923     if (iCharsTmp == 0) {
1924       return;
1925     }
1926     FX_FLOAT fOrgX = 0.0f, fEndX = 0.0f;
1927     pPiece = pPieceLine->m_textPieces.GetAt(iPiecePrev);
1928     iChars = GetDisplayPos(pPiece, pCharPos);
1929     if (iChars < 1) {
1930       return;
1931     }
1932     fOrgX = pCharPos[iChars - 1].m_OriginX +
1933             pCharPos[iChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
1934     pPiece = pPieceLine->m_textPieces.GetAt(iPieceNext);
1935     iChars = GetDisplayPos(pPiece, pCharPos);
1936     if (iChars < 1) {
1937       return;
1938     }
1939     fEndX = pCharPos[0].m_OriginX;
1940     CFX_PointF pt1, pt2;
1941     pt1.x = fOrgX, pt2.x = fEndX;
1942     FX_FLOAT fEndY = pCharPos[0].m_OriginY + 1.05f;
1943     for (int32_t i = 0; i < pPiece->iUnderline; i++) {
1944       pt1.y = pt2.y = fEndY;
1945       pPath->AddLine(pt1, pt2);
1946       fEndY += 2.0f;
1947     }
1948     fEndY = pCharPos[0].m_OriginY - pPiece->rtPiece.height * 0.25f;
1949     for (int32_t i = 0; i < pPiece->iLineThrough; i++) {
1950       pt1.y = pt2.y = fEndY;
1951       pPath->AddLine(pt1, pt2);
1952       fEndY += 2.0f;
1953     }
1954   }
1955   pDevice->DrawPath(pPen, 1, pPath.get(), &tmDoc2Device);
1956 }
1957 
GetDisplayPos(const XFA_TextPiece * pPiece,FXTEXT_CHARPOS * pCharPos,FX_BOOL bCharCode)1958 int32_t CXFA_TextLayout::GetDisplayPos(const XFA_TextPiece* pPiece,
1959                                        FXTEXT_CHARPOS* pCharPos,
1960                                        FX_BOOL bCharCode) {
1961   if (!pPiece) {
1962     return 0;
1963   }
1964   FX_RTFTEXTOBJ tr;
1965   if (!ToRun(pPiece, tr)) {
1966     return 0;
1967   }
1968   return m_pBreak->GetDisplayPos(&tr, pCharPos, bCharCode);
1969 }
ToRun(const XFA_TextPiece * pPiece,FX_RTFTEXTOBJ & tr)1970 FX_BOOL CXFA_TextLayout::ToRun(const XFA_TextPiece* pPiece, FX_RTFTEXTOBJ& tr) {
1971   int32_t iLength = pPiece->iChars;
1972   if (iLength < 1) {
1973     return FALSE;
1974   }
1975   tr.pStr = pPiece->pszText;
1976   tr.pFont = pPiece->pFont;
1977   tr.pRect = &pPiece->rtPiece;
1978   tr.pWidths = pPiece->pWidths;
1979   tr.iLength = iLength;
1980   tr.fFontSize = pPiece->fFontSize;
1981   tr.iBidiLevel = pPiece->iBidiLevel;
1982   tr.iCharRotation = 0;
1983   tr.wLineBreakChar = L'\n';
1984   tr.iVerticalScale = pPiece->iVerScale;
1985   tr.dwLayoutStyles = FX_RTFLAYOUTSTYLE_ExpandTab;
1986   tr.iHorizontalScale = pPiece->iHorScale;
1987   return TRUE;
1988 }
1989 
CXFA_LinkUserData(IFX_MemoryAllocator * pAllocator,FX_WCHAR * pszText)1990 CXFA_LinkUserData::CXFA_LinkUserData(IFX_MemoryAllocator* pAllocator,
1991                                      FX_WCHAR* pszText)
1992     : m_pAllocator(pAllocator), m_dwRefCount(1), m_wsURLContent(pszText) {}
1993 
~CXFA_LinkUserData()1994 CXFA_LinkUserData::~CXFA_LinkUserData() {}
1995 
Retain()1996 uint32_t CXFA_LinkUserData::Retain() {
1997   return ++m_dwRefCount;
1998 }
1999 
Release()2000 uint32_t CXFA_LinkUserData::Release() {
2001   uint32_t dwRefCount = --m_dwRefCount;
2002   if (dwRefCount <= 0)
2003     FXTARGET_DeleteWith(CXFA_LinkUserData, m_pAllocator, this);
2004   return dwRefCount;
2005 }
2006 
GetLinkURL()2007 const FX_WCHAR* CXFA_LinkUserData::GetLinkURL() {
2008   return m_wsURLContent.c_str();
2009 }
2010 
CXFA_TextUserData(IFX_MemoryAllocator * pAllocator,IFDE_CSSComputedStyle * pStyle)2011 CXFA_TextUserData::CXFA_TextUserData(IFX_MemoryAllocator* pAllocator,
2012                                      IFDE_CSSComputedStyle* pStyle)
2013     : m_pStyle(pStyle),
2014       m_pLinkData(nullptr),
2015       m_pAllocator(pAllocator),
2016       m_dwRefCount(0) {
2017   ASSERT(m_pAllocator);
2018   if (m_pStyle)
2019     m_pStyle->Retain();
2020 }
2021 
CXFA_TextUserData(IFX_MemoryAllocator * pAllocator,IFDE_CSSComputedStyle * pStyle,CXFA_LinkUserData * pLinkData)2022 CXFA_TextUserData::CXFA_TextUserData(IFX_MemoryAllocator* pAllocator,
2023                                      IFDE_CSSComputedStyle* pStyle,
2024                                      CXFA_LinkUserData* pLinkData)
2025     : m_pStyle(pStyle),
2026       m_pLinkData(pLinkData),
2027       m_pAllocator(pAllocator),
2028       m_dwRefCount(0) {
2029   ASSERT(m_pAllocator);
2030   if (m_pStyle)
2031     m_pStyle->Retain();
2032 }
2033 
~CXFA_TextUserData()2034 CXFA_TextUserData::~CXFA_TextUserData() {
2035   if (m_pStyle)
2036     m_pStyle->Release();
2037   if (m_pLinkData)
2038     m_pLinkData->Release();
2039 }
2040 
Retain()2041 uint32_t CXFA_TextUserData::Retain() {
2042   return ++m_dwRefCount;
2043 }
2044 
Release()2045 uint32_t CXFA_TextUserData::Release() {
2046   uint32_t dwRefCount = --m_dwRefCount;
2047   if (dwRefCount == 0)
2048     FXTARGET_DeleteWith(CXFA_TextUserData, m_pAllocator, this);
2049   return dwRefCount;
2050 }
2051 
CXFA_PieceLine()2052 CXFA_PieceLine::CXFA_PieceLine() {}
2053 
~CXFA_PieceLine()2054 CXFA_PieceLine::~CXFA_PieceLine() {}
2055 
CXFA_TextTabstopsContext()2056 CXFA_TextTabstopsContext::CXFA_TextTabstopsContext()
2057     : m_iTabCount(0),
2058       m_iTabIndex(-1),
2059       m_bTabstops(FALSE),
2060       m_fTabWidth(0),
2061       m_fLeft(0) {}
2062 
~CXFA_TextTabstopsContext()2063 CXFA_TextTabstopsContext::~CXFA_TextTabstopsContext() {}
2064 
Append(uint32_t dwAlign,FX_FLOAT fTabstops)2065 void CXFA_TextTabstopsContext::Append(uint32_t dwAlign, FX_FLOAT fTabstops) {
2066   int32_t i = 0;
2067   for (i = 0; i < m_iTabCount; i++) {
2068     XFA_TABSTOPS* pTabstop = m_tabstops.GetDataPtr(i);
2069     if (fTabstops < pTabstop->fTabstops) {
2070       break;
2071     }
2072   }
2073   m_tabstops.InsertSpaceAt(i, 1);
2074   XFA_TABSTOPS tabstop;
2075   tabstop.dwAlign = dwAlign;
2076   tabstop.fTabstops = fTabstops;
2077   m_tabstops.SetAt(i, tabstop);
2078   m_iTabCount++;
2079 }
2080 
RemoveAll()2081 void CXFA_TextTabstopsContext::RemoveAll() {
2082   m_tabstops.RemoveAll();
2083   m_iTabCount = 0;
2084 }
2085 
Reset()2086 void CXFA_TextTabstopsContext::Reset() {
2087   m_iTabIndex = -1;
2088   m_bTabstops = FALSE;
2089   m_fTabWidth = 0;
2090   m_fLeft = 0;
2091 }
2092