blob: 038f451ad9e9469a4c3af99e3fdd072b1adefb0f [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
Dan Sinclair24ef6332017-07-24 10:52:57 -04007#include "xfa/fxfa/cxfa_textlayout.h"
Dan Sinclair1f5d4982017-01-10 16:37:32 -05008
9#include <algorithm>
tsepez783a7e02017-01-17 11:05:57 -080010#include <utility>
Dan Sinclair1f5d4982017-01-10 16:37:32 -050011
Dan Sinclair9f0e85a2017-08-08 13:23:24 -040012#include "core/fxcrt/css/cfx_csscomputedstyle.h"
13#include "core/fxcrt/css/cfx_cssstyleselector.h"
Dan Sinclair0d86ecb2017-04-19 09:19:57 -040014#include "core/fxcrt/xml/cfx_xmlelement.h"
15#include "core/fxcrt/xml/cfx_xmlnode.h"
16#include "core/fxcrt/xml/cfx_xmltext.h"
Dan Sinclair73b492a2017-08-14 17:23:25 -040017#include "core/fxge/cfx_graphstatedata.h"
Dan Sinclair7ffb59f2017-08-10 10:16:06 -040018#include "core/fxge/cfx_pathdata.h"
Dan Sinclair1f5d4982017-01-10 16:37:32 -050019#include "third_party/base/ptr_util.h"
20#include "third_party/base/stl_util.h"
Dan Sinclair73b492a2017-08-14 17:23:25 -040021#include "xfa/fde/cfde_textout.h"
Dan Sinclair24ef6332017-07-24 10:52:57 -040022#include "xfa/fxfa/cxfa_linkuserdata.h"
23#include "xfa/fxfa/cxfa_loadercontext.h"
24#include "xfa/fxfa/cxfa_pieceline.h"
25#include "xfa/fxfa/cxfa_textparsecontext.h"
26#include "xfa/fxfa/cxfa_textpiece.h"
27#include "xfa/fxfa/cxfa_textprovider.h"
28#include "xfa/fxfa/cxfa_texttabstopscontext.h"
29#include "xfa/fxfa/cxfa_textuserdata.h"
Dan Sinclair1f5d4982017-01-10 16:37:32 -050030#include "xfa/fxfa/parser/cxfa_font.h"
Dan Sinclairefcae5d2017-03-29 14:47:46 -040031#include "xfa/fxfa/parser/cxfa_node.h"
Dan Sinclair1f5d4982017-01-10 16:37:32 -050032#include "xfa/fxfa/parser/cxfa_para.h"
Dan Sinclair1f5d4982017-01-10 16:37:32 -050033
34#define XFA_LOADERCNTXTFLG_FILTERSPACE 0x001
35
36CXFA_TextLayout::CXFA_TextLayout(CXFA_TextProvider* pTextProvider)
37 : m_bHasBlock(false),
38 m_pTextProvider(pTextProvider),
39 m_pTextDataNode(nullptr),
40 m_bRichText(false),
41 m_iLines(0),
42 m_fMaxWidth(0),
43 m_bBlockContinue(true) {
44 ASSERT(m_pTextProvider);
45}
46
47CXFA_TextLayout::~CXFA_TextLayout() {
48 m_textParser.Reset();
49 Unload();
50}
51
52void CXFA_TextLayout::Unload() {
tsepez783a7e02017-01-17 11:05:57 -080053 m_pieceLines.clear();
Dan Sinclair1f5d4982017-01-10 16:37:32 -050054 m_pBreak.reset();
Dan Sinclair1f5d4982017-01-10 16:37:32 -050055}
56
Dan Sinclair1f5d4982017-01-10 16:37:32 -050057void CXFA_TextLayout::GetTextDataNode() {
58 if (!m_pTextProvider)
59 return;
60
61 CXFA_Node* pNode = m_pTextProvider->GetTextNode(m_bRichText);
62 if (pNode && m_bRichText)
63 m_textParser.Reset();
64
65 m_pTextDataNode = pNode;
66}
67
Dan Sinclair0d86ecb2017-04-19 09:19:57 -040068CFX_XMLNode* CXFA_TextLayout::GetXMLContainerNode() {
Dan Sinclair1f5d4982017-01-10 16:37:32 -050069 if (!m_bRichText)
70 return nullptr;
71
Dan Sinclair0d86ecb2017-04-19 09:19:57 -040072 CFX_XMLNode* pXMLRoot = m_pTextDataNode->GetXMLMappingNode();
Dan Sinclair1f5d4982017-01-10 16:37:32 -050073 if (!pXMLRoot)
74 return nullptr;
75
Dan Sinclair0d86ecb2017-04-19 09:19:57 -040076 CFX_XMLNode* pXMLContainer = nullptr;
77 for (CFX_XMLNode* pXMLChild = pXMLRoot->GetNodeItem(CFX_XMLNode::FirstChild);
Dan Sinclair1f5d4982017-01-10 16:37:32 -050078 pXMLChild;
Dan Sinclair0d86ecb2017-04-19 09:19:57 -040079 pXMLChild = pXMLChild->GetNodeItem(CFX_XMLNode::NextSibling)) {
80 if (pXMLChild->GetType() == FX_XMLNODE_Element) {
81 CFX_XMLElement* pXMLElement = static_cast<CFX_XMLElement*>(pXMLChild);
Ryan Harrison275e2602017-09-18 14:23:18 -040082 WideString wsTag = pXMLElement->GetLocalTagName();
dan sinclair65c7c232017-02-02 14:05:30 -080083 if (wsTag == L"body" || wsTag == L"html") {
Dan Sinclair1f5d4982017-01-10 16:37:32 -050084 pXMLContainer = pXMLChild;
85 break;
86 }
87 }
88 }
89 return pXMLContainer;
90}
91
Dan Sinclairb0d31602017-03-01 15:58:32 -050092std::unique_ptr<CFX_RTFBreak> CXFA_TextLayout::CreateBreak(bool bDefault) {
Dan Sinclaire533b932017-03-16 11:47:20 -040093 uint32_t dwStyle = FX_LAYOUTSTYLE_ExpandTab;
Dan Sinclair1f5d4982017-01-10 16:37:32 -050094 if (!bDefault)
Dan Sinclaire533b932017-03-16 11:47:20 -040095 dwStyle |= FX_LAYOUTSTYLE_Pagination;
Dan Sinclair1f5d4982017-01-10 16:37:32 -050096
Dan Sinclairb0d31602017-03-01 15:58:32 -050097 auto pBreak = pdfium::MakeUnique<CFX_RTFBreak>(dwStyle);
Dan Sinclair1f5d4982017-01-10 16:37:32 -050098 pBreak->SetLineBreakTolerance(1);
99 pBreak->SetFont(m_textParser.GetFont(m_pTextProvider, nullptr));
100 pBreak->SetFontSize(m_textParser.GetFontSize(m_pTextProvider, nullptr));
101 return pBreak;
102}
103
Dan Sinclair05df0752017-03-14 14:43:42 -0400104void CXFA_TextLayout::InitBreak(float fLineWidth) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500105 CXFA_Font font = m_pTextProvider->GetFontNode();
106 CXFA_Para para = m_pTextProvider->GetParaNode();
Dan Sinclair05df0752017-03-14 14:43:42 -0400107 float fStart = 0;
108 float fStartPos = 0;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500109 if (para) {
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500110 CFX_RTFLineAlignment iAlign = CFX_RTFLineAlignment::Left;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500111 switch (para.GetHorizontalAlign()) {
112 case XFA_ATTRIBUTEENUM_Center:
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500113 iAlign = CFX_RTFLineAlignment::Center;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500114 break;
115 case XFA_ATTRIBUTEENUM_Right:
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500116 iAlign = CFX_RTFLineAlignment::Right;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500117 break;
118 case XFA_ATTRIBUTEENUM_Justify:
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500119 iAlign = CFX_RTFLineAlignment::Justified;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500120 break;
121 case XFA_ATTRIBUTEENUM_JustifyAll:
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500122 iAlign = CFX_RTFLineAlignment::Distributed;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500123 break;
124 }
125 m_pBreak->SetAlignment(iAlign);
126
127 fStart = para.GetMarginLeft();
128 if (m_pTextProvider->IsCheckButtonAndAutoWidth()) {
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500129 if (iAlign != CFX_RTFLineAlignment::Left)
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500130 fLineWidth -= para.GetMarginRight();
131 } else {
132 fLineWidth -= para.GetMarginRight();
133 }
134 if (fLineWidth < 0)
135 fLineWidth = fStart;
136
137 fStartPos = fStart;
Dan Sinclair05df0752017-03-14 14:43:42 -0400138 float fIndent = para.GetTextIndent();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500139 if (fIndent > 0)
140 fStartPos += fIndent;
141 }
142
143 m_pBreak->SetLineBoundary(fStart, fLineWidth);
144 m_pBreak->SetLineStartPos(fStartPos);
145 if (font) {
146 m_pBreak->SetHorizontalScale((int32_t)font.GetHorizontalScale());
147 m_pBreak->SetVerticalScale((int32_t)font.GetVerticalScale());
148 m_pBreak->SetCharSpace(font.GetLetterSpacing());
149 }
150
Dan Sinclair05df0752017-03-14 14:43:42 -0400151 float fFontSize = m_textParser.GetFontSize(m_pTextProvider, nullptr);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500152 m_pBreak->SetFontSize(fFontSize);
153 m_pBreak->SetFont(m_textParser.GetFont(m_pTextProvider, nullptr));
154 m_pBreak->SetLineBreakTolerance(fFontSize * 0.2f);
155}
156
Dan Sinclair9f0e85a2017-08-08 13:23:24 -0400157void CXFA_TextLayout::InitBreak(CFX_CSSComputedStyle* pStyle,
158 CFX_CSSDisplay eDisplay,
Dan Sinclair05df0752017-03-14 14:43:42 -0400159 float fLineWidth,
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400160 CFX_XMLNode* pXMLNode,
Dan Sinclair9f0e85a2017-08-08 13:23:24 -0400161 CFX_CSSComputedStyle* pParentStyle) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500162 if (!pStyle) {
163 InitBreak(fLineWidth);
164 return;
165 }
166
Dan Sinclair9f0e85a2017-08-08 13:23:24 -0400167 if (eDisplay == CFX_CSSDisplay::Block ||
168 eDisplay == CFX_CSSDisplay::ListItem) {
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500169 CFX_RTFLineAlignment iAlign = CFX_RTFLineAlignment::Left;
Dan Sinclaircfb856c2017-01-16 16:03:44 -0500170 switch (pStyle->GetTextAlign()) {
Dan Sinclair9f0e85a2017-08-08 13:23:24 -0400171 case CFX_CSSTextAlign::Right:
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500172 iAlign = CFX_RTFLineAlignment::Right;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500173 break;
Dan Sinclair9f0e85a2017-08-08 13:23:24 -0400174 case CFX_CSSTextAlign::Center:
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500175 iAlign = CFX_RTFLineAlignment::Center;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500176 break;
Dan Sinclair9f0e85a2017-08-08 13:23:24 -0400177 case CFX_CSSTextAlign::Justify:
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500178 iAlign = CFX_RTFLineAlignment::Justified;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500179 break;
Dan Sinclair9f0e85a2017-08-08 13:23:24 -0400180 case CFX_CSSTextAlign::JustifyAll:
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500181 iAlign = CFX_RTFLineAlignment::Distributed;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500182 break;
183 default:
184 break;
185 }
186 m_pBreak->SetAlignment(iAlign);
Dan Sinclaird7de8e12017-02-28 10:37:00 -0500187
Dan Sinclair05df0752017-03-14 14:43:42 -0400188 float fStart = 0;
Dan Sinclair9f0e85a2017-08-08 13:23:24 -0400189 const CFX_CSSRect* pRect = pStyle->GetMarginWidth();
190 const CFX_CSSRect* pPaddingRect = pStyle->GetPaddingWidth();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500191 if (pRect) {
192 fStart = pRect->left.GetValue();
193 fLineWidth -= pRect->right.GetValue();
194 if (pPaddingRect) {
195 fStart += pPaddingRect->left.GetValue();
196 fLineWidth -= pPaddingRect->right.GetValue();
197 }
Dan Sinclair9f0e85a2017-08-08 13:23:24 -0400198 if (eDisplay == CFX_CSSDisplay::ListItem) {
199 const CFX_CSSRect* pParRect = pParentStyle->GetMarginWidth();
200 const CFX_CSSRect* pParPaddingRect = pParentStyle->GetPaddingWidth();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500201 if (pParRect) {
202 fStart += pParRect->left.GetValue();
203 fLineWidth -= pParRect->right.GetValue();
204 if (pParPaddingRect) {
205 fStart += pParPaddingRect->left.GetValue();
206 fLineWidth -= pParPaddingRect->right.GetValue();
207 }
208 }
Dan Sinclair9f0e85a2017-08-08 13:23:24 -0400209 CFX_CSSRect pNewRect;
210 pNewRect.left.Set(CFX_CSSLengthUnit::Point, fStart);
211 pNewRect.right.Set(CFX_CSSLengthUnit::Point, pRect->right.GetValue());
212 pNewRect.top.Set(CFX_CSSLengthUnit::Point, pRect->top.GetValue());
213 pNewRect.bottom.Set(CFX_CSSLengthUnit::Point, pRect->bottom.GetValue());
Dan Sinclaircfb856c2017-01-16 16:03:44 -0500214 pStyle->SetMarginWidth(pNewRect);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500215 }
216 }
217 m_pBreak->SetLineBoundary(fStart, fLineWidth);
Dan Sinclair05df0752017-03-14 14:43:42 -0400218 float fIndent = pStyle->GetTextIndent().GetValue();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500219 if (fIndent > 0)
220 fStart += fIndent;
221
222 m_pBreak->SetLineStartPos(fStart);
223 m_pBreak->SetTabWidth(m_textParser.GetTabInterval(pStyle));
224 if (!m_pTabstopContext)
225 m_pTabstopContext = pdfium::MakeUnique<CXFA_TextTabstopsContext>();
226 m_textParser.GetTabstops(pStyle, m_pTabstopContext.get());
Tom Sepez5c500ac2017-03-27 12:44:20 -0700227 for (const auto& stop : m_pTabstopContext->m_tabstops)
228 m_pBreak->AddPositionedTab(stop.fTabstops);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500229 }
Dan Sinclair05df0752017-03-14 14:43:42 -0400230 float fFontSize = m_textParser.GetFontSize(m_pTextProvider, pStyle);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500231 m_pBreak->SetFontSize(fFontSize);
232 m_pBreak->SetLineBreakTolerance(fFontSize * 0.2f);
233 m_pBreak->SetFont(m_textParser.GetFont(m_pTextProvider, pStyle));
234 m_pBreak->SetHorizontalScale(
235 m_textParser.GetHorScale(m_pTextProvider, pStyle, pXMLNode));
236 m_pBreak->SetVerticalScale(m_textParser.GetVerScale(m_pTextProvider, pStyle));
Dan Sinclaircfb856c2017-01-16 16:03:44 -0500237 m_pBreak->SetCharSpace(pStyle->GetLetterSpacing().GetValue());
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500238}
239
Ryan Harrison275e2602017-09-18 14:23:18 -0400240int32_t CXFA_TextLayout::GetText(WideString& wsText) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500241 GetTextDataNode();
242 wsText.clear();
243 if (!m_bRichText)
244 wsText = m_pTextDataNode->GetContent();
245 return wsText.GetLength();
246}
247
Dan Sinclair05df0752017-03-14 14:43:42 -0400248float CXFA_TextLayout::GetLayoutHeight() {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500249 if (!m_pLoader)
250 return 0;
251
Tom Sepezfcc309e2017-03-24 14:19:11 -0700252 if (m_pLoader->m_lineHeights.empty() && m_pLoader->m_fWidth > 0) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500253 CFX_SizeF szMax(m_pLoader->m_fWidth, m_pLoader->m_fHeight);
254 CFX_SizeF szDef;
255 m_pLoader->m_bSaveLineHeight = true;
256 m_pLoader->m_fLastPos = 0;
257 CalcSize(szMax, szMax, szDef);
258 m_pLoader->m_bSaveLineHeight = false;
dan sinclair071d7862017-02-07 20:46:32 -0500259 return szDef.height;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500260 }
261
Dan Sinclair05df0752017-03-14 14:43:42 -0400262 float fHeight = m_pLoader->m_fHeight;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500263 if (fHeight < 0.1f) {
264 fHeight = 0;
Tom Sepezfcc309e2017-03-24 14:19:11 -0700265 for (float value : m_pLoader->m_lineHeights)
266 fHeight += value;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500267 }
268 return fHeight;
269}
270
Dan Sinclair05df0752017-03-14 14:43:42 -0400271float CXFA_TextLayout::StartLayout(float fWidth) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500272 if (!m_pLoader)
273 m_pLoader = pdfium::MakeUnique<CXFA_LoaderContext>();
274
Dan Sinclair669a4182017-04-03 14:51:45 -0400275 if (fWidth < 0 ||
276 (m_pLoader->m_fWidth > -1 && fabs(fWidth - m_pLoader->m_fWidth) > 0)) {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700277 m_pLoader->m_lineHeights.clear();
278 m_Blocks.clear();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500279 Unload();
280 m_pLoader->m_fStartLineOffset = 0;
281 }
282 m_pLoader->m_fWidth = fWidth;
283
284 if (fWidth < 0) {
285 CFX_SizeF szMax;
286 CFX_SizeF szDef;
287 m_pLoader->m_bSaveLineHeight = true;
288 m_pLoader->m_fLastPos = 0;
289 CalcSize(szMax, szMax, szDef);
290 m_pLoader->m_bSaveLineHeight = false;
dan sinclair071d7862017-02-07 20:46:32 -0500291 fWidth = szDef.width;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500292 }
293 return fWidth;
294}
295
296bool CXFA_TextLayout::DoLayout(int32_t iBlockIndex,
Dan Sinclair05df0752017-03-14 14:43:42 -0400297 float& fCalcHeight,
298 float fContentAreaHeight,
299 float fTextHeight) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500300 if (!m_pLoader)
301 return false;
302
Tom Sepezfcc309e2017-03-24 14:19:11 -0700303 int32_t iBlockCount = pdfium::CollectionSize<int32_t>(m_Blocks);
Dan Sinclair05df0752017-03-14 14:43:42 -0400304 float fHeight = fTextHeight;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500305 if (fHeight < 0)
306 fHeight = GetLayoutHeight();
307
308 m_pLoader->m_fHeight = fHeight;
309 if (fContentAreaHeight < 0)
310 return false;
311
312 m_bHasBlock = true;
313 if (iBlockCount == 0 && fHeight > 0) {
314 fHeight = fTextHeight - GetLayoutHeight();
315 if (fHeight > 0) {
316 int32_t iAlign = m_textParser.GetVAlign(m_pTextProvider);
317 if (iAlign == XFA_ATTRIBUTEENUM_Middle)
318 fHeight /= 2.0f;
319 else if (iAlign != XFA_ATTRIBUTEENUM_Bottom)
320 fHeight = 0;
321 m_pLoader->m_fStartLineOffset = fHeight;
322 }
323 }
324
Dan Sinclair05df0752017-03-14 14:43:42 -0400325 float fLinePos = m_pLoader->m_fStartLineOffset;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500326 int32_t iLineIndex = 0;
327 if (iBlockCount > 1) {
328 if (iBlockCount >= (iBlockIndex + 1) * 2) {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700329 iLineIndex = m_Blocks[iBlockIndex * 2];
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500330 } else {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700331 iLineIndex = m_Blocks[iBlockCount - 1] + m_Blocks[iBlockCount - 2];
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500332 }
333 if (!m_pLoader->m_BlocksHeight.empty()) {
334 for (int32_t i = 0; i < iBlockIndex; i++)
335 fLinePos -= m_pLoader->m_BlocksHeight[i * 2 + 1];
336 }
337 }
338
Tom Sepezfcc309e2017-03-24 14:19:11 -0700339 int32_t iCount = pdfium::CollectionSize<int32_t>(m_pLoader->m_lineHeights);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500340 int32_t i = 0;
341 for (i = iLineIndex; i < iCount; i++) {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700342 float fLineHeight = m_pLoader->m_lineHeights[i];
343 if (i == iLineIndex && fLineHeight - fContentAreaHeight > 0.001) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500344 fCalcHeight = 0;
345 return true;
346 }
347 if (fLinePos + fLineHeight - fContentAreaHeight > 0.001) {
348 if (iBlockCount >= (iBlockIndex + 1) * 2) {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700349 m_Blocks[iBlockIndex * 2] = iLineIndex;
350 m_Blocks[iBlockIndex * 2 + 1] = i - iLineIndex;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500351 } else {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700352 m_Blocks.push_back(iLineIndex);
353 m_Blocks.push_back(i - iLineIndex);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500354 }
355 if (i == iLineIndex) {
356 if (fCalcHeight <= fLinePos) {
357 if (pdfium::CollectionSize<int32_t>(m_pLoader->m_BlocksHeight) >
358 iBlockIndex * 2 &&
359 (m_pLoader->m_BlocksHeight[iBlockIndex * 2] == iBlockIndex)) {
360 m_pLoader->m_BlocksHeight[iBlockIndex * 2 + 1] = fCalcHeight;
361 } else {
Dan Sinclair05df0752017-03-14 14:43:42 -0400362 m_pLoader->m_BlocksHeight.push_back((float)iBlockIndex);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500363 m_pLoader->m_BlocksHeight.push_back(fCalcHeight);
364 }
365 }
366 return true;
367 }
368
369 fCalcHeight = fLinePos;
370 return true;
371 }
372 fLinePos += fLineHeight;
373 }
374 return false;
375}
376
377int32_t CXFA_TextLayout::CountBlocks() const {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700378 int32_t iCount = pdfium::CollectionSize<int32_t>(m_Blocks) / 2;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500379 return iCount > 0 ? iCount : 1;
380}
381
382bool CXFA_TextLayout::CalcSize(const CFX_SizeF& minSize,
383 const CFX_SizeF& maxSize,
384 CFX_SizeF& defaultSize) {
dan sinclair071d7862017-02-07 20:46:32 -0500385 defaultSize.width = maxSize.width;
386 if (defaultSize.width < 1)
387 defaultSize.width = 0xFFFF;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500388
Dan Sinclairb0d31602017-03-01 15:58:32 -0500389 m_pBreak = CreateBreak(false);
Dan Sinclair05df0752017-03-14 14:43:42 -0400390 float fLinePos = 0;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500391 m_iLines = 0;
392 m_fMaxWidth = 0;
393 Loader(defaultSize, fLinePos, false);
394 if (fLinePos < 0.1f)
395 fLinePos = m_textParser.GetFontSize(m_pTextProvider, nullptr);
396
397 m_pTabstopContext.reset();
398 defaultSize = CFX_SizeF(m_fMaxWidth, fLinePos);
399 return true;
400}
401
Dan Sinclair05df0752017-03-14 14:43:42 -0400402bool CXFA_TextLayout::Layout(const CFX_SizeF& size, float* fHeight) {
dan sinclair071d7862017-02-07 20:46:32 -0500403 if (size.width < 1)
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500404 return false;
405
406 Unload();
Dan Sinclairb0d31602017-03-01 15:58:32 -0500407 m_pBreak = CreateBreak(true);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500408 if (m_pLoader) {
409 m_pLoader->m_iTotalLines = -1;
410 m_pLoader->m_iChar = 0;
411 }
412
413 m_iLines = 0;
Dan Sinclair05df0752017-03-14 14:43:42 -0400414 float fLinePos = 0;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500415 Loader(size, fLinePos, true);
dan sinclair071d7862017-02-07 20:46:32 -0500416 UpdateAlign(size.height, fLinePos);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500417 m_pTabstopContext.reset();
418 if (fHeight)
419 *fHeight = fLinePos;
420 return true;
421}
422
423bool CXFA_TextLayout::Layout(int32_t iBlock) {
424 if (!m_pLoader || iBlock < 0 || iBlock >= CountBlocks())
425 return false;
426 if (m_pLoader->m_fWidth < 1)
427 return false;
428
429 m_pLoader->m_iTotalLines = -1;
430 m_iLines = 0;
Dan Sinclair05df0752017-03-14 14:43:42 -0400431 float fLinePos = 0;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500432 CXFA_Node* pNode = nullptr;
433 CFX_SizeF szText(m_pLoader->m_fWidth, m_pLoader->m_fHeight);
Tom Sepezfcc309e2017-03-24 14:19:11 -0700434 int32_t iCount = pdfium::CollectionSize<int32_t>(m_Blocks);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500435 int32_t iBlocksHeightCount =
436 pdfium::CollectionSize<int32_t>(m_pLoader->m_BlocksHeight);
437 iBlocksHeightCount /= 2;
438 if (iBlock < iBlocksHeightCount)
439 return true;
440 if (iBlock == iBlocksHeightCount) {
441 Unload();
Dan Sinclairb0d31602017-03-01 15:58:32 -0500442 m_pBreak = CreateBreak(true);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500443 fLinePos = m_pLoader->m_fStartLineOffset;
444 for (int32_t i = 0; i < iBlocksHeightCount; i++)
445 fLinePos -= m_pLoader->m_BlocksHeight[i * 2 + 1];
446
447 m_pLoader->m_iChar = 0;
448 if (iCount > 1)
Tom Sepezfcc309e2017-03-24 14:19:11 -0700449 m_pLoader->m_iTotalLines = m_Blocks[iBlock * 2 + 1];
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500450
451 Loader(szText, fLinePos, true);
452 if (iCount == 0 && m_pLoader->m_fStartLineOffset < 0.1f)
dan sinclair071d7862017-02-07 20:46:32 -0500453 UpdateAlign(szText.height, fLinePos);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500454 } else if (m_pTextDataNode) {
455 iBlock *= 2;
456 if (iBlock < iCount - 2)
Tom Sepezfcc309e2017-03-24 14:19:11 -0700457 m_pLoader->m_iTotalLines = m_Blocks[iBlock + 1];
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500458
459 m_pBreak->Reset();
460 if (m_bRichText) {
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400461 CFX_XMLNode* pContainerNode = GetXMLContainerNode();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500462 if (!pContainerNode)
463 return true;
464
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400465 CFX_XMLNode* pXMLNode = m_pLoader->m_pXMLNode;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500466 if (!pXMLNode)
467 return true;
468
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400469 CFX_XMLNode* pSaveXMLNode = m_pLoader->m_pXMLNode;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500470 for (; pXMLNode;
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400471 pXMLNode = pXMLNode->GetNodeItem(CFX_XMLNode::NextSibling)) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500472 if (!LoadRichText(pXMLNode, szText, fLinePos, m_pLoader->m_pParentStyle,
Tom Sepez03de8842017-01-24 14:24:36 -0800473 true, nullptr)) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500474 break;
475 }
476 }
477 while (!pXMLNode) {
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400478 pXMLNode = pSaveXMLNode->GetNodeItem(CFX_XMLNode::Parent);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500479 if (pXMLNode == pContainerNode)
480 break;
481 if (!LoadRichText(pXMLNode, szText, fLinePos, m_pLoader->m_pParentStyle,
482 true, nullptr, false)) {
483 break;
484 }
485 pSaveXMLNode = pXMLNode;
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400486 pXMLNode = pXMLNode->GetNodeItem(CFX_XMLNode::NextSibling);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500487 if (!pXMLNode)
488 continue;
489 for (; pXMLNode;
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400490 pXMLNode = pXMLNode->GetNodeItem(CFX_XMLNode::NextSibling)) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500491 if (!LoadRichText(pXMLNode, szText, fLinePos,
Tom Sepez03de8842017-01-24 14:24:36 -0800492 m_pLoader->m_pParentStyle, true, nullptr)) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500493 break;
494 }
495 }
496 }
497 } else {
498 pNode = m_pLoader->m_pNode;
499 if (!pNode)
500 return true;
501 LoadText(pNode, szText, fLinePos, true);
502 }
503 }
504 if (iBlock == iCount) {
505 m_pTabstopContext.reset();
506 m_pLoader.reset();
507 }
508 return true;
509}
510
511void CXFA_TextLayout::ItemBlocks(const CFX_RectF& rtText, int32_t iBlockIndex) {
512 if (!m_pLoader)
513 return;
514
Tom Sepezfcc309e2017-03-24 14:19:11 -0700515 int32_t iCountHeight =
516 pdfium::CollectionSize<int32_t>(m_pLoader->m_lineHeights);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500517 if (iCountHeight == 0)
518 return;
519
520 bool bEndItem = true;
Tom Sepezfcc309e2017-03-24 14:19:11 -0700521 int32_t iBlockCount = pdfium::CollectionSize<int32_t>(m_Blocks);
Dan Sinclair05df0752017-03-14 14:43:42 -0400522 float fLinePos = m_pLoader->m_fStartLineOffset;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500523 int32_t iLineIndex = 0;
524 if (iBlockIndex > 0) {
525 int32_t iBlockHeightCount =
526 pdfium::CollectionSize<int32_t>(m_pLoader->m_BlocksHeight);
527 iBlockHeightCount /= 2;
528 if (iBlockHeightCount >= iBlockIndex) {
529 for (int32_t i = 0; i < iBlockIndex; i++)
530 fLinePos -= m_pLoader->m_BlocksHeight[i * 2 + 1];
531 } else {
532 fLinePos = 0;
533 }
534 iLineIndex = m_Blocks[iBlockCount - 1] + m_Blocks[iBlockCount - 2];
535 }
536
537 int32_t i = 0;
538 for (i = iLineIndex; i < iCountHeight; i++) {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700539 float fLineHeight = m_pLoader->m_lineHeights[i];
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500540 if (fLinePos + fLineHeight - rtText.height > 0.001) {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700541 m_Blocks.push_back(iLineIndex);
542 m_Blocks.push_back(i - iLineIndex);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500543 bEndItem = false;
544 break;
545 }
546 fLinePos += fLineHeight;
547 }
548 if (iCountHeight > 0 && (i - iLineIndex) > 0 && bEndItem) {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700549 m_Blocks.push_back(iLineIndex);
550 m_Blocks.push_back(i - iLineIndex);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500551 }
552}
553
554bool CXFA_TextLayout::DrawString(CFX_RenderDevice* pFxDevice,
555 const CFX_Matrix& tmDoc2Device,
556 const CFX_RectF& rtClip,
557 int32_t iBlock) {
558 if (!pFxDevice)
559 return false;
560
Dan Sinclair73b492a2017-08-14 17:23:25 -0400561 pFxDevice->SaveState();
562 pFxDevice->SetClip_Rect(rtClip);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500563
tsepez783a7e02017-01-17 11:05:57 -0800564 if (m_pieceLines.empty()) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500565 int32_t iBlockCount = CountBlocks();
566 for (int32_t i = 0; i < iBlockCount; i++)
567 Layout(i);
568 }
569
570 FXTEXT_CHARPOS* pCharPos = nullptr;
571 int32_t iCharCount = 0;
572 int32_t iLineStart = 0;
tsepez783a7e02017-01-17 11:05:57 -0800573 int32_t iPieceLines = pdfium::CollectionSize<int32_t>(m_pieceLines);
Tom Sepezfcc309e2017-03-24 14:19:11 -0700574 int32_t iCount = pdfium::CollectionSize<int32_t>(m_Blocks);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500575 if (iCount > 0) {
576 iBlock *= 2;
577 if (iBlock < iCount) {
Tom Sepezfcc309e2017-03-24 14:19:11 -0700578 iLineStart = m_Blocks[iBlock];
579 iPieceLines = m_Blocks[iBlock + 1];
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500580 } else {
581 iPieceLines = 0;
582 }
583 }
584
585 for (int32_t i = 0; i < iPieceLines; i++) {
tsepez783a7e02017-01-17 11:05:57 -0800586 if (i + iLineStart >= pdfium::CollectionSize<int32_t>(m_pieceLines))
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500587 break;
588
tsepez783a7e02017-01-17 11:05:57 -0800589 CXFA_PieceLine* pPieceLine = m_pieceLines[i + iLineStart].get();
590 int32_t iPieces = pdfium::CollectionSize<int32_t>(pPieceLine->m_textPieces);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500591 int32_t j = 0;
592 for (j = 0; j < iPieces; j++) {
Dan Sinclair2eddb662017-05-25 16:49:51 -0400593 const CXFA_TextPiece* pPiece = pPieceLine->m_textPieces[j].get();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500594 int32_t iChars = pPiece->iChars;
595 if (iCharCount < iChars) {
596 FX_Free(pCharPos);
597 pCharPos = FX_Alloc(FXTEXT_CHARPOS, iChars);
598 iCharCount = iChars;
599 }
Dan Sinclair1c5d0b42017-04-03 15:05:11 -0400600 memset(pCharPos, 0, iCharCount * sizeof(FXTEXT_CHARPOS));
Dan Sinclair73b492a2017-08-14 17:23:25 -0400601 RenderString(pFxDevice, pPieceLine, j, pCharPos, tmDoc2Device);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500602 }
Dan Sinclair73b492a2017-08-14 17:23:25 -0400603 for (j = 0; j < iPieces; j++)
604 RenderPath(pFxDevice, pPieceLine, j, pCharPos, tmDoc2Device);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500605 }
Dan Sinclair73b492a2017-08-14 17:23:25 -0400606 pFxDevice->RestoreState(false);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500607 FX_Free(pCharPos);
608 return iPieceLines > 0;
609}
610
Dan Sinclair05df0752017-03-14 14:43:42 -0400611void CXFA_TextLayout::UpdateAlign(float fHeight, float fBottom) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500612 fHeight -= fBottom;
613 if (fHeight < 0.1f)
614 return;
615
616 switch (m_textParser.GetVAlign(m_pTextProvider)) {
617 case XFA_ATTRIBUTEENUM_Middle:
618 fHeight /= 2.0f;
619 break;
620 case XFA_ATTRIBUTEENUM_Bottom:
621 break;
622 default:
623 return;
624 }
625
tsepez783a7e02017-01-17 11:05:57 -0800626 for (const auto& pPieceLine : m_pieceLines) {
627 for (const auto& pPiece : pPieceLine->m_textPieces)
628 pPiece->rtPiece.top += fHeight;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500629 }
630}
631
632bool CXFA_TextLayout::Loader(const CFX_SizeF& szText,
Dan Sinclair05df0752017-03-14 14:43:42 -0400633 float& fLinePos,
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500634 bool bSavePieces) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500635 GetTextDataNode();
636 if (!m_pTextDataNode)
637 return true;
638
639 if (m_bRichText) {
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400640 CFX_XMLNode* pXMLContainer = GetXMLContainerNode();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500641 if (pXMLContainer) {
642 if (!m_textParser.IsParsed())
643 m_textParser.DoParse(pXMLContainer, m_pTextProvider);
644
Dan Sinclair7e5fdd02017-01-23 16:24:26 -0500645 auto pRootStyle = m_textParser.CreateRootStyle(m_pTextProvider);
Tom Sepez03de8842017-01-24 14:24:36 -0800646 LoadRichText(pXMLContainer, szText, fLinePos, pRootStyle, bSavePieces,
647 nullptr);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500648 }
649 } else {
650 LoadText(m_pTextDataNode, szText, fLinePos, bSavePieces);
651 }
652 return true;
653}
654
655void CXFA_TextLayout::LoadText(CXFA_Node* pNode,
656 const CFX_SizeF& szText,
Dan Sinclair05df0752017-03-14 14:43:42 -0400657 float& fLinePos,
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500658 bool bSavePieces) {
dan sinclair071d7862017-02-07 20:46:32 -0500659 InitBreak(szText.width);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500660
661 CXFA_Para para = m_pTextProvider->GetParaNode();
Dan Sinclair05df0752017-03-14 14:43:42 -0400662 float fSpaceAbove = 0;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500663 if (para) {
664 fSpaceAbove = para.GetSpaceAbove();
665 if (fSpaceAbove < 0.1f) {
666 fSpaceAbove = 0;
667 }
668 int32_t verAlign = para.GetVerticalAlign();
669 switch (verAlign) {
670 case XFA_ATTRIBUTEENUM_Top:
671 case XFA_ATTRIBUTEENUM_Middle:
672 case XFA_ATTRIBUTEENUM_Bottom: {
673 fLinePos += fSpaceAbove;
674 break;
675 }
676 }
677 }
678
Ryan Harrison275e2602017-09-18 14:23:18 -0400679 WideString wsText = pNode->GetContent();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500680 wsText.TrimRight(L" ");
681 bool bRet = AppendChar(wsText, fLinePos, fSpaceAbove, bSavePieces);
682 if (bRet && m_pLoader)
683 m_pLoader->m_pNode = pNode;
684 else
Dan Sinclairc36fe072017-03-09 16:58:12 -0500685 EndBreak(CFX_BreakType::Paragraph, fLinePos, bSavePieces);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500686}
687
Dan Sinclair7e5fdd02017-01-23 16:24:26 -0500688bool CXFA_TextLayout::LoadRichText(
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400689 CFX_XMLNode* pXMLNode,
Dan Sinclair7e5fdd02017-01-23 16:24:26 -0500690 const CFX_SizeF& szText,
Dan Sinclair05df0752017-03-14 14:43:42 -0400691 float& fLinePos,
Dan Sinclair0b950422017-09-21 15:49:49 -0400692 const RetainPtr<CFX_CSSComputedStyle>& pParentStyle,
Dan Sinclair7e5fdd02017-01-23 16:24:26 -0500693 bool bSavePieces,
Dan Sinclair0b950422017-09-21 15:49:49 -0400694 RetainPtr<CXFA_LinkUserData> pLinkData,
Dan Sinclair7e5fdd02017-01-23 16:24:26 -0500695 bool bEndBreak,
696 bool bIsOl,
697 int32_t iLiCount) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500698 if (!pXMLNode)
699 return false;
700
701 CXFA_TextParseContext* pContext =
702 m_textParser.GetParseContextFromMap(pXMLNode);
Dan Sinclair9f0e85a2017-08-08 13:23:24 -0400703 CFX_CSSDisplay eDisplay = CFX_CSSDisplay::None;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500704 bool bContentNode = false;
Dan Sinclair05df0752017-03-14 14:43:42 -0400705 float fSpaceBelow = 0;
Dan Sinclair0b950422017-09-21 15:49:49 -0400706 RetainPtr<CFX_CSSComputedStyle> pStyle;
Ryan Harrison275e2602017-09-18 14:23:18 -0400707 WideString wsName;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500708 if (bEndBreak) {
709 bool bCurOl = false;
710 bool bCurLi = false;
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400711 CFX_XMLElement* pElement = nullptr;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500712 if (pContext) {
713 if (m_bBlockContinue ||
714 (m_pLoader && pXMLNode == m_pLoader->m_pXMLNode)) {
715 m_bBlockContinue = true;
716 }
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400717 if (pXMLNode->GetType() == FX_XMLNODE_Text) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500718 bContentNode = true;
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400719 } else if (pXMLNode->GetType() == FX_XMLNODE_Element) {
720 pElement = static_cast<CFX_XMLElement*>(pXMLNode);
Dan Sinclair5fa4e982017-04-05 11:48:21 -0400721 wsName = pElement->GetLocalTagName();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500722 }
dan sinclair65c7c232017-02-02 14:05:30 -0800723 if (wsName == L"ol") {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500724 bIsOl = true;
725 bCurOl = true;
726 }
727 if (m_bBlockContinue || bContentNode == false) {
728 eDisplay = pContext->GetDisplay();
Dan Sinclair9f0e85a2017-08-08 13:23:24 -0400729 if (eDisplay != CFX_CSSDisplay::Block &&
730 eDisplay != CFX_CSSDisplay::Inline &&
731 eDisplay != CFX_CSSDisplay::ListItem) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500732 return true;
733 }
734
Dan Sinclair7e5fdd02017-01-23 16:24:26 -0500735 pStyle = m_textParser.ComputeStyle(pXMLNode, pParentStyle.Get());
736 InitBreak(bContentNode ? pParentStyle.Get() : pStyle.Get(), eDisplay,
dan sinclair071d7862017-02-07 20:46:32 -0500737 szText.width, pXMLNode, pParentStyle.Get());
Dan Sinclair9f0e85a2017-08-08 13:23:24 -0400738 if ((eDisplay == CFX_CSSDisplay::Block ||
739 eDisplay == CFX_CSSDisplay::ListItem) &&
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500740 pStyle &&
dan sinclair65c7c232017-02-02 14:05:30 -0800741 (wsName.IsEmpty() || (wsName != L"body" && wsName != L"html" &&
742 wsName != L"ol" && wsName != L"ul"))) {
Dan Sinclair9f0e85a2017-08-08 13:23:24 -0400743 const CFX_CSSRect* pRect = pStyle->GetMarginWidth();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500744 if (pRect) {
745 fLinePos += pRect->top.GetValue();
746 fSpaceBelow = pRect->bottom.GetValue();
747 }
748 }
749
dan sinclair65c7c232017-02-02 14:05:30 -0800750 if (wsName == L"a") {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500751 ASSERT(pElement);
Ryan Harrison275e2602017-09-18 14:23:18 -0400752 WideString wsLinkContent = pElement->GetString(L"href");
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500753 if (!wsLinkContent.IsEmpty()) {
Tom Sepez03de8842017-01-24 14:24:36 -0800754 pLinkData = pdfium::MakeRetain<CXFA_LinkUserData>(
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500755 wsLinkContent.GetBuffer(wsLinkContent.GetLength()));
756 wsLinkContent.ReleaseBuffer(wsLinkContent.GetLength());
757 }
758 }
759
Dan Sinclair7e5fdd02017-01-23 16:24:26 -0500760 int32_t iTabCount = m_textParser.CountTabs(
761 bContentNode ? pParentStyle.Get() : pStyle.Get());
762 bool bSpaceRun = m_textParser.IsSpaceRun(
763 bContentNode ? pParentStyle.Get() : pStyle.Get());
Ryan Harrison275e2602017-09-18 14:23:18 -0400764 WideString wsText;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500765 if (bContentNode && iTabCount == 0) {
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400766 wsText = static_cast<CFX_XMLText*>(pXMLNode)->GetText();
dan sinclair65c7c232017-02-02 14:05:30 -0800767 } else if (wsName == L"br") {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500768 wsText = L'\n';
dan sinclair65c7c232017-02-02 14:05:30 -0800769 } else if (wsName == L"li") {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500770 bCurLi = true;
771 if (bIsOl)
772 wsText.Format(L"%d. ", iLiCount);
773 else
Ryan Harrison275e2602017-09-18 14:23:18 -0400774 wsText = 0x00B7 + WideStringView(L" ", 1);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500775 } else if (!bContentNode) {
776 if (iTabCount > 0) {
777 while (iTabCount-- > 0)
778 wsText += L'\t';
779 } else {
780 m_textParser.GetEmbbedObj(m_pTextProvider, pXMLNode, wsText);
781 }
782 }
783
784 int32_t iLength = wsText.GetLength();
785 if (iLength > 0 && bContentNode && !bSpaceRun)
786 ProcessText(wsText);
787
788 if (m_pLoader) {
789 if (wsText.GetLength() > 0 &&
790 (m_pLoader->m_dwFlags & XFA_LOADERCNTXTFLG_FILTERSPACE)) {
791 wsText.TrimLeft(0x20);
792 }
Dan Sinclair9f0e85a2017-08-08 13:23:24 -0400793 if (CFX_CSSDisplay::Block == eDisplay) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500794 m_pLoader->m_dwFlags |= XFA_LOADERCNTXTFLG_FILTERSPACE;
Dan Sinclair9f0e85a2017-08-08 13:23:24 -0400795 } else if (CFX_CSSDisplay::Inline == eDisplay &&
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500796 (m_pLoader->m_dwFlags & XFA_LOADERCNTXTFLG_FILTERSPACE)) {
797 m_pLoader->m_dwFlags &= ~XFA_LOADERCNTXTFLG_FILTERSPACE;
798 } else if (wsText.GetLength() > 0 &&
Ryan Harrison8a1758b2017-08-15 10:37:59 -0400799 (0x20 == wsText[wsText.GetLength() - 1])) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500800 m_pLoader->m_dwFlags |= XFA_LOADERCNTXTFLG_FILTERSPACE;
801 } else if (wsText.GetLength() != 0) {
802 m_pLoader->m_dwFlags &= ~XFA_LOADERCNTXTFLG_FILTERSPACE;
803 }
804 }
805
806 if (wsText.GetLength() > 0) {
807 if (!m_pLoader || m_pLoader->m_iChar == 0) {
Tom Sepez03de8842017-01-24 14:24:36 -0800808 auto pUserData = pdfium::MakeRetain<CXFA_TextUserData>(
Dan Sinclair0cb9b8c2017-01-10 16:38:10 -0500809 bContentNode ? pParentStyle : pStyle, pLinkData);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500810 m_pBreak->SetUserData(pUserData);
811 }
812
813 if (AppendChar(wsText, fLinePos, 0, bSavePieces)) {
814 if (m_pLoader)
815 m_pLoader->m_dwFlags &= ~XFA_LOADERCNTXTFLG_FILTERSPACE;
816 if (IsEnd(bSavePieces)) {
817 if (m_pLoader && m_pLoader->m_iTotalLines > -1) {
818 m_pLoader->m_pXMLNode = pXMLNode;
819 m_pLoader->m_pParentStyle = pParentStyle;
820 }
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500821 return false;
822 }
823 return true;
824 }
825 }
826 }
827 }
828
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400829 for (CFX_XMLNode* pChildNode =
830 pXMLNode->GetNodeItem(CFX_XMLNode::FirstChild);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500831 pChildNode;
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400832 pChildNode = pChildNode->GetNodeItem(CFX_XMLNode::NextSibling)) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500833 if (bCurOl)
834 iLiCount++;
835
836 if (!LoadRichText(pChildNode, szText, fLinePos,
837 pContext ? pStyle : pParentStyle, bSavePieces,
838 pLinkData, true, bIsOl, iLiCount))
839 return false;
840 }
841
842 if (m_pLoader) {
Dan Sinclair9f0e85a2017-08-08 13:23:24 -0400843 if (CFX_CSSDisplay::Block == eDisplay)
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500844 m_pLoader->m_dwFlags |= XFA_LOADERCNTXTFLG_FILTERSPACE;
845 }
846 if (bCurLi)
Dan Sinclairc36fe072017-03-09 16:58:12 -0500847 EndBreak(CFX_BreakType::Line, fLinePos, bSavePieces);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500848 } else {
849 if (pContext)
850 eDisplay = pContext->GetDisplay();
851 }
852
853 if (m_bBlockContinue) {
854 if (pContext && !bContentNode) {
Dan Sinclair9f0e85a2017-08-08 13:23:24 -0400855 CFX_BreakType dwStatus = (eDisplay == CFX_CSSDisplay::Block)
Dan Sinclairc36fe072017-03-09 16:58:12 -0500856 ? CFX_BreakType::Paragraph
857 : CFX_BreakType::Piece;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500858 EndBreak(dwStatus, fLinePos, bSavePieces);
Dan Sinclair9f0e85a2017-08-08 13:23:24 -0400859 if (eDisplay == CFX_CSSDisplay::Block) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500860 fLinePos += fSpaceBelow;
861 if (m_pTabstopContext)
862 m_pTabstopContext->RemoveAll();
863 }
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500864 if (IsEnd(bSavePieces)) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500865 if (m_pLoader && m_pLoader->m_iTotalLines > -1) {
866 m_pLoader->m_pXMLNode =
Dan Sinclair0d86ecb2017-04-19 09:19:57 -0400867 pXMLNode->GetNodeItem(CFX_XMLNode::NextSibling);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500868 m_pLoader->m_pParentStyle = pParentStyle;
869 }
870 return false;
871 }
872 }
873 }
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500874 return true;
875}
876
Ryan Harrison275e2602017-09-18 14:23:18 -0400877bool CXFA_TextLayout::AppendChar(const WideString& wsText,
Dan Sinclair05df0752017-03-14 14:43:42 -0400878 float& fLinePos,
879 float fSpaceAbove,
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500880 bool bSavePieces) {
Dan Sinclairc36fe072017-03-09 16:58:12 -0500881 CFX_BreakType dwStatus = CFX_BreakType::None;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500882 int32_t iChar = 0;
883 if (m_pLoader)
884 iChar = m_pLoader->m_iChar;
885
886 int32_t iLength = wsText.GetLength();
887 for (int32_t i = iChar; i < iLength; i++) {
Ryan Harrison8a1758b2017-08-15 10:37:59 -0400888 wchar_t wch = wsText[i];
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500889 if (wch == 0xA0)
890 wch = 0x20;
891
Dan Sinclaird2ee0f32017-02-28 14:46:18 -0500892 dwStatus = m_pBreak->AppendChar(wch);
Dan Sinclairc36fe072017-03-09 16:58:12 -0500893 if (dwStatus != CFX_BreakType::None && dwStatus != CFX_BreakType::Piece) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500894 AppendTextLine(dwStatus, fLinePos, bSavePieces);
895 if (IsEnd(bSavePieces)) {
896 if (m_pLoader)
897 m_pLoader->m_iChar = i;
898 return true;
899 }
Dan Sinclairc36fe072017-03-09 16:58:12 -0500900 if (dwStatus == CFX_BreakType::Paragraph && m_bRichText)
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500901 fLinePos += fSpaceAbove;
902 }
903 }
904 if (m_pLoader)
905 m_pLoader->m_iChar = 0;
906
907 return false;
908}
909
910bool CXFA_TextLayout::IsEnd(bool bSavePieces) {
911 if (!bSavePieces)
912 return false;
913 if (m_pLoader && m_pLoader->m_iTotalLines > 0)
914 return m_iLines >= m_pLoader->m_iTotalLines;
915 return false;
916}
917
Ryan Harrison275e2602017-09-18 14:23:18 -0400918void CXFA_TextLayout::ProcessText(WideString& wsText) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500919 int32_t iLen = wsText.GetLength();
920 if (iLen == 0)
921 return;
922
Dan Sinclair812e96c2017-03-13 16:43:37 -0400923 wchar_t* psz = wsText.GetBuffer(iLen);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500924 int32_t iTrimLeft = 0;
Dan Sinclair812e96c2017-03-13 16:43:37 -0400925 wchar_t wch = 0, wPrev = 0;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500926 for (int32_t i = 0; i < iLen; i++) {
927 wch = psz[i];
928 if (wch < 0x20)
929 wch = 0x20;
930 if (wch == 0x20 && wPrev == 0x20)
931 continue;
932
933 wPrev = wch;
934 psz[iTrimLeft++] = wch;
935 }
936 wsText.ReleaseBuffer(iLen);
937 wsText = wsText.Left(iTrimLeft);
938}
939
Dan Sinclairc36fe072017-03-09 16:58:12 -0500940void CXFA_TextLayout::EndBreak(CFX_BreakType dwStatus,
Dan Sinclair05df0752017-03-14 14:43:42 -0400941 float& fLinePos,
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500942 bool bSavePieces) {
943 dwStatus = m_pBreak->EndBreak(dwStatus);
Dan Sinclairc36fe072017-03-09 16:58:12 -0500944 if (dwStatus != CFX_BreakType::None && dwStatus != CFX_BreakType::Piece)
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500945 AppendTextLine(dwStatus, fLinePos, bSavePieces, true);
946}
947
Dan Sinclair9f0e85a2017-08-08 13:23:24 -0400948void CXFA_TextLayout::DoTabstops(CFX_CSSComputedStyle* pStyle,
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500949 CXFA_PieceLine* pPieceLine) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500950 if (!pStyle || !pPieceLine)
951 return;
952
Tom Sepez5c500ac2017-03-27 12:44:20 -0700953 if (!m_pTabstopContext || m_pTabstopContext->m_tabstops.empty())
954 return;
955
tsepez783a7e02017-01-17 11:05:57 -0800956 int32_t iPieces = pdfium::CollectionSize<int32_t>(pPieceLine->m_textPieces);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500957 if (iPieces == 0)
958 return;
959
Dan Sinclair2eddb662017-05-25 16:49:51 -0400960 CXFA_TextPiece* pPiece = pPieceLine->m_textPieces[iPieces - 1].get();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500961 int32_t& iTabstopsIndex = m_pTabstopContext->m_iTabIndex;
962 int32_t iCount = m_textParser.CountTabs(pStyle);
Tom Sepez5c500ac2017-03-27 12:44:20 -0700963 if (!pdfium::IndexInBounds(m_pTabstopContext->m_tabstops, iTabstopsIndex))
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500964 return;
965
966 if (iCount > 0) {
967 iTabstopsIndex++;
968 m_pTabstopContext->m_bTabstops = true;
Dan Sinclair05df0752017-03-14 14:43:42 -0400969 float fRight = 0;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500970 if (iPieces > 1) {
Dan Sinclair2eddb662017-05-25 16:49:51 -0400971 CXFA_TextPiece* p = pPieceLine->m_textPieces[iPieces - 2].get();
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500972 fRight = p->rtPiece.right();
973 }
974 m_pTabstopContext->m_fTabWidth =
975 pPiece->rtPiece.width + pPiece->rtPiece.left - fRight;
976 } else if (iTabstopsIndex > -1) {
Dan Sinclair05df0752017-03-14 14:43:42 -0400977 float fLeft = 0;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500978 if (m_pTabstopContext->m_bTabstops) {
Tom Sepez5c500ac2017-03-27 12:44:20 -0700979 uint32_t dwAlign = m_pTabstopContext->m_tabstops[iTabstopsIndex].dwAlign;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500980 if (dwAlign == FX_HashCode_GetW(L"center", false)) {
981 fLeft = pPiece->rtPiece.width / 2.0f;
982 } else if (dwAlign == FX_HashCode_GetW(L"right", false) ||
983 dwAlign == FX_HashCode_GetW(L"before", false)) {
984 fLeft = pPiece->rtPiece.width;
985 } else if (dwAlign == FX_HashCode_GetW(L"decimal", false)) {
986 int32_t iChars = pPiece->iChars;
987 for (int32_t i = 0; i < iChars; i++) {
Dan Sinclairbef73892017-03-01 11:23:14 -0500988 if (pPiece->szText[i] == L'.')
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500989 break;
990
Dan Sinclairbef73892017-03-01 11:23:14 -0500991 fLeft += pPiece->Widths[i] / 20000.0f;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500992 }
993 }
994 m_pTabstopContext->m_fLeft =
995 std::min(fLeft, m_pTabstopContext->m_fTabWidth);
996 m_pTabstopContext->m_bTabstops = false;
997 m_pTabstopContext->m_fTabWidth = 0;
998 }
999 pPiece->rtPiece.left -= m_pTabstopContext->m_fLeft;
1000 }
1001}
1002
Dan Sinclairc36fe072017-03-09 16:58:12 -05001003void CXFA_TextLayout::AppendTextLine(CFX_BreakType dwStatus,
Dan Sinclair05df0752017-03-14 14:43:42 -04001004 float& fLinePos,
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001005 bool bSavePieces,
1006 bool bEndBreak) {
1007 int32_t iPieces = m_pBreak->CountBreakPieces();
1008 if (iPieces < 1)
1009 return;
1010
Dan Sinclair0b950422017-09-21 15:49:49 -04001011 RetainPtr<CFX_CSSComputedStyle> pStyle;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001012 if (bSavePieces) {
tsepez783a7e02017-01-17 11:05:57 -08001013 auto pNew = pdfium::MakeUnique<CXFA_PieceLine>();
1014 CXFA_PieceLine* pPieceLine = pNew.get();
1015 m_pieceLines.push_back(std::move(pNew));
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001016 if (m_pTabstopContext)
1017 m_pTabstopContext->Reset();
1018
Dan Sinclair05df0752017-03-14 14:43:42 -04001019 float fLineStep = 0, fBaseLine = 0;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001020 int32_t i = 0;
1021 for (i = 0; i < iPieces; i++) {
Dan Sinclair893822a2017-03-13 15:32:07 -04001022 const CFX_BreakPiece* pPiece = m_pBreak->GetBreakPieceUnstable(i);
Tom Sepeze02b2bc2017-05-09 10:12:39 -07001023 CXFA_TextUserData* pUserData = pPiece->m_pUserData.Get();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001024 if (pUserData)
1025 pStyle = pUserData->m_pStyle;
Dan Sinclair05df0752017-03-14 14:43:42 -04001026 float fVerScale = pPiece->m_iVerticalScale / 100.0f;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001027
Dan Sinclair2eddb662017-05-25 16:49:51 -04001028 auto pTP = pdfium::MakeUnique<CXFA_TextPiece>();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001029 pTP->iChars = pPiece->m_iChars;
Dan Sinclairbef73892017-03-01 11:23:14 -05001030 pTP->szText = pPiece->GetString();
1031 pTP->Widths = pPiece->GetWidths();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001032 pTP->iBidiLevel = pPiece->m_iBidiLevel;
1033 pTP->iHorScale = pPiece->m_iHorizontalScale;
1034 pTP->iVerScale = pPiece->m_iVerticalScale;
Dan Sinclair7e5fdd02017-01-23 16:24:26 -05001035 m_textParser.GetUnderline(m_pTextProvider, pStyle.Get(), pTP->iUnderline,
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001036 pTP->iPeriod);
Dan Sinclair7e5fdd02017-01-23 16:24:26 -05001037 m_textParser.GetLinethrough(m_pTextProvider, pStyle.Get(),
1038 pTP->iLineThrough);
1039 pTP->dwColor = m_textParser.GetColor(m_pTextProvider, pStyle.Get());
1040 pTP->pFont = m_textParser.GetFont(m_pTextProvider, pStyle.Get());
1041 pTP->fFontSize = m_textParser.GetFontSize(m_pTextProvider, pStyle.Get());
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001042 pTP->rtPiece.left = pPiece->m_iStartPos / 20000.0f;
1043 pTP->rtPiece.width = pPiece->m_iWidth / 20000.0f;
Dan Sinclair05df0752017-03-14 14:43:42 -04001044 pTP->rtPiece.height = (float)pPiece->m_iFontSize * fVerScale / 20.0f;
1045 float fBaseLineTemp =
Dan Sinclair7e5fdd02017-01-23 16:24:26 -05001046 m_textParser.GetBaseline(m_pTextProvider, pStyle.Get());
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001047 pTP->rtPiece.top = fBaseLineTemp;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001048
Dan Sinclair05df0752017-03-14 14:43:42 -04001049 float fLineHeight = m_textParser.GetLineHeight(
Dan Sinclair7e5fdd02017-01-23 16:24:26 -05001050 m_pTextProvider, pStyle.Get(), m_iLines == 0, fVerScale);
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001051 if (fBaseLineTemp > 0) {
Dan Sinclair05df0752017-03-14 14:43:42 -04001052 float fLineHeightTmp = fBaseLineTemp + pTP->rtPiece.height;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001053 if (fLineHeight < fLineHeightTmp)
1054 fLineHeight = fLineHeightTmp;
1055 else
1056 fBaseLineTemp = 0;
1057 } else if (fBaseLine < -fBaseLineTemp) {
1058 fBaseLine = -fBaseLineTemp;
1059 }
1060 fLineStep = std::max(fLineStep, fLineHeight);
Tom Sepez03de8842017-01-24 14:24:36 -08001061 pTP->pLinkData = pUserData ? pUserData->m_pLinkData : nullptr;
tsepez783a7e02017-01-17 11:05:57 -08001062 pPieceLine->m_textPieces.push_back(std::move(pTP));
Dan Sinclair7e5fdd02017-01-23 16:24:26 -05001063 DoTabstops(pStyle.Get(), pPieceLine);
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001064 }
tsepez783a7e02017-01-17 11:05:57 -08001065 for (const auto& pTP : pPieceLine->m_textPieces) {
Dan Sinclair05df0752017-03-14 14:43:42 -04001066 float& fTop = pTP->rtPiece.top;
1067 float fBaseLineTemp = fTop;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001068 fTop = fLinePos + fLineStep - pTP->rtPiece.height - fBaseLineTemp;
1069 fTop = std::max(0.0f, fTop);
1070 }
1071 fLinePos += fLineStep + fBaseLine;
1072 } else {
Dan Sinclair05df0752017-03-14 14:43:42 -04001073 float fLineStep = 0;
1074 float fLineWidth = 0;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001075 for (int32_t i = 0; i < iPieces; i++) {
Dan Sinclair893822a2017-03-13 15:32:07 -04001076 const CFX_BreakPiece* pPiece = m_pBreak->GetBreakPieceUnstable(i);
Tom Sepeze02b2bc2017-05-09 10:12:39 -07001077 CXFA_TextUserData* pUserData = pPiece->m_pUserData.Get();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001078 if (pUserData)
1079 pStyle = pUserData->m_pStyle;
Dan Sinclair05df0752017-03-14 14:43:42 -04001080 float fVerScale = pPiece->m_iVerticalScale / 100.0f;
1081 float fBaseLine = m_textParser.GetBaseline(m_pTextProvider, pStyle.Get());
1082 float fLineHeight = m_textParser.GetLineHeight(
Dan Sinclair7e5fdd02017-01-23 16:24:26 -05001083 m_pTextProvider, pStyle.Get(), m_iLines == 0, fVerScale);
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001084 if (fBaseLine > 0) {
Dan Sinclair05df0752017-03-14 14:43:42 -04001085 float fLineHeightTmp =
1086 fBaseLine + (float)pPiece->m_iFontSize * fVerScale / 20.0f;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001087 if (fLineHeight < fLineHeightTmp) {
1088 fLineHeight = fLineHeightTmp;
1089 }
1090 }
1091 fLineStep = std::max(fLineStep, fLineHeight);
1092 fLineWidth += pPiece->m_iWidth / 20000.0f;
1093 }
1094 fLinePos += fLineStep;
1095 m_fMaxWidth = std::max(m_fMaxWidth, fLineWidth);
1096 if (m_pLoader && m_pLoader->m_bSaveLineHeight) {
Dan Sinclair05df0752017-03-14 14:43:42 -04001097 float fHeight = fLinePos - m_pLoader->m_fLastPos;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001098 m_pLoader->m_fLastPos = fLinePos;
Tom Sepezfcc309e2017-03-24 14:19:11 -07001099 m_pLoader->m_lineHeights.push_back(fHeight);
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001100 }
1101 }
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001102
1103 m_pBreak->ClearBreakPieces();
Dan Sinclairc36fe072017-03-09 16:58:12 -05001104 if (dwStatus == CFX_BreakType::Paragraph) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001105 m_pBreak->Reset();
1106 if (!pStyle && bEndBreak) {
1107 CXFA_Para para = m_pTextProvider->GetParaNode();
1108 if (para) {
Dan Sinclair05df0752017-03-14 14:43:42 -04001109 float fStartPos = para.GetMarginLeft();
1110 float fIndent = para.GetTextIndent();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001111 if (fIndent > 0)
1112 fStartPos += fIndent;
1113
Dan Sinclair05df0752017-03-14 14:43:42 -04001114 float fSpaceBelow = para.GetSpaceBelow();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001115 if (fSpaceBelow < 0.1f)
1116 fSpaceBelow = 0;
1117
1118 m_pBreak->SetLineStartPos(fStartPos);
1119 fLinePos += fSpaceBelow;
1120 }
1121 }
1122 }
1123
1124 if (pStyle) {
Dan Sinclair05df0752017-03-14 14:43:42 -04001125 float fStart = 0;
Dan Sinclair9f0e85a2017-08-08 13:23:24 -04001126 const CFX_CSSRect* pRect = pStyle->GetMarginWidth();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001127 if (pRect)
1128 fStart = pRect->left.GetValue();
1129
Dan Sinclair05df0752017-03-14 14:43:42 -04001130 float fTextIndent = pStyle->GetTextIndent().GetValue();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001131 if (fTextIndent < 0)
1132 fStart -= fTextIndent;
1133
1134 m_pBreak->SetLineStartPos(fStart);
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001135 }
1136 m_iLines++;
1137}
1138
Dan Sinclair73b492a2017-08-14 17:23:25 -04001139void CXFA_TextLayout::RenderString(CFX_RenderDevice* pDevice,
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001140 CXFA_PieceLine* pPieceLine,
1141 int32_t iPiece,
1142 FXTEXT_CHARPOS* pCharPos,
1143 const CFX_Matrix& tmDoc2Device) {
Dan Sinclair2eddb662017-05-25 16:49:51 -04001144 const CXFA_TextPiece* pPiece = pPieceLine->m_textPieces[iPiece].get();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001145 int32_t iCount = GetDisplayPos(pPiece, pCharPos);
1146 if (iCount > 0) {
Dan Sinclair73b492a2017-08-14 17:23:25 -04001147 CFDE_TextOut::DrawString(pDevice, pPiece->dwColor, pPiece->pFont, pCharPos,
1148 iCount, pPiece->fFontSize, &tmDoc2Device);
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001149 }
Tom Sepezfcc309e2017-03-24 14:19:11 -07001150 pPieceLine->m_charCounts.push_back(iCount);
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001151}
1152
Dan Sinclair73b492a2017-08-14 17:23:25 -04001153void CXFA_TextLayout::RenderPath(CFX_RenderDevice* pDevice,
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001154 CXFA_PieceLine* pPieceLine,
1155 int32_t iPiece,
1156 FXTEXT_CHARPOS* pCharPos,
1157 const CFX_Matrix& tmDoc2Device) {
Dan Sinclair2eddb662017-05-25 16:49:51 -04001158 CXFA_TextPiece* pPiece = pPieceLine->m_textPieces[iPiece].get();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001159 bool bNoUnderline = pPiece->iUnderline < 1 || pPiece->iUnderline > 2;
1160 bool bNoLineThrough = pPiece->iLineThrough < 1 || pPiece->iLineThrough > 2;
1161 if (bNoUnderline && bNoLineThrough)
1162 return;
1163
Dan Sinclair7ffb59f2017-08-10 10:16:06 -04001164 CFX_PathData path;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001165 int32_t iChars = GetDisplayPos(pPiece, pCharPos);
1166 if (iChars > 0) {
1167 CFX_PointF pt1, pt2;
Dan Sinclair05df0752017-03-14 14:43:42 -04001168 float fEndY = pCharPos[0].m_Origin.y + 1.05f;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001169 if (pPiece->iPeriod == XFA_ATTRIBUTEENUM_Word) {
1170 for (int32_t i = 0; i < pPiece->iUnderline; i++) {
1171 for (int32_t j = 0; j < iChars; j++) {
Dan Sinclair2c02fae2017-02-16 13:42:11 -05001172 pt1.x = pCharPos[j].m_Origin.x;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001173 pt2.x =
1174 pt1.x + pCharPos[j].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
1175 pt1.y = pt2.y = fEndY;
Dan Sinclair7ffb59f2017-08-10 10:16:06 -04001176 path.AppendLine(pt1, pt2);
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001177 }
1178 fEndY += 2.0f;
1179 }
1180 } else {
Dan Sinclair2c02fae2017-02-16 13:42:11 -05001181 pt1.x = pCharPos[0].m_Origin.x;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001182 pt2.x =
Dan Sinclair2c02fae2017-02-16 13:42:11 -05001183 pCharPos[iChars - 1].m_Origin.x +
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001184 pCharPos[iChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
1185 for (int32_t i = 0; i < pPiece->iUnderline; i++) {
1186 pt1.y = pt2.y = fEndY;
Dan Sinclair7ffb59f2017-08-10 10:16:06 -04001187 path.AppendLine(pt1, pt2);
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001188 fEndY += 2.0f;
1189 }
1190 }
Dan Sinclair2c02fae2017-02-16 13:42:11 -05001191 fEndY = pCharPos[0].m_Origin.y - pPiece->rtPiece.height * 0.25f;
1192 pt1.x = pCharPos[0].m_Origin.x;
1193 pt2.x = pCharPos[iChars - 1].m_Origin.x +
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001194 pCharPos[iChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
1195 for (int32_t i = 0; i < pPiece->iLineThrough; i++) {
1196 pt1.y = pt2.y = fEndY;
Dan Sinclair7ffb59f2017-08-10 10:16:06 -04001197 path.AppendLine(pt1, pt2);
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001198 fEndY += 2.0f;
1199 }
1200 } else {
1201 if (bNoLineThrough &&
1202 (bNoUnderline || pPiece->iPeriod != XFA_ATTRIBUTEENUM_All)) {
1203 return;
1204 }
1205 int32_t iCharsTmp = 0;
Tom Sepezfcc309e2017-03-24 14:19:11 -07001206 int32_t iPiecePrev = iPiece;
1207 int32_t iPieceNext = iPiece;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001208 while (iPiecePrev > 0) {
1209 iPiecePrev--;
Tom Sepezfcc309e2017-03-24 14:19:11 -07001210 iCharsTmp = pPieceLine->m_charCounts[iPiecePrev];
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001211 if (iCharsTmp > 0)
1212 break;
1213 }
1214 if (iCharsTmp == 0)
1215 return;
1216
1217 iCharsTmp = 0;
tsepez783a7e02017-01-17 11:05:57 -08001218 int32_t iPieces = pdfium::CollectionSize<int32_t>(pPieceLine->m_textPieces);
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001219 while (iPieceNext < iPieces - 1) {
1220 iPieceNext++;
Tom Sepezfcc309e2017-03-24 14:19:11 -07001221 iCharsTmp = pPieceLine->m_charCounts[iPieceNext];
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001222 if (iCharsTmp > 0)
1223 break;
1224 }
1225 if (iCharsTmp == 0)
1226 return;
1227
Dan Sinclair05df0752017-03-14 14:43:42 -04001228 float fOrgX = 0.0f;
1229 float fEndX = 0.0f;
tsepez783a7e02017-01-17 11:05:57 -08001230 pPiece = pPieceLine->m_textPieces[iPiecePrev].get();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001231 iChars = GetDisplayPos(pPiece, pCharPos);
1232 if (iChars < 1)
1233 return;
1234
Dan Sinclair2c02fae2017-02-16 13:42:11 -05001235 fOrgX = pCharPos[iChars - 1].m_Origin.x +
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001236 pCharPos[iChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
tsepez783a7e02017-01-17 11:05:57 -08001237 pPiece = pPieceLine->m_textPieces[iPieceNext].get();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001238 iChars = GetDisplayPos(pPiece, pCharPos);
1239 if (iChars < 1)
1240 return;
1241
Dan Sinclair2c02fae2017-02-16 13:42:11 -05001242 fEndX = pCharPos[0].m_Origin.x;
1243 CFX_PointF pt1;
1244 CFX_PointF pt2;
1245 pt1.x = fOrgX;
1246 pt2.x = fEndX;
Dan Sinclair05df0752017-03-14 14:43:42 -04001247 float fEndY = pCharPos[0].m_Origin.y + 1.05f;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001248 for (int32_t i = 0; i < pPiece->iUnderline; i++) {
Dan Sinclair2c02fae2017-02-16 13:42:11 -05001249 pt1.y = fEndY;
1250 pt2.y = fEndY;
Dan Sinclair7ffb59f2017-08-10 10:16:06 -04001251 path.AppendLine(pt1, pt2);
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001252 fEndY += 2.0f;
1253 }
Dan Sinclair2c02fae2017-02-16 13:42:11 -05001254 fEndY = pCharPos[0].m_Origin.y - pPiece->rtPiece.height * 0.25f;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001255 for (int32_t i = 0; i < pPiece->iLineThrough; i++) {
Dan Sinclair2c02fae2017-02-16 13:42:11 -05001256 pt1.y = fEndY;
1257 pt2.y = fEndY;
Dan Sinclair7ffb59f2017-08-10 10:16:06 -04001258 path.AppendLine(pt1, pt2);
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001259 fEndY += 2.0f;
1260 }
1261 }
Dan Sinclair73b492a2017-08-14 17:23:25 -04001262
1263 CFX_GraphStateData graphState;
1264 graphState.m_LineCap = CFX_GraphStateData::LineCapButt;
1265 graphState.m_LineJoin = CFX_GraphStateData::LineJoinMiter;
1266 graphState.m_LineWidth = 1;
1267 graphState.m_MiterLimit = 10;
1268 graphState.m_DashPhase = 0;
1269 pDevice->DrawPath(&path, &tmDoc2Device, &graphState, 0, pPiece->dwColor, 0);
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001270}
1271
Dan Sinclair2eddb662017-05-25 16:49:51 -04001272int32_t CXFA_TextLayout::GetDisplayPos(const CXFA_TextPiece* pPiece,
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001273 FXTEXT_CHARPOS* pCharPos,
1274 bool bCharCode) {
1275 if (!pPiece)
1276 return 0;
1277
1278 FX_RTFTEXTOBJ tr;
tsepez783a7e02017-01-17 11:05:57 -08001279 if (!ToRun(pPiece, &tr))
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001280 return 0;
1281 return m_pBreak->GetDisplayPos(&tr, pCharPos, bCharCode);
1282}
1283
Dan Sinclair2eddb662017-05-25 16:49:51 -04001284bool CXFA_TextLayout::ToRun(const CXFA_TextPiece* pPiece, FX_RTFTEXTOBJ* tr) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001285 int32_t iLength = pPiece->iChars;
1286 if (iLength < 1)
1287 return false;
1288
Dan Sinclairbef73892017-03-01 11:23:14 -05001289 tr->pStr = pPiece->szText;
tsepez783a7e02017-01-17 11:05:57 -08001290 tr->pFont = pPiece->pFont;
1291 tr->pRect = &pPiece->rtPiece;
Dan Sinclairbef73892017-03-01 11:23:14 -05001292 tr->pWidths = pPiece->Widths;
tsepez783a7e02017-01-17 11:05:57 -08001293 tr->iLength = iLength;
1294 tr->fFontSize = pPiece->fFontSize;
1295 tr->iBidiLevel = pPiece->iBidiLevel;
tsepez783a7e02017-01-17 11:05:57 -08001296 tr->wLineBreakChar = L'\n';
1297 tr->iVerticalScale = pPiece->iVerScale;
tsepez783a7e02017-01-17 11:05:57 -08001298 tr->iHorizontalScale = pPiece->iHorScale;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001299 return true;
1300}