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