blob: 686ad4ee0d41c6726e1f61b7e69f6f5455433054 [file] [log] [blame]
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001// Copyright 2017 PDFium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7#include "xfa/fxfa/app/cxfa_textlayout.h"
8
9#include <algorithm>
tsepez783a7e02017-01-17 11:05:57 -080010#include <utility>
Dan Sinclair1f5d4982017-01-10 16:37:32 -050011
Dan Sinclair0d86ecb2017-04-19 09:19:57 -040012#include "core/fxcrt/xml/cfx_xmlelement.h"
13#include "core/fxcrt/xml/cfx_xmlnode.h"
14#include "core/fxcrt/xml/cfx_xmltext.h"
Dan Sinclair1f5d4982017-01-10 16:37:32 -050015#include "third_party/base/ptr_util.h"
16#include "third_party/base/stl_util.h"
Dan Sinclaird9828fd2017-03-30 10:58:49 -040017#include "xfa/fde/cfde_brush.h"
Dan Sinclair1f5d4982017-01-10 16:37:32 -050018#include "xfa/fde/cfde_path.h"
Dan Sinclaird9828fd2017-03-30 10:58:49 -040019#include "xfa/fde/cfde_pen.h"
20#include "xfa/fde/cfde_renderdevice.h"
Dan Sinclair95bec802017-01-19 10:27:58 -050021#include "xfa/fde/css/cfde_csscomputedstyle.h"
22#include "xfa/fde/css/cfde_cssstyleselector.h"
Dan Sinclair1f5d4982017-01-10 16:37:32 -050023#include "xfa/fxfa/app/cxfa_linkuserdata.h"
24#include "xfa/fxfa/app/cxfa_loadercontext.h"
25#include "xfa/fxfa/app/cxfa_pieceline.h"
26#include "xfa/fxfa/app/cxfa_textparsecontext.h"
27#include "xfa/fxfa/app/cxfa_texttabstopscontext.h"
28#include "xfa/fxfa/app/cxfa_textuserdata.h"
29#include "xfa/fxfa/app/xfa_ffwidgetacc.h"
30#include "xfa/fxfa/app/xfa_textpiece.h"
31#include "xfa/fxfa/parser/cxfa_font.h"
Dan Sinclairefcae5d2017-03-29 14:47:46 -040032#include "xfa/fxfa/parser/cxfa_node.h"
Dan Sinclair1f5d4982017-01-10 16:37:32 -050033#include "xfa/fxfa/parser/cxfa_para.h"
Dan Sinclair1f5d4982017-01-10 16:37:32 -050034
35#define XFA_LOADERCNTXTFLG_FILTERSPACE 0x001
36
37CXFA_TextLayout::CXFA_TextLayout(CXFA_TextProvider* pTextProvider)
38 : m_bHasBlock(false),
39 m_pTextProvider(pTextProvider),
40 m_pTextDataNode(nullptr),
41 m_bRichText(false),
42 m_iLines(0),
43 m_fMaxWidth(0),
44 m_bBlockContinue(true) {
45 ASSERT(m_pTextProvider);
46}
47
48CXFA_TextLayout::~CXFA_TextLayout() {
49 m_textParser.Reset();
50 Unload();
51}
52
53void CXFA_TextLayout::Unload() {
tsepez783a7e02017-01-17 11:05:57 -080054 m_pieceLines.clear();
Dan Sinclair1f5d4982017-01-10 16:37:32 -050055 m_pBreak.reset();
Dan Sinclair1f5d4982017-01-10 16:37:32 -050056}
57
Dan Sinclair1f5d4982017-01-10 16:37:32 -050058void CXFA_TextLayout::GetTextDataNode() {
59 if (!m_pTextProvider)
60 return;
61
62 CXFA_Node* pNode = m_pTextProvider->GetTextNode(m_bRichText);
63 if (pNode && m_bRichText)
64 m_textParser.Reset();
65
66 m_pTextDataNode = pNode;
67}
68
Dan Sinclair0d86ecb2017-04-19 09:19:57 -040069CFX_XMLNode* CXFA_TextLayout::GetXMLContainerNode() {
Dan Sinclair1f5d4982017-01-10 16:37:32 -050070 if (!m_bRichText)
71 return nullptr;
72
Dan Sinclair0d86ecb2017-04-19 09:19:57 -040073 CFX_XMLNode* pXMLRoot = m_pTextDataNode->GetXMLMappingNode();
Dan Sinclair1f5d4982017-01-10 16:37:32 -050074 if (!pXMLRoot)
75 return nullptr;
76
Dan Sinclair0d86ecb2017-04-19 09:19:57 -040077 CFX_XMLNode* pXMLContainer = nullptr;
78 for (CFX_XMLNode* pXMLChild = pXMLRoot->GetNodeItem(CFX_XMLNode::FirstChild);
Dan Sinclair1f5d4982017-01-10 16:37:32 -050079 pXMLChild;
Dan Sinclair0d86ecb2017-04-19 09:19:57 -040080 pXMLChild = pXMLChild->GetNodeItem(CFX_XMLNode::NextSibling)) {
81 if (pXMLChild->GetType() == FX_XMLNODE_Element) {
82 CFX_XMLElement* pXMLElement = static_cast<CFX_XMLElement*>(pXMLChild);
Dan Sinclair5fa4e982017-04-05 11:48:21 -040083 CFX_WideString wsTag = pXMLElement->GetLocalTagName();
dan sinclair65c7c232017-02-02 14:05:30 -080084 if (wsTag == L"body" || wsTag == L"html") {
Dan Sinclair1f5d4982017-01-10 16:37:32 -050085 pXMLContainer = pXMLChild;
86 break;
87 }
88 }
89 }
90 return pXMLContainer;
91}
92
Dan Sinclairb0d31602017-03-01 15:58:32 -050093std::unique_ptr<CFX_RTFBreak> CXFA_TextLayout::CreateBreak(bool bDefault) {
Dan Sinclaire533b932017-03-16 11:47:20 -040094 uint32_t dwStyle = FX_LAYOUTSTYLE_ExpandTab;
Dan Sinclair1f5d4982017-01-10 16:37:32 -050095 if (!bDefault)
Dan Sinclaire533b932017-03-16 11:47:20 -040096 dwStyle |= FX_LAYOUTSTYLE_Pagination;
Dan Sinclair1f5d4982017-01-10 16:37:32 -050097
Dan Sinclairb0d31602017-03-01 15:58:32 -050098 auto pBreak = pdfium::MakeUnique<CFX_RTFBreak>(dwStyle);
Dan Sinclair1f5d4982017-01-10 16:37:32 -050099 pBreak->SetLineBreakTolerance(1);
100 pBreak->SetFont(m_textParser.GetFont(m_pTextProvider, nullptr));
101 pBreak->SetFontSize(m_textParser.GetFontSize(m_pTextProvider, nullptr));
102 return pBreak;
103}
104
Dan Sinclair05df0752017-03-14 14:43:42 -0400105void CXFA_TextLayout::InitBreak(float fLineWidth) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500106 CXFA_Font font = m_pTextProvider->GetFontNode();
107 CXFA_Para para = m_pTextProvider->GetParaNode();
Dan Sinclair05df0752017-03-14 14:43:42 -0400108 float fStart = 0;
109 float fStartPos = 0;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500110 if (para) {
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500111 CFX_RTFLineAlignment iAlign = CFX_RTFLineAlignment::Left;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500112 switch (para.GetHorizontalAlign()) {
113 case XFA_ATTRIBUTEENUM_Center:
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500114 iAlign = CFX_RTFLineAlignment::Center;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500115 break;
116 case XFA_ATTRIBUTEENUM_Right:
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500117 iAlign = CFX_RTFLineAlignment::Right;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500118 break;
119 case XFA_ATTRIBUTEENUM_Justify:
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500120 iAlign = CFX_RTFLineAlignment::Justified;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500121 break;
122 case XFA_ATTRIBUTEENUM_JustifyAll:
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500123 iAlign = CFX_RTFLineAlignment::Distributed;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500124 break;
125 }
126 m_pBreak->SetAlignment(iAlign);
127
128 fStart = para.GetMarginLeft();
129 if (m_pTextProvider->IsCheckButtonAndAutoWidth()) {
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500130 if (iAlign != CFX_RTFLineAlignment::Left)
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500131 fLineWidth -= para.GetMarginRight();
132 } else {
133 fLineWidth -= para.GetMarginRight();
134 }
135 if (fLineWidth < 0)
136 fLineWidth = fStart;
137
138 fStartPos = fStart;
Dan Sinclair05df0752017-03-14 14:43:42 -0400139 float fIndent = para.GetTextIndent();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500140 if (fIndent > 0)
141 fStartPos += fIndent;
142 }
143
144 m_pBreak->SetLineBoundary(fStart, fLineWidth);
145 m_pBreak->SetLineStartPos(fStartPos);
146 if (font) {
147 m_pBreak->SetHorizontalScale((int32_t)font.GetHorizontalScale());
148 m_pBreak->SetVerticalScale((int32_t)font.GetVerticalScale());
149 m_pBreak->SetCharSpace(font.GetLetterSpacing());
150 }
151
Dan Sinclair05df0752017-03-14 14:43:42 -0400152 float fFontSize = m_textParser.GetFontSize(m_pTextProvider, nullptr);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500153 m_pBreak->SetFontSize(fFontSize);
154 m_pBreak->SetFont(m_textParser.GetFont(m_pTextProvider, nullptr));
155 m_pBreak->SetLineBreakTolerance(fFontSize * 0.2f);
156}
157
Dan Sinclaircfb856c2017-01-16 16:03:44 -0500158void CXFA_TextLayout::InitBreak(CFDE_CSSComputedStyle* pStyle,
Dan Sinclair96f482c2017-01-11 16:31:27 -0500159 FDE_CSSDisplay eDisplay,
Dan Sinclair05df0752017-03-14 14:43:42 -0400160 float fLineWidth,
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400161 CFX_XMLNode* pXMLNode,
Dan Sinclaircfb856c2017-01-16 16:03:44 -0500162 CFDE_CSSComputedStyle* pParentStyle) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500163 if (!pStyle) {
164 InitBreak(fLineWidth);
165 return;
166 }
167
Dan Sinclair96f482c2017-01-11 16:31:27 -0500168 if (eDisplay == FDE_CSSDisplay::Block ||
169 eDisplay == FDE_CSSDisplay::ListItem) {
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500170 CFX_RTFLineAlignment iAlign = CFX_RTFLineAlignment::Left;
Dan Sinclaircfb856c2017-01-16 16:03:44 -0500171 switch (pStyle->GetTextAlign()) {
Dan Sinclair96f482c2017-01-11 16:31:27 -0500172 case FDE_CSSTextAlign::Right:
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500173 iAlign = CFX_RTFLineAlignment::Right;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500174 break;
Dan Sinclair96f482c2017-01-11 16:31:27 -0500175 case FDE_CSSTextAlign::Center:
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500176 iAlign = CFX_RTFLineAlignment::Center;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500177 break;
Dan Sinclair96f482c2017-01-11 16:31:27 -0500178 case FDE_CSSTextAlign::Justify:
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500179 iAlign = CFX_RTFLineAlignment::Justified;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500180 break;
Dan Sinclair96f482c2017-01-11 16:31:27 -0500181 case FDE_CSSTextAlign::JustifyAll:
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500182 iAlign = CFX_RTFLineAlignment::Distributed;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500183 break;
184 default:
185 break;
186 }
187 m_pBreak->SetAlignment(iAlign);
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500188
Dan Sinclair05df0752017-03-14 14:43:42 -0400189 float fStart = 0;
Dan Sinclairb9fbe6e2017-01-16 16:07:41 -0500190 const FDE_CSSRect* pRect = pStyle->GetMarginWidth();
191 const FDE_CSSRect* pPaddingRect = pStyle->GetPaddingWidth();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500192 if (pRect) {
193 fStart = pRect->left.GetValue();
194 fLineWidth -= pRect->right.GetValue();
195 if (pPaddingRect) {
196 fStart += pPaddingRect->left.GetValue();
197 fLineWidth -= pPaddingRect->right.GetValue();
198 }
Dan Sinclair96f482c2017-01-11 16:31:27 -0500199 if (eDisplay == FDE_CSSDisplay::ListItem) {
Dan Sinclairb9fbe6e2017-01-16 16:07:41 -0500200 const FDE_CSSRect* pParRect = pParentStyle->GetMarginWidth();
201 const FDE_CSSRect* pParPaddingRect = pParentStyle->GetPaddingWidth();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500202 if (pParRect) {
203 fStart += pParRect->left.GetValue();
204 fLineWidth -= pParRect->right.GetValue();
205 if (pParPaddingRect) {
206 fStart += pParPaddingRect->left.GetValue();
207 fLineWidth -= pParPaddingRect->right.GetValue();
208 }
209 }
Dan Sinclairb9fbe6e2017-01-16 16:07:41 -0500210 FDE_CSSRect pNewRect;
Dan Sinclair96f482c2017-01-11 16:31:27 -0500211 pNewRect.left.Set(FDE_CSSLengthUnit::Point, fStart);
212 pNewRect.right.Set(FDE_CSSLengthUnit::Point, pRect->right.GetValue());
213 pNewRect.top.Set(FDE_CSSLengthUnit::Point, pRect->top.GetValue());
214 pNewRect.bottom.Set(FDE_CSSLengthUnit::Point, pRect->bottom.GetValue());
Dan Sinclaircfb856c2017-01-16 16:03:44 -0500215 pStyle->SetMarginWidth(pNewRect);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500216 }
217 }
218 m_pBreak->SetLineBoundary(fStart, fLineWidth);
Dan Sinclair05df0752017-03-14 14:43:42 -0400219 float fIndent = pStyle->GetTextIndent().GetValue();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500220 if (fIndent > 0)
221 fStart += fIndent;
222
223 m_pBreak->SetLineStartPos(fStart);
224 m_pBreak->SetTabWidth(m_textParser.GetTabInterval(pStyle));
225 if (!m_pTabstopContext)
226 m_pTabstopContext = pdfium::MakeUnique<CXFA_TextTabstopsContext>();
227 m_textParser.GetTabstops(pStyle, m_pTabstopContext.get());
Tom Sepez5c500ac2017-03-27 12:44:20 -0700228 for (const auto& stop : m_pTabstopContext->m_tabstops)
229 m_pBreak->AddPositionedTab(stop.fTabstops);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500230 }
Dan Sinclair05df0752017-03-14 14:43:42 -0400231 float fFontSize = m_textParser.GetFontSize(m_pTextProvider, pStyle);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500232 m_pBreak->SetFontSize(fFontSize);
233 m_pBreak->SetLineBreakTolerance(fFontSize * 0.2f);
234 m_pBreak->SetFont(m_textParser.GetFont(m_pTextProvider, pStyle));
235 m_pBreak->SetHorizontalScale(
236 m_textParser.GetHorScale(m_pTextProvider, pStyle, pXMLNode));
237 m_pBreak->SetVerticalScale(m_textParser.GetVerScale(m_pTextProvider, pStyle));
Dan Sinclaircfb856c2017-01-16 16:03:44 -0500238 m_pBreak->SetCharSpace(pStyle->GetLetterSpacing().GetValue());
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500239}
240
241int32_t CXFA_TextLayout::GetText(CFX_WideString& wsText) {
242 GetTextDataNode();
243 wsText.clear();
244 if (!m_bRichText)
245 wsText = m_pTextDataNode->GetContent();
246 return wsText.GetLength();
247}
248
Dan Sinclair05df0752017-03-14 14:43:42 -0400249float CXFA_TextLayout::GetLayoutHeight() {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500250 if (!m_pLoader)
251 return 0;
252
Tom Sepezfcc309e2017-03-24 14:19:11 -0700253 if (m_pLoader->m_lineHeights.empty() && m_pLoader->m_fWidth > 0) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500254 CFX_SizeF szMax(m_pLoader->m_fWidth, m_pLoader->m_fHeight);
255 CFX_SizeF szDef;
256 m_pLoader->m_bSaveLineHeight = true;
257 m_pLoader->m_fLastPos = 0;
258 CalcSize(szMax, szMax, szDef);
259 m_pLoader->m_bSaveLineHeight = false;
dan sinclair071d7862017-02-07 20:46:32 -0500260 return szDef.height;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500261 }
262
Dan Sinclair05df0752017-03-14 14:43:42 -0400263 float fHeight = m_pLoader->m_fHeight;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500264 if (fHeight < 0.1f) {
265 fHeight = 0;
Tom Sepezfcc309e2017-03-24 14:19:11 -0700266 for (float value : m_pLoader->m_lineHeights)
267 fHeight += value;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500268 }
269 return fHeight;
270}
271
Dan Sinclair05df0752017-03-14 14:43:42 -0400272float CXFA_TextLayout::StartLayout(float fWidth) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500273 if (!m_pLoader)
274 m_pLoader = pdfium::MakeUnique<CXFA_LoaderContext>();
275
Dan Sinclair669a4182017-04-03 14:51:45 -0400276 if (fWidth < 0 ||
277 (m_pLoader->m_fWidth > -1 && fabs(fWidth - m_pLoader->m_fWidth) > 0)) {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700278 m_pLoader->m_lineHeights.clear();
279 m_Blocks.clear();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500280 Unload();
281 m_pLoader->m_fStartLineOffset = 0;
282 }
283 m_pLoader->m_fWidth = fWidth;
284
285 if (fWidth < 0) {
286 CFX_SizeF szMax;
287 CFX_SizeF szDef;
288 m_pLoader->m_bSaveLineHeight = true;
289 m_pLoader->m_fLastPos = 0;
290 CalcSize(szMax, szMax, szDef);
291 m_pLoader->m_bSaveLineHeight = false;
dan sinclair071d7862017-02-07 20:46:32 -0500292 fWidth = szDef.width;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500293 }
294 return fWidth;
295}
296
297bool CXFA_TextLayout::DoLayout(int32_t iBlockIndex,
Dan Sinclair05df0752017-03-14 14:43:42 -0400298 float& fCalcHeight,
299 float fContentAreaHeight,
300 float fTextHeight) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500301 if (!m_pLoader)
302 return false;
303
Tom Sepezfcc309e2017-03-24 14:19:11 -0700304 int32_t iBlockCount = pdfium::CollectionSize<int32_t>(m_Blocks);
Dan Sinclair05df0752017-03-14 14:43:42 -0400305 float fHeight = fTextHeight;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500306 if (fHeight < 0)
307 fHeight = GetLayoutHeight();
308
309 m_pLoader->m_fHeight = fHeight;
310 if (fContentAreaHeight < 0)
311 return false;
312
313 m_bHasBlock = true;
314 if (iBlockCount == 0 && fHeight > 0) {
315 fHeight = fTextHeight - GetLayoutHeight();
316 if (fHeight > 0) {
317 int32_t iAlign = m_textParser.GetVAlign(m_pTextProvider);
318 if (iAlign == XFA_ATTRIBUTEENUM_Middle)
319 fHeight /= 2.0f;
320 else if (iAlign != XFA_ATTRIBUTEENUM_Bottom)
321 fHeight = 0;
322 m_pLoader->m_fStartLineOffset = fHeight;
323 }
324 }
325
Dan Sinclair05df0752017-03-14 14:43:42 -0400326 float fLinePos = m_pLoader->m_fStartLineOffset;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500327 int32_t iLineIndex = 0;
328 if (iBlockCount > 1) {
329 if (iBlockCount >= (iBlockIndex + 1) * 2) {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700330 iLineIndex = m_Blocks[iBlockIndex * 2];
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500331 } else {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700332 iLineIndex = m_Blocks[iBlockCount - 1] + m_Blocks[iBlockCount - 2];
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500333 }
334 if (!m_pLoader->m_BlocksHeight.empty()) {
335 for (int32_t i = 0; i < iBlockIndex; i++)
336 fLinePos -= m_pLoader->m_BlocksHeight[i * 2 + 1];
337 }
338 }
339
Tom Sepezfcc309e2017-03-24 14:19:11 -0700340 int32_t iCount = pdfium::CollectionSize<int32_t>(m_pLoader->m_lineHeights);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500341 int32_t i = 0;
342 for (i = iLineIndex; i < iCount; i++) {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700343 float fLineHeight = m_pLoader->m_lineHeights[i];
344 if (i == iLineIndex && fLineHeight - fContentAreaHeight > 0.001) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500345 fCalcHeight = 0;
346 return true;
347 }
348 if (fLinePos + fLineHeight - fContentAreaHeight > 0.001) {
349 if (iBlockCount >= (iBlockIndex + 1) * 2) {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700350 m_Blocks[iBlockIndex * 2] = iLineIndex;
351 m_Blocks[iBlockIndex * 2 + 1] = i - iLineIndex;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500352 } else {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700353 m_Blocks.push_back(iLineIndex);
354 m_Blocks.push_back(i - iLineIndex);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500355 }
356 if (i == iLineIndex) {
357 if (fCalcHeight <= fLinePos) {
358 if (pdfium::CollectionSize<int32_t>(m_pLoader->m_BlocksHeight) >
359 iBlockIndex * 2 &&
360 (m_pLoader->m_BlocksHeight[iBlockIndex * 2] == iBlockIndex)) {
361 m_pLoader->m_BlocksHeight[iBlockIndex * 2 + 1] = fCalcHeight;
362 } else {
Dan Sinclair05df0752017-03-14 14:43:42 -0400363 m_pLoader->m_BlocksHeight.push_back((float)iBlockIndex);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500364 m_pLoader->m_BlocksHeight.push_back(fCalcHeight);
365 }
366 }
367 return true;
368 }
369
370 fCalcHeight = fLinePos;
371 return true;
372 }
373 fLinePos += fLineHeight;
374 }
375 return false;
376}
377
378int32_t CXFA_TextLayout::CountBlocks() const {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700379 int32_t iCount = pdfium::CollectionSize<int32_t>(m_Blocks) / 2;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500380 return iCount > 0 ? iCount : 1;
381}
382
383bool CXFA_TextLayout::CalcSize(const CFX_SizeF& minSize,
384 const CFX_SizeF& maxSize,
385 CFX_SizeF& defaultSize) {
dan sinclair071d7862017-02-07 20:46:32 -0500386 defaultSize.width = maxSize.width;
387 if (defaultSize.width < 1)
388 defaultSize.width = 0xFFFF;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500389
Dan Sinclairb0d31602017-03-01 15:58:32 -0500390 m_pBreak = CreateBreak(false);
Dan Sinclair05df0752017-03-14 14:43:42 -0400391 float fLinePos = 0;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500392 m_iLines = 0;
393 m_fMaxWidth = 0;
394 Loader(defaultSize, fLinePos, false);
395 if (fLinePos < 0.1f)
396 fLinePos = m_textParser.GetFontSize(m_pTextProvider, nullptr);
397
398 m_pTabstopContext.reset();
399 defaultSize = CFX_SizeF(m_fMaxWidth, fLinePos);
400 return true;
401}
402
Dan Sinclair05df0752017-03-14 14:43:42 -0400403bool CXFA_TextLayout::Layout(const CFX_SizeF& size, float* fHeight) {
dan sinclair071d7862017-02-07 20:46:32 -0500404 if (size.width < 1)
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500405 return false;
406
407 Unload();
Dan Sinclairb0d31602017-03-01 15:58:32 -0500408 m_pBreak = CreateBreak(true);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500409 if (m_pLoader) {
410 m_pLoader->m_iTotalLines = -1;
411 m_pLoader->m_iChar = 0;
412 }
413
414 m_iLines = 0;
Dan Sinclair05df0752017-03-14 14:43:42 -0400415 float fLinePos = 0;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500416 Loader(size, fLinePos, true);
dan sinclair071d7862017-02-07 20:46:32 -0500417 UpdateAlign(size.height, fLinePos);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500418 m_pTabstopContext.reset();
419 if (fHeight)
420 *fHeight = fLinePos;
421 return true;
422}
423
424bool CXFA_TextLayout::Layout(int32_t iBlock) {
425 if (!m_pLoader || iBlock < 0 || iBlock >= CountBlocks())
426 return false;
427 if (m_pLoader->m_fWidth < 1)
428 return false;
429
430 m_pLoader->m_iTotalLines = -1;
431 m_iLines = 0;
Dan Sinclair05df0752017-03-14 14:43:42 -0400432 float fLinePos = 0;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500433 CXFA_Node* pNode = nullptr;
434 CFX_SizeF szText(m_pLoader->m_fWidth, m_pLoader->m_fHeight);
Tom Sepezfcc309e2017-03-24 14:19:11 -0700435 int32_t iCount = pdfium::CollectionSize<int32_t>(m_Blocks);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500436 int32_t iBlocksHeightCount =
437 pdfium::CollectionSize<int32_t>(m_pLoader->m_BlocksHeight);
438 iBlocksHeightCount /= 2;
439 if (iBlock < iBlocksHeightCount)
440 return true;
441 if (iBlock == iBlocksHeightCount) {
442 Unload();
Dan Sinclairb0d31602017-03-01 15:58:32 -0500443 m_pBreak = CreateBreak(true);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500444 fLinePos = m_pLoader->m_fStartLineOffset;
445 for (int32_t i = 0; i < iBlocksHeightCount; i++)
446 fLinePos -= m_pLoader->m_BlocksHeight[i * 2 + 1];
447
448 m_pLoader->m_iChar = 0;
449 if (iCount > 1)
Tom Sepezfcc309e2017-03-24 14:19:11 -0700450 m_pLoader->m_iTotalLines = m_Blocks[iBlock * 2 + 1];
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500451
452 Loader(szText, fLinePos, true);
453 if (iCount == 0 && m_pLoader->m_fStartLineOffset < 0.1f)
dan sinclair071d7862017-02-07 20:46:32 -0500454 UpdateAlign(szText.height, fLinePos);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500455 } else if (m_pTextDataNode) {
456 iBlock *= 2;
457 if (iBlock < iCount - 2)
Tom Sepezfcc309e2017-03-24 14:19:11 -0700458 m_pLoader->m_iTotalLines = m_Blocks[iBlock + 1];
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500459
460 m_pBreak->Reset();
461 if (m_bRichText) {
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400462 CFX_XMLNode* pContainerNode = GetXMLContainerNode();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500463 if (!pContainerNode)
464 return true;
465
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400466 CFX_XMLNode* pXMLNode = m_pLoader->m_pXMLNode;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500467 if (!pXMLNode)
468 return true;
469
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400470 CFX_XMLNode* pSaveXMLNode = m_pLoader->m_pXMLNode;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500471 for (; pXMLNode;
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400472 pXMLNode = pXMLNode->GetNodeItem(CFX_XMLNode::NextSibling)) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500473 if (!LoadRichText(pXMLNode, szText, fLinePos, m_pLoader->m_pParentStyle,
Tom Sepez03de8842017-01-24 14:24:36 -0800474 true, nullptr)) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500475 break;
476 }
477 }
478 while (!pXMLNode) {
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400479 pXMLNode = pSaveXMLNode->GetNodeItem(CFX_XMLNode::Parent);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500480 if (pXMLNode == pContainerNode)
481 break;
482 if (!LoadRichText(pXMLNode, szText, fLinePos, m_pLoader->m_pParentStyle,
483 true, nullptr, false)) {
484 break;
485 }
486 pSaveXMLNode = pXMLNode;
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400487 pXMLNode = pXMLNode->GetNodeItem(CFX_XMLNode::NextSibling);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500488 if (!pXMLNode)
489 continue;
490 for (; pXMLNode;
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400491 pXMLNode = pXMLNode->GetNodeItem(CFX_XMLNode::NextSibling)) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500492 if (!LoadRichText(pXMLNode, szText, fLinePos,
Tom Sepez03de8842017-01-24 14:24:36 -0800493 m_pLoader->m_pParentStyle, true, nullptr)) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500494 break;
495 }
496 }
497 }
498 } else {
499 pNode = m_pLoader->m_pNode;
500 if (!pNode)
501 return true;
502 LoadText(pNode, szText, fLinePos, true);
503 }
504 }
505 if (iBlock == iCount) {
506 m_pTabstopContext.reset();
507 m_pLoader.reset();
508 }
509 return true;
510}
511
512void CXFA_TextLayout::ItemBlocks(const CFX_RectF& rtText, int32_t iBlockIndex) {
513 if (!m_pLoader)
514 return;
515
Tom Sepezfcc309e2017-03-24 14:19:11 -0700516 int32_t iCountHeight =
517 pdfium::CollectionSize<int32_t>(m_pLoader->m_lineHeights);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500518 if (iCountHeight == 0)
519 return;
520
521 bool bEndItem = true;
Tom Sepezfcc309e2017-03-24 14:19:11 -0700522 int32_t iBlockCount = pdfium::CollectionSize<int32_t>(m_Blocks);
Dan Sinclair05df0752017-03-14 14:43:42 -0400523 float fLinePos = m_pLoader->m_fStartLineOffset;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500524 int32_t iLineIndex = 0;
525 if (iBlockIndex > 0) {
526 int32_t iBlockHeightCount =
527 pdfium::CollectionSize<int32_t>(m_pLoader->m_BlocksHeight);
528 iBlockHeightCount /= 2;
529 if (iBlockHeightCount >= iBlockIndex) {
530 for (int32_t i = 0; i < iBlockIndex; i++)
531 fLinePos -= m_pLoader->m_BlocksHeight[i * 2 + 1];
532 } else {
533 fLinePos = 0;
534 }
535 iLineIndex = m_Blocks[iBlockCount - 1] + m_Blocks[iBlockCount - 2];
536 }
537
538 int32_t i = 0;
539 for (i = iLineIndex; i < iCountHeight; i++) {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700540 float fLineHeight = m_pLoader->m_lineHeights[i];
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500541 if (fLinePos + fLineHeight - rtText.height > 0.001) {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700542 m_Blocks.push_back(iLineIndex);
543 m_Blocks.push_back(i - iLineIndex);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500544 bEndItem = false;
545 break;
546 }
547 fLinePos += fLineHeight;
548 }
549 if (iCountHeight > 0 && (i - iLineIndex) > 0 && bEndItem) {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700550 m_Blocks.push_back(iLineIndex);
551 m_Blocks.push_back(i - iLineIndex);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500552 }
553}
554
555bool CXFA_TextLayout::DrawString(CFX_RenderDevice* pFxDevice,
556 const CFX_Matrix& tmDoc2Device,
557 const CFX_RectF& rtClip,
558 int32_t iBlock) {
559 if (!pFxDevice)
560 return false;
561
Dan Sinclair0bb13332017-03-30 16:12:02 -0400562 auto pDevice = pdfium::MakeUnique<CFDE_RenderDevice>(pFxDevice, false);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500563 pDevice->SaveState();
564 pDevice->SetClipRect(rtClip);
565
566 auto pSolidBrush = pdfium::MakeUnique<CFDE_Brush>();
567 auto pPen = pdfium::MakeUnique<CFDE_Pen>();
tsepez783a7e02017-01-17 11:05:57 -0800568 if (m_pieceLines.empty()) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500569 int32_t iBlockCount = CountBlocks();
570 for (int32_t i = 0; i < iBlockCount; i++)
571 Layout(i);
572 }
573
574 FXTEXT_CHARPOS* pCharPos = nullptr;
575 int32_t iCharCount = 0;
576 int32_t iLineStart = 0;
tsepez783a7e02017-01-17 11:05:57 -0800577 int32_t iPieceLines = pdfium::CollectionSize<int32_t>(m_pieceLines);
Tom Sepezfcc309e2017-03-24 14:19:11 -0700578 int32_t iCount = pdfium::CollectionSize<int32_t>(m_Blocks);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500579 if (iCount > 0) {
580 iBlock *= 2;
581 if (iBlock < iCount) {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700582 iLineStart = m_Blocks[iBlock];
583 iPieceLines = m_Blocks[iBlock + 1];
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500584 } else {
585 iPieceLines = 0;
586 }
587 }
588
589 for (int32_t i = 0; i < iPieceLines; i++) {
tsepez783a7e02017-01-17 11:05:57 -0800590 if (i + iLineStart >= pdfium::CollectionSize<int32_t>(m_pieceLines))
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500591 break;
592
tsepez783a7e02017-01-17 11:05:57 -0800593 CXFA_PieceLine* pPieceLine = m_pieceLines[i + iLineStart].get();
594 int32_t iPieces = pdfium::CollectionSize<int32_t>(pPieceLine->m_textPieces);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500595 int32_t j = 0;
596 for (j = 0; j < iPieces; j++) {
tsepez783a7e02017-01-17 11:05:57 -0800597 const XFA_TextPiece* pPiece = pPieceLine->m_textPieces[j].get();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500598 int32_t iChars = pPiece->iChars;
599 if (iCharCount < iChars) {
600 FX_Free(pCharPos);
601 pCharPos = FX_Alloc(FXTEXT_CHARPOS, iChars);
602 iCharCount = iChars;
603 }
Dan Sinclair1c5d0b42017-04-03 15:05:11 -0400604 memset(pCharPos, 0, iCharCount * sizeof(FXTEXT_CHARPOS));
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500605 RenderString(pDevice.get(), pSolidBrush.get(), pPieceLine, j, pCharPos,
606 tmDoc2Device);
607 }
608 for (j = 0; j < iPieces; j++) {
609 RenderPath(pDevice.get(), pPen.get(), pPieceLine, j, pCharPos,
610 tmDoc2Device);
611 }
612 }
613 pDevice->RestoreState();
614 FX_Free(pCharPos);
615 return iPieceLines > 0;
616}
617
Dan Sinclair05df0752017-03-14 14:43:42 -0400618void CXFA_TextLayout::UpdateAlign(float fHeight, float fBottom) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500619 fHeight -= fBottom;
620 if (fHeight < 0.1f)
621 return;
622
623 switch (m_textParser.GetVAlign(m_pTextProvider)) {
624 case XFA_ATTRIBUTEENUM_Middle:
625 fHeight /= 2.0f;
626 break;
627 case XFA_ATTRIBUTEENUM_Bottom:
628 break;
629 default:
630 return;
631 }
632
tsepez783a7e02017-01-17 11:05:57 -0800633 for (const auto& pPieceLine : m_pieceLines) {
634 for (const auto& pPiece : pPieceLine->m_textPieces)
635 pPiece->rtPiece.top += fHeight;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500636 }
637}
638
639bool CXFA_TextLayout::Loader(const CFX_SizeF& szText,
Dan Sinclair05df0752017-03-14 14:43:42 -0400640 float& fLinePos,
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500641 bool bSavePieces) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500642 GetTextDataNode();
643 if (!m_pTextDataNode)
644 return true;
645
646 if (m_bRichText) {
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400647 CFX_XMLNode* pXMLContainer = GetXMLContainerNode();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500648 if (pXMLContainer) {
649 if (!m_textParser.IsParsed())
650 m_textParser.DoParse(pXMLContainer, m_pTextProvider);
651
Dan Sinclair7e5fdd02017-01-23 16:24:26 -0500652 auto pRootStyle = m_textParser.CreateRootStyle(m_pTextProvider);
Tom Sepez03de8842017-01-24 14:24:36 -0800653 LoadRichText(pXMLContainer, szText, fLinePos, pRootStyle, bSavePieces,
654 nullptr);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500655 }
656 } else {
657 LoadText(m_pTextDataNode, szText, fLinePos, bSavePieces);
658 }
659 return true;
660}
661
662void CXFA_TextLayout::LoadText(CXFA_Node* pNode,
663 const CFX_SizeF& szText,
Dan Sinclair05df0752017-03-14 14:43:42 -0400664 float& fLinePos,
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500665 bool bSavePieces) {
dan sinclair071d7862017-02-07 20:46:32 -0500666 InitBreak(szText.width);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500667
668 CXFA_Para para = m_pTextProvider->GetParaNode();
Dan Sinclair05df0752017-03-14 14:43:42 -0400669 float fSpaceAbove = 0;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500670 if (para) {
671 fSpaceAbove = para.GetSpaceAbove();
672 if (fSpaceAbove < 0.1f) {
673 fSpaceAbove = 0;
674 }
675 int32_t verAlign = para.GetVerticalAlign();
676 switch (verAlign) {
677 case XFA_ATTRIBUTEENUM_Top:
678 case XFA_ATTRIBUTEENUM_Middle:
679 case XFA_ATTRIBUTEENUM_Bottom: {
680 fLinePos += fSpaceAbove;
681 break;
682 }
683 }
684 }
685
686 CFX_WideString wsText = pNode->GetContent();
687 wsText.TrimRight(L" ");
688 bool bRet = AppendChar(wsText, fLinePos, fSpaceAbove, bSavePieces);
689 if (bRet && m_pLoader)
690 m_pLoader->m_pNode = pNode;
691 else
Dan Sinclairc36fe072017-03-09 16:58:12 -0500692 EndBreak(CFX_BreakType::Paragraph, fLinePos, bSavePieces);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500693}
694
Dan Sinclair7e5fdd02017-01-23 16:24:26 -0500695bool CXFA_TextLayout::LoadRichText(
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400696 CFX_XMLNode* pXMLNode,
Dan Sinclair7e5fdd02017-01-23 16:24:26 -0500697 const CFX_SizeF& szText,
Dan Sinclair05df0752017-03-14 14:43:42 -0400698 float& fLinePos,
Dan Sinclair7e5fdd02017-01-23 16:24:26 -0500699 const CFX_RetainPtr<CFDE_CSSComputedStyle>& pParentStyle,
700 bool bSavePieces,
Tom Sepez03de8842017-01-24 14:24:36 -0800701 CFX_RetainPtr<CXFA_LinkUserData> pLinkData,
Dan Sinclair7e5fdd02017-01-23 16:24:26 -0500702 bool bEndBreak,
703 bool bIsOl,
704 int32_t iLiCount) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500705 if (!pXMLNode)
706 return false;
707
708 CXFA_TextParseContext* pContext =
709 m_textParser.GetParseContextFromMap(pXMLNode);
Dan Sinclair96f482c2017-01-11 16:31:27 -0500710 FDE_CSSDisplay eDisplay = FDE_CSSDisplay::None;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500711 bool bContentNode = false;
Dan Sinclair05df0752017-03-14 14:43:42 -0400712 float fSpaceBelow = 0;
Dan Sinclair7e5fdd02017-01-23 16:24:26 -0500713 CFX_RetainPtr<CFDE_CSSComputedStyle> pStyle;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500714 CFX_WideString wsName;
715 if (bEndBreak) {
716 bool bCurOl = false;
717 bool bCurLi = false;
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400718 CFX_XMLElement* pElement = nullptr;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500719 if (pContext) {
720 if (m_bBlockContinue ||
721 (m_pLoader && pXMLNode == m_pLoader->m_pXMLNode)) {
722 m_bBlockContinue = true;
723 }
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400724 if (pXMLNode->GetType() == FX_XMLNODE_Text) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500725 bContentNode = true;
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400726 } else if (pXMLNode->GetType() == FX_XMLNODE_Element) {
727 pElement = static_cast<CFX_XMLElement*>(pXMLNode);
Dan Sinclair5fa4e982017-04-05 11:48:21 -0400728 wsName = pElement->GetLocalTagName();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500729 }
dan sinclair65c7c232017-02-02 14:05:30 -0800730 if (wsName == L"ol") {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500731 bIsOl = true;
732 bCurOl = true;
733 }
734 if (m_bBlockContinue || bContentNode == false) {
735 eDisplay = pContext->GetDisplay();
Dan Sinclair96f482c2017-01-11 16:31:27 -0500736 if (eDisplay != FDE_CSSDisplay::Block &&
737 eDisplay != FDE_CSSDisplay::Inline &&
738 eDisplay != FDE_CSSDisplay::ListItem) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500739 return true;
740 }
741
Dan Sinclair7e5fdd02017-01-23 16:24:26 -0500742 pStyle = m_textParser.ComputeStyle(pXMLNode, pParentStyle.Get());
743 InitBreak(bContentNode ? pParentStyle.Get() : pStyle.Get(), eDisplay,
dan sinclair071d7862017-02-07 20:46:32 -0500744 szText.width, pXMLNode, pParentStyle.Get());
Dan Sinclair96f482c2017-01-11 16:31:27 -0500745 if ((eDisplay == FDE_CSSDisplay::Block ||
746 eDisplay == FDE_CSSDisplay::ListItem) &&
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500747 pStyle &&
dan sinclair65c7c232017-02-02 14:05:30 -0800748 (wsName.IsEmpty() || (wsName != L"body" && wsName != L"html" &&
749 wsName != L"ol" && wsName != L"ul"))) {
Dan Sinclairb9fbe6e2017-01-16 16:07:41 -0500750 const FDE_CSSRect* pRect = pStyle->GetMarginWidth();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500751 if (pRect) {
752 fLinePos += pRect->top.GetValue();
753 fSpaceBelow = pRect->bottom.GetValue();
754 }
755 }
756
dan sinclair65c7c232017-02-02 14:05:30 -0800757 if (wsName == L"a") {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500758 ASSERT(pElement);
Dan Sinclair5fa4e982017-04-05 11:48:21 -0400759 CFX_WideString wsLinkContent = pElement->GetString(L"href");
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500760 if (!wsLinkContent.IsEmpty()) {
Tom Sepez03de8842017-01-24 14:24:36 -0800761 pLinkData = pdfium::MakeRetain<CXFA_LinkUserData>(
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500762 wsLinkContent.GetBuffer(wsLinkContent.GetLength()));
763 wsLinkContent.ReleaseBuffer(wsLinkContent.GetLength());
764 }
765 }
766
Dan Sinclair7e5fdd02017-01-23 16:24:26 -0500767 int32_t iTabCount = m_textParser.CountTabs(
768 bContentNode ? pParentStyle.Get() : pStyle.Get());
769 bool bSpaceRun = m_textParser.IsSpaceRun(
770 bContentNode ? pParentStyle.Get() : pStyle.Get());
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500771 CFX_WideString wsText;
772 if (bContentNode && iTabCount == 0) {
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400773 wsText = static_cast<CFX_XMLText*>(pXMLNode)->GetText();
dan sinclair65c7c232017-02-02 14:05:30 -0800774 } else if (wsName == L"br") {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500775 wsText = L'\n';
dan sinclair65c7c232017-02-02 14:05:30 -0800776 } else if (wsName == L"li") {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500777 bCurLi = true;
778 if (bIsOl)
779 wsText.Format(L"%d. ", iLiCount);
780 else
dan sinclair65c7c232017-02-02 14:05:30 -0800781 wsText = 0x00B7 + CFX_WideStringC(L" ", 1);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500782 } else if (!bContentNode) {
783 if (iTabCount > 0) {
784 while (iTabCount-- > 0)
785 wsText += L'\t';
786 } else {
787 m_textParser.GetEmbbedObj(m_pTextProvider, pXMLNode, wsText);
788 }
789 }
790
791 int32_t iLength = wsText.GetLength();
792 if (iLength > 0 && bContentNode && !bSpaceRun)
793 ProcessText(wsText);
794
795 if (m_pLoader) {
796 if (wsText.GetLength() > 0 &&
797 (m_pLoader->m_dwFlags & XFA_LOADERCNTXTFLG_FILTERSPACE)) {
798 wsText.TrimLeft(0x20);
799 }
Dan Sinclair96f482c2017-01-11 16:31:27 -0500800 if (FDE_CSSDisplay::Block == eDisplay) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500801 m_pLoader->m_dwFlags |= XFA_LOADERCNTXTFLG_FILTERSPACE;
Dan Sinclair96f482c2017-01-11 16:31:27 -0500802 } else if (FDE_CSSDisplay::Inline == eDisplay &&
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500803 (m_pLoader->m_dwFlags & XFA_LOADERCNTXTFLG_FILTERSPACE)) {
804 m_pLoader->m_dwFlags &= ~XFA_LOADERCNTXTFLG_FILTERSPACE;
805 } else if (wsText.GetLength() > 0 &&
806 (0x20 == wsText.GetAt(wsText.GetLength() - 1))) {
807 m_pLoader->m_dwFlags |= XFA_LOADERCNTXTFLG_FILTERSPACE;
808 } else if (wsText.GetLength() != 0) {
809 m_pLoader->m_dwFlags &= ~XFA_LOADERCNTXTFLG_FILTERSPACE;
810 }
811 }
812
813 if (wsText.GetLength() > 0) {
814 if (!m_pLoader || m_pLoader->m_iChar == 0) {
Tom Sepez03de8842017-01-24 14:24:36 -0800815 auto pUserData = pdfium::MakeRetain<CXFA_TextUserData>(
Dan Sinclair0cb9b8c2017-01-10 16:38:10 -0500816 bContentNode ? pParentStyle : pStyle, pLinkData);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500817 m_pBreak->SetUserData(pUserData);
818 }
819
820 if (AppendChar(wsText, fLinePos, 0, bSavePieces)) {
821 if (m_pLoader)
822 m_pLoader->m_dwFlags &= ~XFA_LOADERCNTXTFLG_FILTERSPACE;
823 if (IsEnd(bSavePieces)) {
824 if (m_pLoader && m_pLoader->m_iTotalLines > -1) {
825 m_pLoader->m_pXMLNode = pXMLNode;
826 m_pLoader->m_pParentStyle = pParentStyle;
827 }
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500828 return false;
829 }
830 return true;
831 }
832 }
833 }
834 }
835
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400836 for (CFX_XMLNode* pChildNode =
837 pXMLNode->GetNodeItem(CFX_XMLNode::FirstChild);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500838 pChildNode;
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400839 pChildNode = pChildNode->GetNodeItem(CFX_XMLNode::NextSibling)) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500840 if (bCurOl)
841 iLiCount++;
842
843 if (!LoadRichText(pChildNode, szText, fLinePos,
844 pContext ? pStyle : pParentStyle, bSavePieces,
845 pLinkData, true, bIsOl, iLiCount))
846 return false;
847 }
848
849 if (m_pLoader) {
Dan Sinclair96f482c2017-01-11 16:31:27 -0500850 if (FDE_CSSDisplay::Block == eDisplay)
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500851 m_pLoader->m_dwFlags |= XFA_LOADERCNTXTFLG_FILTERSPACE;
852 }
853 if (bCurLi)
Dan Sinclairc36fe072017-03-09 16:58:12 -0500854 EndBreak(CFX_BreakType::Line, fLinePos, bSavePieces);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500855 } else {
856 if (pContext)
857 eDisplay = pContext->GetDisplay();
858 }
859
860 if (m_bBlockContinue) {
861 if (pContext && !bContentNode) {
Dan Sinclairc36fe072017-03-09 16:58:12 -0500862 CFX_BreakType dwStatus = (eDisplay == FDE_CSSDisplay::Block)
863 ? CFX_BreakType::Paragraph
864 : CFX_BreakType::Piece;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500865 EndBreak(dwStatus, fLinePos, bSavePieces);
Dan Sinclair96f482c2017-01-11 16:31:27 -0500866 if (eDisplay == FDE_CSSDisplay::Block) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500867 fLinePos += fSpaceBelow;
868 if (m_pTabstopContext)
869 m_pTabstopContext->RemoveAll();
870 }
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500871 if (IsEnd(bSavePieces)) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500872 if (m_pLoader && m_pLoader->m_iTotalLines > -1) {
873 m_pLoader->m_pXMLNode =
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400874 pXMLNode->GetNodeItem(CFX_XMLNode::NextSibling);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500875 m_pLoader->m_pParentStyle = pParentStyle;
876 }
877 return false;
878 }
879 }
880 }
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500881 return true;
882}
883
884bool CXFA_TextLayout::AppendChar(const CFX_WideString& wsText,
Dan Sinclair05df0752017-03-14 14:43:42 -0400885 float& fLinePos,
886 float fSpaceAbove,
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500887 bool bSavePieces) {
Dan Sinclairc36fe072017-03-09 16:58:12 -0500888 CFX_BreakType dwStatus = CFX_BreakType::None;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500889 int32_t iChar = 0;
890 if (m_pLoader)
891 iChar = m_pLoader->m_iChar;
892
893 int32_t iLength = wsText.GetLength();
894 for (int32_t i = iChar; i < iLength; i++) {
Dan Sinclair812e96c2017-03-13 16:43:37 -0400895 wchar_t wch = wsText.GetAt(i);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500896 if (wch == 0xA0)
897 wch = 0x20;
898
Dan Sinclaird2ee0f32017-02-28 14:46:18 -0500899 dwStatus = m_pBreak->AppendChar(wch);
Dan Sinclairc36fe072017-03-09 16:58:12 -0500900 if (dwStatus != CFX_BreakType::None && dwStatus != CFX_BreakType::Piece) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500901 AppendTextLine(dwStatus, fLinePos, bSavePieces);
902 if (IsEnd(bSavePieces)) {
903 if (m_pLoader)
904 m_pLoader->m_iChar = i;
905 return true;
906 }
Dan Sinclairc36fe072017-03-09 16:58:12 -0500907 if (dwStatus == CFX_BreakType::Paragraph && m_bRichText)
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500908 fLinePos += fSpaceAbove;
909 }
910 }
911 if (m_pLoader)
912 m_pLoader->m_iChar = 0;
913
914 return false;
915}
916
917bool CXFA_TextLayout::IsEnd(bool bSavePieces) {
918 if (!bSavePieces)
919 return false;
920 if (m_pLoader && m_pLoader->m_iTotalLines > 0)
921 return m_iLines >= m_pLoader->m_iTotalLines;
922 return false;
923}
924
925void CXFA_TextLayout::ProcessText(CFX_WideString& wsText) {
926 int32_t iLen = wsText.GetLength();
927 if (iLen == 0)
928 return;
929
Dan Sinclair812e96c2017-03-13 16:43:37 -0400930 wchar_t* psz = wsText.GetBuffer(iLen);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500931 int32_t iTrimLeft = 0;
Dan Sinclair812e96c2017-03-13 16:43:37 -0400932 wchar_t wch = 0, wPrev = 0;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500933 for (int32_t i = 0; i < iLen; i++) {
934 wch = psz[i];
935 if (wch < 0x20)
936 wch = 0x20;
937 if (wch == 0x20 && wPrev == 0x20)
938 continue;
939
940 wPrev = wch;
941 psz[iTrimLeft++] = wch;
942 }
943 wsText.ReleaseBuffer(iLen);
944 wsText = wsText.Left(iTrimLeft);
945}
946
Dan Sinclairc36fe072017-03-09 16:58:12 -0500947void CXFA_TextLayout::EndBreak(CFX_BreakType dwStatus,
Dan Sinclair05df0752017-03-14 14:43:42 -0400948 float& fLinePos,
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500949 bool bSavePieces) {
950 dwStatus = m_pBreak->EndBreak(dwStatus);
Dan Sinclairc36fe072017-03-09 16:58:12 -0500951 if (dwStatus != CFX_BreakType::None && dwStatus != CFX_BreakType::Piece)
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500952 AppendTextLine(dwStatus, fLinePos, bSavePieces, true);
953}
954
Dan Sinclaircfb856c2017-01-16 16:03:44 -0500955void CXFA_TextLayout::DoTabstops(CFDE_CSSComputedStyle* pStyle,
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500956 CXFA_PieceLine* pPieceLine) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500957 if (!pStyle || !pPieceLine)
958 return;
959
Tom Sepez5c500ac2017-03-27 12:44:20 -0700960 if (!m_pTabstopContext || m_pTabstopContext->m_tabstops.empty())
961 return;
962
tsepez783a7e02017-01-17 11:05:57 -0800963 int32_t iPieces = pdfium::CollectionSize<int32_t>(pPieceLine->m_textPieces);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500964 if (iPieces == 0)
965 return;
966
tsepez783a7e02017-01-17 11:05:57 -0800967 XFA_TextPiece* pPiece = pPieceLine->m_textPieces[iPieces - 1].get();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500968 int32_t& iTabstopsIndex = m_pTabstopContext->m_iTabIndex;
969 int32_t iCount = m_textParser.CountTabs(pStyle);
Tom Sepez5c500ac2017-03-27 12:44:20 -0700970 if (!pdfium::IndexInBounds(m_pTabstopContext->m_tabstops, iTabstopsIndex))
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500971 return;
972
973 if (iCount > 0) {
974 iTabstopsIndex++;
975 m_pTabstopContext->m_bTabstops = true;
Dan Sinclair05df0752017-03-14 14:43:42 -0400976 float fRight = 0;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500977 if (iPieces > 1) {
tsepez783a7e02017-01-17 11:05:57 -0800978 XFA_TextPiece* p = pPieceLine->m_textPieces[iPieces - 2].get();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500979 fRight = p->rtPiece.right();
980 }
981 m_pTabstopContext->m_fTabWidth =
982 pPiece->rtPiece.width + pPiece->rtPiece.left - fRight;
983 } else if (iTabstopsIndex > -1) {
Dan Sinclair05df0752017-03-14 14:43:42 -0400984 float fLeft = 0;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500985 if (m_pTabstopContext->m_bTabstops) {
Tom Sepez5c500ac2017-03-27 12:44:20 -0700986 uint32_t dwAlign = m_pTabstopContext->m_tabstops[iTabstopsIndex].dwAlign;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500987 if (dwAlign == FX_HashCode_GetW(L"center", false)) {
988 fLeft = pPiece->rtPiece.width / 2.0f;
989 } else if (dwAlign == FX_HashCode_GetW(L"right", false) ||
990 dwAlign == FX_HashCode_GetW(L"before", false)) {
991 fLeft = pPiece->rtPiece.width;
992 } else if (dwAlign == FX_HashCode_GetW(L"decimal", false)) {
993 int32_t iChars = pPiece->iChars;
994 for (int32_t i = 0; i < iChars; i++) {
Dan Sinclairbef73892017-03-01 11:23:14 -0500995 if (pPiece->szText[i] == L'.')
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500996 break;
997
Dan Sinclairbef73892017-03-01 11:23:14 -0500998 fLeft += pPiece->Widths[i] / 20000.0f;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500999 }
1000 }
1001 m_pTabstopContext->m_fLeft =
1002 std::min(fLeft, m_pTabstopContext->m_fTabWidth);
1003 m_pTabstopContext->m_bTabstops = false;
1004 m_pTabstopContext->m_fTabWidth = 0;
1005 }
1006 pPiece->rtPiece.left -= m_pTabstopContext->m_fLeft;
1007 }
1008}
1009
Dan Sinclairc36fe072017-03-09 16:58:12 -05001010void CXFA_TextLayout::AppendTextLine(CFX_BreakType dwStatus,
Dan Sinclair05df0752017-03-14 14:43:42 -04001011 float& fLinePos,
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001012 bool bSavePieces,
1013 bool bEndBreak) {
1014 int32_t iPieces = m_pBreak->CountBreakPieces();
1015 if (iPieces < 1)
1016 return;
1017
Dan Sinclair7e5fdd02017-01-23 16:24:26 -05001018 CFX_RetainPtr<CFDE_CSSComputedStyle> pStyle;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001019 if (bSavePieces) {
tsepez783a7e02017-01-17 11:05:57 -08001020 auto pNew = pdfium::MakeUnique<CXFA_PieceLine>();
1021 CXFA_PieceLine* pPieceLine = pNew.get();
1022 m_pieceLines.push_back(std::move(pNew));
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001023 if (m_pTabstopContext)
1024 m_pTabstopContext->Reset();
1025
Dan Sinclair05df0752017-03-14 14:43:42 -04001026 float fLineStep = 0, fBaseLine = 0;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001027 int32_t i = 0;
1028 for (i = 0; i < iPieces; i++) {
Dan Sinclair893822a2017-03-13 15:32:07 -04001029 const CFX_BreakPiece* pPiece = m_pBreak->GetBreakPieceUnstable(i);
Tom Sepeze02b2bc2017-05-09 10:12:39 -07001030 CXFA_TextUserData* pUserData = pPiece->m_pUserData.Get();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001031 if (pUserData)
1032 pStyle = pUserData->m_pStyle;
Dan Sinclair05df0752017-03-14 14:43:42 -04001033 float fVerScale = pPiece->m_iVerticalScale / 100.0f;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001034
tsepez783a7e02017-01-17 11:05:57 -08001035 auto pTP = pdfium::MakeUnique<XFA_TextPiece>();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001036 pTP->iChars = pPiece->m_iChars;
Dan Sinclairbef73892017-03-01 11:23:14 -05001037 pTP->szText = pPiece->GetString();
1038 pTP->Widths = pPiece->GetWidths();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001039 pTP->iBidiLevel = pPiece->m_iBidiLevel;
1040 pTP->iHorScale = pPiece->m_iHorizontalScale;
1041 pTP->iVerScale = pPiece->m_iVerticalScale;
Dan Sinclair7e5fdd02017-01-23 16:24:26 -05001042 m_textParser.GetUnderline(m_pTextProvider, pStyle.Get(), pTP->iUnderline,
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001043 pTP->iPeriod);
Dan Sinclair7e5fdd02017-01-23 16:24:26 -05001044 m_textParser.GetLinethrough(m_pTextProvider, pStyle.Get(),
1045 pTP->iLineThrough);
1046 pTP->dwColor = m_textParser.GetColor(m_pTextProvider, pStyle.Get());
1047 pTP->pFont = m_textParser.GetFont(m_pTextProvider, pStyle.Get());
1048 pTP->fFontSize = m_textParser.GetFontSize(m_pTextProvider, pStyle.Get());
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001049 pTP->rtPiece.left = pPiece->m_iStartPos / 20000.0f;
1050 pTP->rtPiece.width = pPiece->m_iWidth / 20000.0f;
Dan Sinclair05df0752017-03-14 14:43:42 -04001051 pTP->rtPiece.height = (float)pPiece->m_iFontSize * fVerScale / 20.0f;
1052 float fBaseLineTemp =
Dan Sinclair7e5fdd02017-01-23 16:24:26 -05001053 m_textParser.GetBaseline(m_pTextProvider, pStyle.Get());
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001054 pTP->rtPiece.top = fBaseLineTemp;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001055
Dan Sinclair05df0752017-03-14 14:43:42 -04001056 float fLineHeight = m_textParser.GetLineHeight(
Dan Sinclair7e5fdd02017-01-23 16:24:26 -05001057 m_pTextProvider, pStyle.Get(), m_iLines == 0, fVerScale);
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001058 if (fBaseLineTemp > 0) {
Dan Sinclair05df0752017-03-14 14:43:42 -04001059 float fLineHeightTmp = fBaseLineTemp + pTP->rtPiece.height;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001060 if (fLineHeight < fLineHeightTmp)
1061 fLineHeight = fLineHeightTmp;
1062 else
1063 fBaseLineTemp = 0;
1064 } else if (fBaseLine < -fBaseLineTemp) {
1065 fBaseLine = -fBaseLineTemp;
1066 }
1067 fLineStep = std::max(fLineStep, fLineHeight);
Tom Sepez03de8842017-01-24 14:24:36 -08001068 pTP->pLinkData = pUserData ? pUserData->m_pLinkData : nullptr;
tsepez783a7e02017-01-17 11:05:57 -08001069 pPieceLine->m_textPieces.push_back(std::move(pTP));
Dan Sinclair7e5fdd02017-01-23 16:24:26 -05001070 DoTabstops(pStyle.Get(), pPieceLine);
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001071 }
tsepez783a7e02017-01-17 11:05:57 -08001072 for (const auto& pTP : pPieceLine->m_textPieces) {
Dan Sinclair05df0752017-03-14 14:43:42 -04001073 float& fTop = pTP->rtPiece.top;
1074 float fBaseLineTemp = fTop;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001075 fTop = fLinePos + fLineStep - pTP->rtPiece.height - fBaseLineTemp;
1076 fTop = std::max(0.0f, fTop);
1077 }
1078 fLinePos += fLineStep + fBaseLine;
1079 } else {
Dan Sinclair05df0752017-03-14 14:43:42 -04001080 float fLineStep = 0;
1081 float fLineWidth = 0;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001082 for (int32_t i = 0; i < iPieces; i++) {
Dan Sinclair893822a2017-03-13 15:32:07 -04001083 const CFX_BreakPiece* pPiece = m_pBreak->GetBreakPieceUnstable(i);
Tom Sepeze02b2bc2017-05-09 10:12:39 -07001084 CXFA_TextUserData* pUserData = pPiece->m_pUserData.Get();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001085 if (pUserData)
1086 pStyle = pUserData->m_pStyle;
Dan Sinclair05df0752017-03-14 14:43:42 -04001087 float fVerScale = pPiece->m_iVerticalScale / 100.0f;
1088 float fBaseLine = m_textParser.GetBaseline(m_pTextProvider, pStyle.Get());
1089 float fLineHeight = m_textParser.GetLineHeight(
Dan Sinclair7e5fdd02017-01-23 16:24:26 -05001090 m_pTextProvider, pStyle.Get(), m_iLines == 0, fVerScale);
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001091 if (fBaseLine > 0) {
Dan Sinclair05df0752017-03-14 14:43:42 -04001092 float fLineHeightTmp =
1093 fBaseLine + (float)pPiece->m_iFontSize * fVerScale / 20.0f;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001094 if (fLineHeight < fLineHeightTmp) {
1095 fLineHeight = fLineHeightTmp;
1096 }
1097 }
1098 fLineStep = std::max(fLineStep, fLineHeight);
1099 fLineWidth += pPiece->m_iWidth / 20000.0f;
1100 }
1101 fLinePos += fLineStep;
1102 m_fMaxWidth = std::max(m_fMaxWidth, fLineWidth);
1103 if (m_pLoader && m_pLoader->m_bSaveLineHeight) {
Dan Sinclair05df0752017-03-14 14:43:42 -04001104 float fHeight = fLinePos - m_pLoader->m_fLastPos;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001105 m_pLoader->m_fLastPos = fLinePos;
Tom Sepezfcc309e2017-03-24 14:19:11 -07001106 m_pLoader->m_lineHeights.push_back(fHeight);
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001107 }
1108 }
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001109
1110 m_pBreak->ClearBreakPieces();
Dan Sinclairc36fe072017-03-09 16:58:12 -05001111 if (dwStatus == CFX_BreakType::Paragraph) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001112 m_pBreak->Reset();
1113 if (!pStyle && bEndBreak) {
1114 CXFA_Para para = m_pTextProvider->GetParaNode();
1115 if (para) {
Dan Sinclair05df0752017-03-14 14:43:42 -04001116 float fStartPos = para.GetMarginLeft();
1117 float fIndent = para.GetTextIndent();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001118 if (fIndent > 0)
1119 fStartPos += fIndent;
1120
Dan Sinclair05df0752017-03-14 14:43:42 -04001121 float fSpaceBelow = para.GetSpaceBelow();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001122 if (fSpaceBelow < 0.1f)
1123 fSpaceBelow = 0;
1124
1125 m_pBreak->SetLineStartPos(fStartPos);
1126 fLinePos += fSpaceBelow;
1127 }
1128 }
1129 }
1130
1131 if (pStyle) {
Dan Sinclair05df0752017-03-14 14:43:42 -04001132 float fStart = 0;
Dan Sinclairb9fbe6e2017-01-16 16:07:41 -05001133 const FDE_CSSRect* pRect = pStyle->GetMarginWidth();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001134 if (pRect)
1135 fStart = pRect->left.GetValue();
1136
Dan Sinclair05df0752017-03-14 14:43:42 -04001137 float fTextIndent = pStyle->GetTextIndent().GetValue();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001138 if (fTextIndent < 0)
1139 fStart -= fTextIndent;
1140
1141 m_pBreak->SetLineStartPos(fStart);
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001142 }
1143 m_iLines++;
1144}
1145
1146void CXFA_TextLayout::RenderString(CFDE_RenderDevice* pDevice,
1147 CFDE_Brush* pBrush,
1148 CXFA_PieceLine* pPieceLine,
1149 int32_t iPiece,
1150 FXTEXT_CHARPOS* pCharPos,
1151 const CFX_Matrix& tmDoc2Device) {
tsepez783a7e02017-01-17 11:05:57 -08001152 const XFA_TextPiece* pPiece = pPieceLine->m_textPieces[iPiece].get();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001153 int32_t iCount = GetDisplayPos(pPiece, pCharPos);
1154 if (iCount > 0) {
1155 pBrush->SetColor(pPiece->dwColor);
1156 pDevice->DrawString(pBrush, pPiece->pFont, pCharPos, iCount,
1157 pPiece->fFontSize, &tmDoc2Device);
1158 }
Tom Sepezfcc309e2017-03-24 14:19:11 -07001159 pPieceLine->m_charCounts.push_back(iCount);
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001160}
1161
1162void CXFA_TextLayout::RenderPath(CFDE_RenderDevice* pDevice,
1163 CFDE_Pen* pPen,
1164 CXFA_PieceLine* pPieceLine,
1165 int32_t iPiece,
1166 FXTEXT_CHARPOS* pCharPos,
1167 const CFX_Matrix& tmDoc2Device) {
tsepez783a7e02017-01-17 11:05:57 -08001168 XFA_TextPiece* pPiece = pPieceLine->m_textPieces[iPiece].get();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001169 bool bNoUnderline = pPiece->iUnderline < 1 || pPiece->iUnderline > 2;
1170 bool bNoLineThrough = pPiece->iLineThrough < 1 || pPiece->iLineThrough > 2;
1171 if (bNoUnderline && bNoLineThrough)
1172 return;
1173
1174 pPen->SetColor(pPiece->dwColor);
Dan Sinclair0bb13332017-03-30 16:12:02 -04001175 auto pPath = pdfium::MakeUnique<CFDE_Path>();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001176 int32_t iChars = GetDisplayPos(pPiece, pCharPos);
1177 if (iChars > 0) {
1178 CFX_PointF pt1, pt2;
Dan Sinclair05df0752017-03-14 14:43:42 -04001179 float fEndY = pCharPos[0].m_Origin.y + 1.05f;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001180 if (pPiece->iPeriod == XFA_ATTRIBUTEENUM_Word) {
1181 for (int32_t i = 0; i < pPiece->iUnderline; i++) {
1182 for (int32_t j = 0; j < iChars; j++) {
Dan Sinclair2c02fae2017-02-16 13:42:11 -05001183 pt1.x = pCharPos[j].m_Origin.x;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001184 pt2.x =
1185 pt1.x + pCharPos[j].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
1186 pt1.y = pt2.y = fEndY;
1187 pPath->AddLine(pt1, pt2);
1188 }
1189 fEndY += 2.0f;
1190 }
1191 } else {
Dan Sinclair2c02fae2017-02-16 13:42:11 -05001192 pt1.x = pCharPos[0].m_Origin.x;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001193 pt2.x =
Dan Sinclair2c02fae2017-02-16 13:42:11 -05001194 pCharPos[iChars - 1].m_Origin.x +
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001195 pCharPos[iChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
1196 for (int32_t i = 0; i < pPiece->iUnderline; i++) {
1197 pt1.y = pt2.y = fEndY;
1198 pPath->AddLine(pt1, pt2);
1199 fEndY += 2.0f;
1200 }
1201 }
Dan Sinclair2c02fae2017-02-16 13:42:11 -05001202 fEndY = pCharPos[0].m_Origin.y - pPiece->rtPiece.height * 0.25f;
1203 pt1.x = pCharPos[0].m_Origin.x;
1204 pt2.x = pCharPos[iChars - 1].m_Origin.x +
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001205 pCharPos[iChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
1206 for (int32_t i = 0; i < pPiece->iLineThrough; i++) {
1207 pt1.y = pt2.y = fEndY;
1208 pPath->AddLine(pt1, pt2);
1209 fEndY += 2.0f;
1210 }
1211 } else {
1212 if (bNoLineThrough &&
1213 (bNoUnderline || pPiece->iPeriod != XFA_ATTRIBUTEENUM_All)) {
1214 return;
1215 }
1216 int32_t iCharsTmp = 0;
Tom Sepezfcc309e2017-03-24 14:19:11 -07001217 int32_t iPiecePrev = iPiece;
1218 int32_t iPieceNext = iPiece;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001219 while (iPiecePrev > 0) {
1220 iPiecePrev--;
Tom Sepezfcc309e2017-03-24 14:19:11 -07001221 iCharsTmp = pPieceLine->m_charCounts[iPiecePrev];
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001222 if (iCharsTmp > 0)
1223 break;
1224 }
1225 if (iCharsTmp == 0)
1226 return;
1227
1228 iCharsTmp = 0;
tsepez783a7e02017-01-17 11:05:57 -08001229 int32_t iPieces = pdfium::CollectionSize<int32_t>(pPieceLine->m_textPieces);
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001230 while (iPieceNext < iPieces - 1) {
1231 iPieceNext++;
Tom Sepezfcc309e2017-03-24 14:19:11 -07001232 iCharsTmp = pPieceLine->m_charCounts[iPieceNext];
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001233 if (iCharsTmp > 0)
1234 break;
1235 }
1236 if (iCharsTmp == 0)
1237 return;
1238
Dan Sinclair05df0752017-03-14 14:43:42 -04001239 float fOrgX = 0.0f;
1240 float fEndX = 0.0f;
tsepez783a7e02017-01-17 11:05:57 -08001241 pPiece = pPieceLine->m_textPieces[iPiecePrev].get();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001242 iChars = GetDisplayPos(pPiece, pCharPos);
1243 if (iChars < 1)
1244 return;
1245
Dan Sinclair2c02fae2017-02-16 13:42:11 -05001246 fOrgX = pCharPos[iChars - 1].m_Origin.x +
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001247 pCharPos[iChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
tsepez783a7e02017-01-17 11:05:57 -08001248 pPiece = pPieceLine->m_textPieces[iPieceNext].get();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001249 iChars = GetDisplayPos(pPiece, pCharPos);
1250 if (iChars < 1)
1251 return;
1252
Dan Sinclair2c02fae2017-02-16 13:42:11 -05001253 fEndX = pCharPos[0].m_Origin.x;
1254 CFX_PointF pt1;
1255 CFX_PointF pt2;
1256 pt1.x = fOrgX;
1257 pt2.x = fEndX;
Dan Sinclair05df0752017-03-14 14:43:42 -04001258 float fEndY = pCharPos[0].m_Origin.y + 1.05f;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001259 for (int32_t i = 0; i < pPiece->iUnderline; i++) {
Dan Sinclair2c02fae2017-02-16 13:42:11 -05001260 pt1.y = fEndY;
1261 pt2.y = fEndY;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001262 pPath->AddLine(pt1, pt2);
1263 fEndY += 2.0f;
1264 }
Dan Sinclair2c02fae2017-02-16 13:42:11 -05001265 fEndY = pCharPos[0].m_Origin.y - pPiece->rtPiece.height * 0.25f;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001266 for (int32_t i = 0; i < pPiece->iLineThrough; i++) {
Dan Sinclair2c02fae2017-02-16 13:42:11 -05001267 pt1.y = fEndY;
1268 pt2.y = fEndY;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001269 pPath->AddLine(pt1, pt2);
1270 fEndY += 2.0f;
1271 }
1272 }
1273 pDevice->DrawPath(pPen, 1, pPath.get(), &tmDoc2Device);
1274}
1275
1276int32_t CXFA_TextLayout::GetDisplayPos(const XFA_TextPiece* pPiece,
1277 FXTEXT_CHARPOS* pCharPos,
1278 bool bCharCode) {
1279 if (!pPiece)
1280 return 0;
1281
1282 FX_RTFTEXTOBJ tr;
tsepez783a7e02017-01-17 11:05:57 -08001283 if (!ToRun(pPiece, &tr))
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001284 return 0;
1285 return m_pBreak->GetDisplayPos(&tr, pCharPos, bCharCode);
1286}
1287
tsepez783a7e02017-01-17 11:05:57 -08001288bool CXFA_TextLayout::ToRun(const XFA_TextPiece* pPiece, FX_RTFTEXTOBJ* tr) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001289 int32_t iLength = pPiece->iChars;
1290 if (iLength < 1)
1291 return false;
1292
Dan Sinclairbef73892017-03-01 11:23:14 -05001293 tr->pStr = pPiece->szText;
tsepez783a7e02017-01-17 11:05:57 -08001294 tr->pFont = pPiece->pFont;
1295 tr->pRect = &pPiece->rtPiece;
Dan Sinclairbef73892017-03-01 11:23:14 -05001296 tr->pWidths = pPiece->Widths;
tsepez783a7e02017-01-17 11:05:57 -08001297 tr->iLength = iLength;
1298 tr->fFontSize = pPiece->fFontSize;
1299 tr->iBidiLevel = pPiece->iBidiLevel;
tsepez783a7e02017-01-17 11:05:57 -08001300 tr->wLineBreakChar = L'\n';
1301 tr->iVerticalScale = pPiece->iVerScale;
tsepez783a7e02017-01-17 11:05:57 -08001302 tr->iHorizontalScale = pPiece->iHorScale;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001303 return true;
1304}