blob: 47f40ac04f479d8a105322bad4731a726ce3f44c [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>
10
11#include "third_party/base/ptr_util.h"
12#include "third_party/base/stl_util.h"
13#include "xfa/fde/cfde_path.h"
14#include "xfa/fde/fde_gedevice.h"
15#include "xfa/fde/fde_object.h"
16#include "xfa/fde/xml/fde_xml_imp.h"
17#include "xfa/fxfa/app/cxfa_linkuserdata.h"
18#include "xfa/fxfa/app/cxfa_loadercontext.h"
19#include "xfa/fxfa/app/cxfa_pieceline.h"
20#include "xfa/fxfa/app/cxfa_textparsecontext.h"
21#include "xfa/fxfa/app/cxfa_texttabstopscontext.h"
22#include "xfa/fxfa/app/cxfa_textuserdata.h"
23#include "xfa/fxfa/app/xfa_ffwidgetacc.h"
24#include "xfa/fxfa/app/xfa_textpiece.h"
25#include "xfa/fxfa/parser/cxfa_font.h"
26#include "xfa/fxfa/parser/cxfa_para.h"
27#include "xfa/fxfa/parser/xfa_object.h"
28
29#define XFA_LOADERCNTXTFLG_FILTERSPACE 0x001
30
31CXFA_TextLayout::CXFA_TextLayout(CXFA_TextProvider* pTextProvider)
32 : m_bHasBlock(false),
33 m_pTextProvider(pTextProvider),
34 m_pTextDataNode(nullptr),
35 m_bRichText(false),
36 m_iLines(0),
37 m_fMaxWidth(0),
38 m_bBlockContinue(true) {
39 ASSERT(m_pTextProvider);
40}
41
42CXFA_TextLayout::~CXFA_TextLayout() {
43 m_textParser.Reset();
44 Unload();
45}
46
47void CXFA_TextLayout::Unload() {
48 for (int32_t i = 0; i < m_pieceLines.GetSize(); i++) {
49 CXFA_PieceLine* pLine = m_pieceLines.GetAt(i);
50 for (int32_t i = 0; i < pLine->m_textPieces.GetSize(); i++) {
51 XFA_TextPiece* pPiece = pLine->m_textPieces.GetAt(i);
52 // Release text and widths in a text piece.
Dan Sinclair0cb9b8c2017-01-10 16:38:10 -050053 delete pPiece->pszText;
54 delete pPiece->pWidths;
Dan Sinclair1f5d4982017-01-10 16:37:32 -050055 // Release text piece.
Dan Sinclair0cb9b8c2017-01-10 16:38:10 -050056 delete pPiece;
Dan Sinclair1f5d4982017-01-10 16:37:32 -050057 }
58 pLine->m_textPieces.RemoveAll();
59 // Release line.
Dan Sinclair0cb9b8c2017-01-10 16:38:10 -050060 delete pLine;
Dan Sinclair1f5d4982017-01-10 16:37:32 -050061 }
62 m_pieceLines.RemoveAll();
63 m_pBreak.reset();
Dan Sinclair1f5d4982017-01-10 16:37:32 -050064}
65
66const CFX_ArrayTemplate<CXFA_PieceLine*>* CXFA_TextLayout::GetPieceLines() {
67 return &m_pieceLines;
68}
69
70void CXFA_TextLayout::GetTextDataNode() {
71 if (!m_pTextProvider)
72 return;
73
74 CXFA_Node* pNode = m_pTextProvider->GetTextNode(m_bRichText);
75 if (pNode && m_bRichText)
76 m_textParser.Reset();
77
78 m_pTextDataNode = pNode;
79}
80
81CFDE_XMLNode* CXFA_TextLayout::GetXMLContainerNode() {
82 if (!m_bRichText)
83 return nullptr;
84
85 CFDE_XMLNode* pXMLRoot = m_pTextDataNode->GetXMLMappingNode();
86 if (!pXMLRoot)
87 return nullptr;
88
89 CFDE_XMLNode* pXMLContainer = nullptr;
90 for (CFDE_XMLNode* pXMLChild =
91 pXMLRoot->GetNodeItem(CFDE_XMLNode::FirstChild);
92 pXMLChild;
93 pXMLChild = pXMLChild->GetNodeItem(CFDE_XMLNode::NextSibling)) {
94 if (pXMLChild->GetType() == FDE_XMLNODE_Element) {
95 CFDE_XMLElement* pXMLElement = static_cast<CFDE_XMLElement*>(pXMLChild);
96 CFX_WideString wsTag;
97 pXMLElement->GetLocalTagName(wsTag);
98 if (wsTag == FX_WSTRC(L"body") || wsTag == FX_WSTRC(L"html")) {
99 pXMLContainer = pXMLChild;
100 break;
101 }
102 }
103 }
104 return pXMLContainer;
105}
106
107CFX_RTFBreak* CXFA_TextLayout::CreateBreak(bool bDefault) {
108 uint32_t dwStyle = FX_RTFLAYOUTSTYLE_ExpandTab;
109 if (!bDefault)
110 dwStyle |= FX_RTFLAYOUTSTYLE_Pagination;
111
112 CFX_RTFBreak* pBreak = new CFX_RTFBreak(0);
113 pBreak->SetLayoutStyles(dwStyle);
114 pBreak->SetLineBreakChar(L'\n');
115 pBreak->SetLineBreakTolerance(1);
116 pBreak->SetFont(m_textParser.GetFont(m_pTextProvider, nullptr));
117 pBreak->SetFontSize(m_textParser.GetFontSize(m_pTextProvider, nullptr));
118 return pBreak;
119}
120
121void CXFA_TextLayout::InitBreak(FX_FLOAT fLineWidth) {
122 CXFA_Font font = m_pTextProvider->GetFontNode();
123 CXFA_Para para = m_pTextProvider->GetParaNode();
124 FX_FLOAT fStart = 0;
125 FX_FLOAT fStartPos = 0;
126 if (para) {
127 int32_t iAlign = FX_RTFLINEALIGNMENT_Left;
128 switch (para.GetHorizontalAlign()) {
129 case XFA_ATTRIBUTEENUM_Center:
130 iAlign = FX_RTFLINEALIGNMENT_Center;
131 break;
132 case XFA_ATTRIBUTEENUM_Right:
133 iAlign = FX_RTFLINEALIGNMENT_Right;
134 break;
135 case XFA_ATTRIBUTEENUM_Justify:
136 iAlign = FX_RTFLINEALIGNMENT_Justified;
137 break;
138 case XFA_ATTRIBUTEENUM_JustifyAll:
139 iAlign = FX_RTFLINEALIGNMENT_Distributed;
140 break;
141 }
142 m_pBreak->SetAlignment(iAlign);
143
144 fStart = para.GetMarginLeft();
145 if (m_pTextProvider->IsCheckButtonAndAutoWidth()) {
146 if (iAlign != FX_RTFLINEALIGNMENT_Left)
147 fLineWidth -= para.GetMarginRight();
148 } else {
149 fLineWidth -= para.GetMarginRight();
150 }
151 if (fLineWidth < 0)
152 fLineWidth = fStart;
153
154 fStartPos = fStart;
155 FX_FLOAT fIndent = para.GetTextIndent();
156 if (fIndent > 0)
157 fStartPos += fIndent;
158 }
159
160 m_pBreak->SetLineBoundary(fStart, fLineWidth);
161 m_pBreak->SetLineStartPos(fStartPos);
162 if (font) {
163 m_pBreak->SetHorizontalScale((int32_t)font.GetHorizontalScale());
164 m_pBreak->SetVerticalScale((int32_t)font.GetVerticalScale());
165 m_pBreak->SetCharSpace(font.GetLetterSpacing());
166 }
167
168 FX_FLOAT fFontSize = m_textParser.GetFontSize(m_pTextProvider, nullptr);
169 m_pBreak->SetFontSize(fFontSize);
170 m_pBreak->SetFont(m_textParser.GetFont(m_pTextProvider, nullptr));
171 m_pBreak->SetLineBreakTolerance(fFontSize * 0.2f);
172}
173
174void CXFA_TextLayout::InitBreak(IFDE_CSSComputedStyle* pStyle,
Dan Sinclair96f482c2017-01-11 16:31:27 -0500175 FDE_CSSDisplay eDisplay,
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500176 FX_FLOAT fLineWidth,
177 CFDE_XMLNode* pXMLNode,
178 IFDE_CSSComputedStyle* pParentStyle) {
179 if (!pStyle) {
180 InitBreak(fLineWidth);
181 return;
182 }
183
184 IFDE_CSSParagraphStyle* pParaStyle = pStyle->GetParagraphStyles();
Dan Sinclair96f482c2017-01-11 16:31:27 -0500185 if (eDisplay == FDE_CSSDisplay::Block ||
186 eDisplay == FDE_CSSDisplay::ListItem) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500187 int32_t iAlign = FX_RTFLINEALIGNMENT_Left;
188 switch (pParaStyle->GetTextAlign()) {
Dan Sinclair96f482c2017-01-11 16:31:27 -0500189 case FDE_CSSTextAlign::Right:
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500190 iAlign = FX_RTFLINEALIGNMENT_Right;
191 break;
Dan Sinclair96f482c2017-01-11 16:31:27 -0500192 case FDE_CSSTextAlign::Center:
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500193 iAlign = FX_RTFLINEALIGNMENT_Center;
194 break;
Dan Sinclair96f482c2017-01-11 16:31:27 -0500195 case FDE_CSSTextAlign::Justify:
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500196 iAlign = FX_RTFLINEALIGNMENT_Justified;
197 break;
Dan Sinclair96f482c2017-01-11 16:31:27 -0500198 case FDE_CSSTextAlign::JustifyAll:
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500199 iAlign = FX_RTFLINEALIGNMENT_Distributed;
200 break;
201 default:
202 break;
203 }
204 m_pBreak->SetAlignment(iAlign);
205 FX_FLOAT fStart = 0;
206 const FDE_CSSRECT* pRect = pStyle->GetBoundaryStyles()->GetMarginWidth();
207 const FDE_CSSRECT* pPaddingRect =
208 pStyle->GetBoundaryStyles()->GetPaddingWidth();
209 if (pRect) {
210 fStart = pRect->left.GetValue();
211 fLineWidth -= pRect->right.GetValue();
212 if (pPaddingRect) {
213 fStart += pPaddingRect->left.GetValue();
214 fLineWidth -= pPaddingRect->right.GetValue();
215 }
Dan Sinclair96f482c2017-01-11 16:31:27 -0500216 if (eDisplay == FDE_CSSDisplay::ListItem) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500217 const FDE_CSSRECT* pParRect =
218 pParentStyle->GetBoundaryStyles()->GetMarginWidth();
219 const FDE_CSSRECT* pParPaddingRect =
220 pParentStyle->GetBoundaryStyles()->GetPaddingWidth();
221 if (pParRect) {
222 fStart += pParRect->left.GetValue();
223 fLineWidth -= pParRect->right.GetValue();
224 if (pParPaddingRect) {
225 fStart += pParPaddingRect->left.GetValue();
226 fLineWidth -= pParPaddingRect->right.GetValue();
227 }
228 }
229 FDE_CSSRECT pNewRect;
Dan Sinclair96f482c2017-01-11 16:31:27 -0500230 pNewRect.left.Set(FDE_CSSLengthUnit::Point, fStart);
231 pNewRect.right.Set(FDE_CSSLengthUnit::Point, pRect->right.GetValue());
232 pNewRect.top.Set(FDE_CSSLengthUnit::Point, pRect->top.GetValue());
233 pNewRect.bottom.Set(FDE_CSSLengthUnit::Point, pRect->bottom.GetValue());
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500234 pStyle->GetBoundaryStyles()->SetMarginWidth(pNewRect);
235 }
236 }
237 m_pBreak->SetLineBoundary(fStart, fLineWidth);
238 FX_FLOAT fIndent = pParaStyle->GetTextIndent().GetValue();
239 if (fIndent > 0)
240 fStart += fIndent;
241
242 m_pBreak->SetLineStartPos(fStart);
243 m_pBreak->SetTabWidth(m_textParser.GetTabInterval(pStyle));
244 if (!m_pTabstopContext)
245 m_pTabstopContext = pdfium::MakeUnique<CXFA_TextTabstopsContext>();
246 m_textParser.GetTabstops(pStyle, m_pTabstopContext.get());
247 for (int32_t i = 0; i < m_pTabstopContext->m_iTabCount; i++) {
248 XFA_TABSTOPS* pTab = m_pTabstopContext->m_tabstops.GetDataPtr(i);
249 m_pBreak->AddPositionedTab(pTab->fTabstops);
250 }
251 }
252
253 FX_FLOAT fFontSize = m_textParser.GetFontSize(m_pTextProvider, pStyle);
254 m_pBreak->SetFontSize(fFontSize);
255 m_pBreak->SetLineBreakTolerance(fFontSize * 0.2f);
256 m_pBreak->SetFont(m_textParser.GetFont(m_pTextProvider, pStyle));
257 m_pBreak->SetHorizontalScale(
258 m_textParser.GetHorScale(m_pTextProvider, pStyle, pXMLNode));
259 m_pBreak->SetVerticalScale(m_textParser.GetVerScale(m_pTextProvider, pStyle));
260 m_pBreak->SetCharSpace(pParaStyle->GetLetterSpacing().GetValue());
261}
262
263int32_t CXFA_TextLayout::GetText(CFX_WideString& wsText) {
264 GetTextDataNode();
265 wsText.clear();
266 if (!m_bRichText)
267 wsText = m_pTextDataNode->GetContent();
268 return wsText.GetLength();
269}
270
271FX_FLOAT CXFA_TextLayout::GetLayoutHeight() {
272 if (!m_pLoader)
273 return 0;
274
275 int32_t iCount = m_pLoader->m_lineHeights.GetSize();
276 if (iCount == 0 && m_pLoader->m_fWidth > 0) {
277 CFX_SizeF szMax(m_pLoader->m_fWidth, m_pLoader->m_fHeight);
278 CFX_SizeF szDef;
279 m_pLoader->m_bSaveLineHeight = true;
280 m_pLoader->m_fLastPos = 0;
281 CalcSize(szMax, szMax, szDef);
282 m_pLoader->m_bSaveLineHeight = false;
283 return szDef.y;
284 }
285
286 FX_FLOAT fHeight = m_pLoader->m_fHeight;
287 if (fHeight < 0.1f) {
288 fHeight = 0;
289 for (int32_t i = 0; i < iCount; i++)
290 fHeight += m_pLoader->m_lineHeights.ElementAt(i);
291 }
292 return fHeight;
293}
294
295FX_FLOAT CXFA_TextLayout::StartLayout(FX_FLOAT fWidth) {
296 if (!m_pLoader)
297 m_pLoader = pdfium::MakeUnique<CXFA_LoaderContext>();
298
299 if (fWidth < 0 || (m_pLoader->m_fWidth > -1 &&
300 FXSYS_fabs(fWidth - m_pLoader->m_fWidth) > 0)) {
301 m_pLoader->m_lineHeights.RemoveAll();
302 m_Blocks.RemoveAll();
303 Unload();
304 m_pLoader->m_fStartLineOffset = 0;
305 }
306 m_pLoader->m_fWidth = fWidth;
307
308 if (fWidth < 0) {
309 CFX_SizeF szMax;
310 CFX_SizeF szDef;
311 m_pLoader->m_bSaveLineHeight = true;
312 m_pLoader->m_fLastPos = 0;
313 CalcSize(szMax, szMax, szDef);
314 m_pLoader->m_bSaveLineHeight = false;
315 fWidth = szDef.x;
316 }
317 return fWidth;
318}
319
320bool CXFA_TextLayout::DoLayout(int32_t iBlockIndex,
321 FX_FLOAT& fCalcHeight,
322 FX_FLOAT fContentAreaHeight,
323 FX_FLOAT fTextHeight) {
324 if (!m_pLoader)
325 return false;
326
327 int32_t iBlockCount = m_Blocks.GetSize();
328 FX_FLOAT fHeight = fTextHeight;
329 if (fHeight < 0)
330 fHeight = GetLayoutHeight();
331
332 m_pLoader->m_fHeight = fHeight;
333 if (fContentAreaHeight < 0)
334 return false;
335
336 m_bHasBlock = true;
337 if (iBlockCount == 0 && fHeight > 0) {
338 fHeight = fTextHeight - GetLayoutHeight();
339 if (fHeight > 0) {
340 int32_t iAlign = m_textParser.GetVAlign(m_pTextProvider);
341 if (iAlign == XFA_ATTRIBUTEENUM_Middle)
342 fHeight /= 2.0f;
343 else if (iAlign != XFA_ATTRIBUTEENUM_Bottom)
344 fHeight = 0;
345 m_pLoader->m_fStartLineOffset = fHeight;
346 }
347 }
348
349 FX_FLOAT fLinePos = m_pLoader->m_fStartLineOffset;
350 int32_t iLineIndex = 0;
351 if (iBlockCount > 1) {
352 if (iBlockCount >= (iBlockIndex + 1) * 2) {
353 iLineIndex = m_Blocks.ElementAt(iBlockIndex * 2);
354 } else {
355 iLineIndex = m_Blocks.ElementAt(iBlockCount - 1) +
356 m_Blocks.ElementAt(iBlockCount - 2);
357 }
358 if (!m_pLoader->m_BlocksHeight.empty()) {
359 for (int32_t i = 0; i < iBlockIndex; i++)
360 fLinePos -= m_pLoader->m_BlocksHeight[i * 2 + 1];
361 }
362 }
363
364 int32_t iCount = m_pLoader->m_lineHeights.GetSize();
365 int32_t i = 0;
366 for (i = iLineIndex; i < iCount; i++) {
367 FX_FLOAT fLineHeight = m_pLoader->m_lineHeights.ElementAt(i);
368 if ((i == iLineIndex) && (fLineHeight - fContentAreaHeight > 0.001)) {
369 fCalcHeight = 0;
370 return true;
371 }
372 if (fLinePos + fLineHeight - fContentAreaHeight > 0.001) {
373 if (iBlockCount >= (iBlockIndex + 1) * 2) {
374 m_Blocks.SetAt(iBlockIndex * 2, iLineIndex);
375 m_Blocks.SetAt(iBlockIndex * 2 + 1, i - iLineIndex);
376 } else {
377 m_Blocks.Add(iLineIndex);
378 m_Blocks.Add(i - iLineIndex);
379 }
380 if (i == iLineIndex) {
381 if (fCalcHeight <= fLinePos) {
382 if (pdfium::CollectionSize<int32_t>(m_pLoader->m_BlocksHeight) >
383 iBlockIndex * 2 &&
384 (m_pLoader->m_BlocksHeight[iBlockIndex * 2] == iBlockIndex)) {
385 m_pLoader->m_BlocksHeight[iBlockIndex * 2 + 1] = fCalcHeight;
386 } else {
387 m_pLoader->m_BlocksHeight.push_back((FX_FLOAT)iBlockIndex);
388 m_pLoader->m_BlocksHeight.push_back(fCalcHeight);
389 }
390 }
391 return true;
392 }
393
394 fCalcHeight = fLinePos;
395 return true;
396 }
397 fLinePos += fLineHeight;
398 }
399 return false;
400}
401
402int32_t CXFA_TextLayout::CountBlocks() const {
403 int32_t iCount = m_Blocks.GetSize() / 2;
404 return iCount > 0 ? iCount : 1;
405}
406
407bool CXFA_TextLayout::CalcSize(const CFX_SizeF& minSize,
408 const CFX_SizeF& maxSize,
409 CFX_SizeF& defaultSize) {
410 defaultSize.x = maxSize.x;
411 if (defaultSize.x < 1)
412 defaultSize.x = 0xFFFF;
413
414 m_pBreak.reset(CreateBreak(false));
415 FX_FLOAT fLinePos = 0;
416 m_iLines = 0;
417 m_fMaxWidth = 0;
418 Loader(defaultSize, fLinePos, false);
419 if (fLinePos < 0.1f)
420 fLinePos = m_textParser.GetFontSize(m_pTextProvider, nullptr);
421
422 m_pTabstopContext.reset();
423 defaultSize = CFX_SizeF(m_fMaxWidth, fLinePos);
424 return true;
425}
426
427bool CXFA_TextLayout::Layout(const CFX_SizeF& size, FX_FLOAT* fHeight) {
428 if (size.x < 1)
429 return false;
430
431 Unload();
432 m_pBreak.reset(CreateBreak(true));
433 if (m_pLoader) {
434 m_pLoader->m_iTotalLines = -1;
435 m_pLoader->m_iChar = 0;
436 }
437
438 m_iLines = 0;
439 FX_FLOAT fLinePos = 0;
440 Loader(size, fLinePos, true);
441 UpdateAlign(size.y, fLinePos);
442 m_pTabstopContext.reset();
443 if (fHeight)
444 *fHeight = fLinePos;
445 return true;
446}
447
448bool CXFA_TextLayout::Layout(int32_t iBlock) {
449 if (!m_pLoader || iBlock < 0 || iBlock >= CountBlocks())
450 return false;
451 if (m_pLoader->m_fWidth < 1)
452 return false;
453
454 m_pLoader->m_iTotalLines = -1;
455 m_iLines = 0;
456 FX_FLOAT fLinePos = 0;
457 CXFA_Node* pNode = nullptr;
458 CFX_SizeF szText(m_pLoader->m_fWidth, m_pLoader->m_fHeight);
459 int32_t iCount = m_Blocks.GetSize();
460 int32_t iBlocksHeightCount =
461 pdfium::CollectionSize<int32_t>(m_pLoader->m_BlocksHeight);
462 iBlocksHeightCount /= 2;
463 if (iBlock < iBlocksHeightCount)
464 return true;
465 if (iBlock == iBlocksHeightCount) {
466 Unload();
467 m_pBreak.reset(CreateBreak(true));
468 fLinePos = m_pLoader->m_fStartLineOffset;
469 for (int32_t i = 0; i < iBlocksHeightCount; i++)
470 fLinePos -= m_pLoader->m_BlocksHeight[i * 2 + 1];
471
472 m_pLoader->m_iChar = 0;
473 if (iCount > 1)
474 m_pLoader->m_iTotalLines = m_Blocks.ElementAt(iBlock * 2 + 1);
475
476 Loader(szText, fLinePos, true);
477 if (iCount == 0 && m_pLoader->m_fStartLineOffset < 0.1f)
478 UpdateAlign(szText.y, fLinePos);
479 } else if (m_pTextDataNode) {
480 iBlock *= 2;
481 if (iBlock < iCount - 2)
482 m_pLoader->m_iTotalLines = m_Blocks.ElementAt(iBlock + 1);
483
484 m_pBreak->Reset();
485 if (m_bRichText) {
486 CFDE_XMLNode* pContainerNode = GetXMLContainerNode();
487 if (!pContainerNode)
488 return true;
489
490 CFDE_XMLNode* pXMLNode = m_pLoader->m_pXMLNode;
491 if (!pXMLNode)
492 return true;
493
494 CFDE_XMLNode* pSaveXMLNode = m_pLoader->m_pXMLNode;
495 for (; pXMLNode;
496 pXMLNode = pXMLNode->GetNodeItem(CFDE_XMLNode::NextSibling)) {
497 if (!LoadRichText(pXMLNode, szText, fLinePos, m_pLoader->m_pParentStyle,
498 true)) {
499 break;
500 }
501 }
502 while (!pXMLNode) {
503 pXMLNode = pSaveXMLNode->GetNodeItem(CFDE_XMLNode::Parent);
504 if (pXMLNode == pContainerNode)
505 break;
506 if (!LoadRichText(pXMLNode, szText, fLinePos, m_pLoader->m_pParentStyle,
507 true, nullptr, false)) {
508 break;
509 }
510 pSaveXMLNode = pXMLNode;
511 pXMLNode = pXMLNode->GetNodeItem(CFDE_XMLNode::NextSibling);
512 if (!pXMLNode)
513 continue;
514 for (; pXMLNode;
515 pXMLNode = pXMLNode->GetNodeItem(CFDE_XMLNode::NextSibling)) {
516 if (!LoadRichText(pXMLNode, szText, fLinePos,
517 m_pLoader->m_pParentStyle, true)) {
518 break;
519 }
520 }
521 }
522 } else {
523 pNode = m_pLoader->m_pNode;
524 if (!pNode)
525 return true;
526 LoadText(pNode, szText, fLinePos, true);
527 }
528 }
529 if (iBlock == iCount) {
530 m_pTabstopContext.reset();
531 m_pLoader.reset();
532 }
533 return true;
534}
535
536void CXFA_TextLayout::ItemBlocks(const CFX_RectF& rtText, int32_t iBlockIndex) {
537 if (!m_pLoader)
538 return;
539
540 int32_t iCountHeight = m_pLoader->m_lineHeights.GetSize();
541 if (iCountHeight == 0)
542 return;
543
544 bool bEndItem = true;
545 int32_t iBlockCount = m_Blocks.GetSize();
546 FX_FLOAT fLinePos = m_pLoader->m_fStartLineOffset;
547 int32_t iLineIndex = 0;
548 if (iBlockIndex > 0) {
549 int32_t iBlockHeightCount =
550 pdfium::CollectionSize<int32_t>(m_pLoader->m_BlocksHeight);
551 iBlockHeightCount /= 2;
552 if (iBlockHeightCount >= iBlockIndex) {
553 for (int32_t i = 0; i < iBlockIndex; i++)
554 fLinePos -= m_pLoader->m_BlocksHeight[i * 2 + 1];
555 } else {
556 fLinePos = 0;
557 }
558 iLineIndex = m_Blocks[iBlockCount - 1] + m_Blocks[iBlockCount - 2];
559 }
560
561 int32_t i = 0;
562 for (i = iLineIndex; i < iCountHeight; i++) {
563 FX_FLOAT fLineHeight = m_pLoader->m_lineHeights.ElementAt(i);
564 if (fLinePos + fLineHeight - rtText.height > 0.001) {
565 m_Blocks.Add(iLineIndex);
566 m_Blocks.Add(i - iLineIndex);
567 bEndItem = false;
568 break;
569 }
570 fLinePos += fLineHeight;
571 }
572 if (iCountHeight > 0 && (i - iLineIndex) > 0 && bEndItem) {
573 m_Blocks.Add(iLineIndex);
574 m_Blocks.Add(i - iLineIndex);
575 }
576}
577
578bool CXFA_TextLayout::DrawString(CFX_RenderDevice* pFxDevice,
579 const CFX_Matrix& tmDoc2Device,
580 const CFX_RectF& rtClip,
581 int32_t iBlock) {
582 if (!pFxDevice)
583 return false;
584
585 std::unique_ptr<CFDE_RenderDevice> pDevice(
586 new CFDE_RenderDevice(pFxDevice, false));
587 pDevice->SaveState();
588 pDevice->SetClipRect(rtClip);
589
590 auto pSolidBrush = pdfium::MakeUnique<CFDE_Brush>();
591 auto pPen = pdfium::MakeUnique<CFDE_Pen>();
592 if (m_pieceLines.GetSize() == 0) {
593 int32_t iBlockCount = CountBlocks();
594 for (int32_t i = 0; i < iBlockCount; i++)
595 Layout(i);
596 }
597
598 FXTEXT_CHARPOS* pCharPos = nullptr;
599 int32_t iCharCount = 0;
600 int32_t iLineStart = 0;
601 int32_t iPieceLines = m_pieceLines.GetSize();
602 int32_t iCount = m_Blocks.GetSize();
603 if (iCount > 0) {
604 iBlock *= 2;
605 if (iBlock < iCount) {
606 iLineStart = m_Blocks.ElementAt(iBlock);
607 iPieceLines = m_Blocks.ElementAt(iBlock + 1);
608 } else {
609 iPieceLines = 0;
610 }
611 }
612
613 for (int32_t i = 0; i < iPieceLines; i++) {
614 if (i + iLineStart >= m_pieceLines.GetSize())
615 break;
616
617 CXFA_PieceLine* pPieceLine = m_pieceLines.GetAt(i + iLineStart);
618 int32_t iPieces = pPieceLine->m_textPieces.GetSize();
619 int32_t j = 0;
620 for (j = 0; j < iPieces; j++) {
621 const XFA_TextPiece* pPiece = pPieceLine->m_textPieces.GetAt(j);
622 int32_t iChars = pPiece->iChars;
623 if (iCharCount < iChars) {
624 FX_Free(pCharPos);
625 pCharPos = FX_Alloc(FXTEXT_CHARPOS, iChars);
626 iCharCount = iChars;
627 }
628 FXSYS_memset(pCharPos, 0, iCharCount * sizeof(FXTEXT_CHARPOS));
629 RenderString(pDevice.get(), pSolidBrush.get(), pPieceLine, j, pCharPos,
630 tmDoc2Device);
631 }
632 for (j = 0; j < iPieces; j++) {
633 RenderPath(pDevice.get(), pPen.get(), pPieceLine, j, pCharPos,
634 tmDoc2Device);
635 }
636 }
637 pDevice->RestoreState();
638 FX_Free(pCharPos);
639 return iPieceLines > 0;
640}
641
642void CXFA_TextLayout::UpdateAlign(FX_FLOAT fHeight, FX_FLOAT fBottom) {
643 fHeight -= fBottom;
644 if (fHeight < 0.1f)
645 return;
646
647 switch (m_textParser.GetVAlign(m_pTextProvider)) {
648 case XFA_ATTRIBUTEENUM_Middle:
649 fHeight /= 2.0f;
650 break;
651 case XFA_ATTRIBUTEENUM_Bottom:
652 break;
653 default:
654 return;
655 }
656
657 int32_t iCount = m_pieceLines.GetSize();
658 for (int32_t i = 0; i < iCount; i++) {
659 CXFA_PieceLine* pPieceLine = m_pieceLines.GetAt(i);
660 int32_t iPieces = pPieceLine->m_textPieces.GetSize();
661 for (int32_t j = 0; j < iPieces; j++) {
662 XFA_TextPiece* pPiece = pPieceLine->m_textPieces.GetAt(j);
663 CFX_RectF& rect = pPiece->rtPiece;
664 rect.top += fHeight;
665 }
666 }
667}
668
669bool CXFA_TextLayout::Loader(const CFX_SizeF& szText,
670 FX_FLOAT& fLinePos,
671 bool bSavePieces) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500672 GetTextDataNode();
673 if (!m_pTextDataNode)
674 return true;
675
676 if (m_bRichText) {
677 CFDE_XMLNode* pXMLContainer = GetXMLContainerNode();
678 if (pXMLContainer) {
679 if (!m_textParser.IsParsed())
680 m_textParser.DoParse(pXMLContainer, m_pTextProvider);
681
682 IFDE_CSSComputedStyle* pRootStyle =
683 m_textParser.CreateRootStyle(m_pTextProvider);
684 LoadRichText(pXMLContainer, szText, fLinePos, pRootStyle, bSavePieces);
685 pRootStyle->Release();
686 }
687 } else {
688 LoadText(m_pTextDataNode, szText, fLinePos, bSavePieces);
689 }
690 return true;
691}
692
693void CXFA_TextLayout::LoadText(CXFA_Node* pNode,
694 const CFX_SizeF& szText,
695 FX_FLOAT& fLinePos,
696 bool bSavePieces) {
697 InitBreak(szText.x);
698
699 CXFA_Para para = m_pTextProvider->GetParaNode();
700 FX_FLOAT fSpaceAbove = 0;
701 if (para) {
702 fSpaceAbove = para.GetSpaceAbove();
703 if (fSpaceAbove < 0.1f) {
704 fSpaceAbove = 0;
705 }
706 int32_t verAlign = para.GetVerticalAlign();
707 switch (verAlign) {
708 case XFA_ATTRIBUTEENUM_Top:
709 case XFA_ATTRIBUTEENUM_Middle:
710 case XFA_ATTRIBUTEENUM_Bottom: {
711 fLinePos += fSpaceAbove;
712 break;
713 }
714 }
715 }
716
717 CFX_WideString wsText = pNode->GetContent();
718 wsText.TrimRight(L" ");
719 bool bRet = AppendChar(wsText, fLinePos, fSpaceAbove, bSavePieces);
720 if (bRet && m_pLoader)
721 m_pLoader->m_pNode = pNode;
722 else
723 EndBreak(FX_RTFBREAK_ParagraphBreak, fLinePos, bSavePieces);
724}
725
726bool CXFA_TextLayout::LoadRichText(CFDE_XMLNode* pXMLNode,
727 const CFX_SizeF& szText,
728 FX_FLOAT& fLinePos,
729 IFDE_CSSComputedStyle* pParentStyle,
730 bool bSavePieces,
731 CXFA_LinkUserData* pLinkData,
732 bool bEndBreak,
733 bool bIsOl,
734 int32_t iLiCount) {
735 if (!pXMLNode)
736 return false;
737
738 CXFA_TextParseContext* pContext =
739 m_textParser.GetParseContextFromMap(pXMLNode);
Dan Sinclair96f482c2017-01-11 16:31:27 -0500740 FDE_CSSDisplay eDisplay = FDE_CSSDisplay::None;
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500741 bool bContentNode = false;
742 FX_FLOAT fSpaceBelow = 0;
743 IFDE_CSSComputedStyle* pStyle = nullptr;
744 CFX_WideString wsName;
745 if (bEndBreak) {
746 bool bCurOl = false;
747 bool bCurLi = false;
748 CFDE_XMLElement* pElement = nullptr;
749 if (pContext) {
750 if (m_bBlockContinue ||
751 (m_pLoader && pXMLNode == m_pLoader->m_pXMLNode)) {
752 m_bBlockContinue = true;
753 }
754 if (pXMLNode->GetType() == FDE_XMLNODE_Text) {
755 bContentNode = true;
756 } else if (pXMLNode->GetType() == FDE_XMLNODE_Element) {
757 pElement = static_cast<CFDE_XMLElement*>(pXMLNode);
758 pElement->GetLocalTagName(wsName);
759 }
760 if (wsName == FX_WSTRC(L"ol")) {
761 bIsOl = true;
762 bCurOl = true;
763 }
764 if (m_bBlockContinue || bContentNode == false) {
765 eDisplay = pContext->GetDisplay();
Dan Sinclair96f482c2017-01-11 16:31:27 -0500766 if (eDisplay != FDE_CSSDisplay::Block &&
767 eDisplay != FDE_CSSDisplay::Inline &&
768 eDisplay != FDE_CSSDisplay::ListItem) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500769 return true;
770 }
771
772 pStyle = m_textParser.ComputeStyle(pXMLNode, pParentStyle);
773 InitBreak(bContentNode ? pParentStyle : pStyle, eDisplay, szText.x,
774 pXMLNode, pParentStyle);
Dan Sinclair96f482c2017-01-11 16:31:27 -0500775 if ((eDisplay == FDE_CSSDisplay::Block ||
776 eDisplay == FDE_CSSDisplay::ListItem) &&
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500777 pStyle &&
778 (wsName.IsEmpty() ||
779 (wsName != FX_WSTRC(L"body") && wsName != FX_WSTRC(L"html") &&
780 wsName != FX_WSTRC(L"ol") && wsName != FX_WSTRC(L"ul")))) {
781 const FDE_CSSRECT* pRect =
782 pStyle->GetBoundaryStyles()->GetMarginWidth();
783 if (pRect) {
784 fLinePos += pRect->top.GetValue();
785 fSpaceBelow = pRect->bottom.GetValue();
786 }
787 }
788
789 if (wsName == FX_WSTRC(L"a")) {
790 CFX_WideString wsLinkContent;
791 ASSERT(pElement);
792 pElement->GetString(L"href", wsLinkContent);
793 if (!wsLinkContent.IsEmpty()) {
Dan Sinclair0cb9b8c2017-01-10 16:38:10 -0500794 pLinkData = new CXFA_LinkUserData(
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500795 wsLinkContent.GetBuffer(wsLinkContent.GetLength()));
796 wsLinkContent.ReleaseBuffer(wsLinkContent.GetLength());
797 }
798 }
799
800 int32_t iTabCount =
801 m_textParser.CountTabs(bContentNode ? pParentStyle : pStyle);
802 bool bSpaceRun =
803 m_textParser.IsSpaceRun(bContentNode ? pParentStyle : pStyle);
804 CFX_WideString wsText;
805 if (bContentNode && iTabCount == 0) {
806 static_cast<CFDE_XMLText*>(pXMLNode)->GetText(wsText);
807 } else if (wsName == FX_WSTRC(L"br")) {
808 wsText = L'\n';
809 } else if (wsName == FX_WSTRC(L"li")) {
810 bCurLi = true;
811 if (bIsOl)
812 wsText.Format(L"%d. ", iLiCount);
813 else
814 wsText = 0x00B7 + FX_WSTRC(L" ");
815 } else if (!bContentNode) {
816 if (iTabCount > 0) {
817 while (iTabCount-- > 0)
818 wsText += L'\t';
819 } else {
820 m_textParser.GetEmbbedObj(m_pTextProvider, pXMLNode, wsText);
821 }
822 }
823
824 int32_t iLength = wsText.GetLength();
825 if (iLength > 0 && bContentNode && !bSpaceRun)
826 ProcessText(wsText);
827
828 if (m_pLoader) {
829 if (wsText.GetLength() > 0 &&
830 (m_pLoader->m_dwFlags & XFA_LOADERCNTXTFLG_FILTERSPACE)) {
831 wsText.TrimLeft(0x20);
832 }
Dan Sinclair96f482c2017-01-11 16:31:27 -0500833 if (FDE_CSSDisplay::Block == eDisplay) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500834 m_pLoader->m_dwFlags |= XFA_LOADERCNTXTFLG_FILTERSPACE;
Dan Sinclair96f482c2017-01-11 16:31:27 -0500835 } else if (FDE_CSSDisplay::Inline == eDisplay &&
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500836 (m_pLoader->m_dwFlags & XFA_LOADERCNTXTFLG_FILTERSPACE)) {
837 m_pLoader->m_dwFlags &= ~XFA_LOADERCNTXTFLG_FILTERSPACE;
838 } else if (wsText.GetLength() > 0 &&
839 (0x20 == wsText.GetAt(wsText.GetLength() - 1))) {
840 m_pLoader->m_dwFlags |= XFA_LOADERCNTXTFLG_FILTERSPACE;
841 } else if (wsText.GetLength() != 0) {
842 m_pLoader->m_dwFlags &= ~XFA_LOADERCNTXTFLG_FILTERSPACE;
843 }
844 }
845
846 if (wsText.GetLength() > 0) {
847 if (!m_pLoader || m_pLoader->m_iChar == 0) {
848 if (pLinkData)
849 pLinkData->Retain();
850
Dan Sinclair0cb9b8c2017-01-10 16:38:10 -0500851 CXFA_TextUserData* pUserData = new CXFA_TextUserData(
852 bContentNode ? pParentStyle : pStyle, pLinkData);
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500853 m_pBreak->SetUserData(pUserData);
854 }
855
856 if (AppendChar(wsText, fLinePos, 0, bSavePieces)) {
857 if (m_pLoader)
858 m_pLoader->m_dwFlags &= ~XFA_LOADERCNTXTFLG_FILTERSPACE;
859 if (IsEnd(bSavePieces)) {
860 if (m_pLoader && m_pLoader->m_iTotalLines > -1) {
861 m_pLoader->m_pXMLNode = pXMLNode;
862 m_pLoader->m_pParentStyle = pParentStyle;
863 }
864 if (pStyle)
865 pStyle->Release();
866 return false;
867 }
868 return true;
869 }
870 }
871 }
872 }
873
874 for (CFDE_XMLNode* pChildNode =
875 pXMLNode->GetNodeItem(CFDE_XMLNode::FirstChild);
876 pChildNode;
877 pChildNode = pChildNode->GetNodeItem(CFDE_XMLNode::NextSibling)) {
878 if (bCurOl)
879 iLiCount++;
880
881 if (!LoadRichText(pChildNode, szText, fLinePos,
882 pContext ? pStyle : pParentStyle, bSavePieces,
883 pLinkData, true, bIsOl, iLiCount))
884 return false;
885 }
886
887 if (m_pLoader) {
Dan Sinclair96f482c2017-01-11 16:31:27 -0500888 if (FDE_CSSDisplay::Block == eDisplay)
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500889 m_pLoader->m_dwFlags |= XFA_LOADERCNTXTFLG_FILTERSPACE;
890 }
891 if (bCurLi)
892 EndBreak(FX_RTFBREAK_LineBreak, fLinePos, bSavePieces);
893 } else {
894 if (pContext)
895 eDisplay = pContext->GetDisplay();
896 }
897
898 if (m_bBlockContinue) {
899 if (pContext && !bContentNode) {
Dan Sinclair96f482c2017-01-11 16:31:27 -0500900 uint32_t dwStatus = (eDisplay == FDE_CSSDisplay::Block)
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500901 ? FX_RTFBREAK_ParagraphBreak
902 : FX_RTFBREAK_PieceBreak;
903 EndBreak(dwStatus, fLinePos, bSavePieces);
Dan Sinclair96f482c2017-01-11 16:31:27 -0500904 if (eDisplay == FDE_CSSDisplay::Block) {
Dan Sinclair1f5d4982017-01-10 16:37:32 -0500905 fLinePos += fSpaceBelow;
906 if (m_pTabstopContext)
907 m_pTabstopContext->RemoveAll();
908 }
909 if (wsName == FX_WSTRC(L"a")) {
910 if (pLinkData) {
911 pLinkData->Release();
912 pLinkData = nullptr;
913 }
914 }
915 if (IsEnd(bSavePieces)) {
916 if (pStyle)
917 pStyle->Release();
918
919 if (m_pLoader && m_pLoader->m_iTotalLines > -1) {
920 m_pLoader->m_pXMLNode =
921 pXMLNode->GetNodeItem(CFDE_XMLNode::NextSibling);
922 m_pLoader->m_pParentStyle = pParentStyle;
923 }
924 return false;
925 }
926 }
927 }
928 if (pStyle)
929 pStyle->Release();
930
931 return true;
932}
933
934bool CXFA_TextLayout::AppendChar(const CFX_WideString& wsText,
935 FX_FLOAT& fLinePos,
936 FX_FLOAT fSpaceAbove,
937 bool bSavePieces) {
938 uint32_t dwStatus = 0;
939 int32_t iChar = 0;
940 if (m_pLoader)
941 iChar = m_pLoader->m_iChar;
942
943 int32_t iLength = wsText.GetLength();
944 for (int32_t i = iChar; i < iLength; i++) {
945 FX_WCHAR wch = wsText.GetAt(i);
946 if (wch == 0xA0)
947 wch = 0x20;
948
949 if ((dwStatus = m_pBreak->AppendChar(wch)) > FX_RTFBREAK_PieceBreak) {
950 AppendTextLine(dwStatus, fLinePos, bSavePieces);
951 if (IsEnd(bSavePieces)) {
952 if (m_pLoader)
953 m_pLoader->m_iChar = i;
954 return true;
955 }
956 if (dwStatus == FX_RTFBREAK_ParagraphBreak && m_bRichText)
957 fLinePos += fSpaceAbove;
958 }
959 }
960 if (m_pLoader)
961 m_pLoader->m_iChar = 0;
962
963 return false;
964}
965
966bool CXFA_TextLayout::IsEnd(bool bSavePieces) {
967 if (!bSavePieces)
968 return false;
969 if (m_pLoader && m_pLoader->m_iTotalLines > 0)
970 return m_iLines >= m_pLoader->m_iTotalLines;
971 return false;
972}
973
974void CXFA_TextLayout::ProcessText(CFX_WideString& wsText) {
975 int32_t iLen = wsText.GetLength();
976 if (iLen == 0)
977 return;
978
979 FX_WCHAR* psz = wsText.GetBuffer(iLen);
980 int32_t iTrimLeft = 0;
981 FX_WCHAR wch = 0, wPrev = 0;
982 for (int32_t i = 0; i < iLen; i++) {
983 wch = psz[i];
984 if (wch < 0x20)
985 wch = 0x20;
986 if (wch == 0x20 && wPrev == 0x20)
987 continue;
988
989 wPrev = wch;
990 psz[iTrimLeft++] = wch;
991 }
992 wsText.ReleaseBuffer(iLen);
993 wsText = wsText.Left(iTrimLeft);
994}
995
996void CXFA_TextLayout::EndBreak(uint32_t dwStatus,
997 FX_FLOAT& fLinePos,
998 bool bSavePieces) {
999 dwStatus = m_pBreak->EndBreak(dwStatus);
1000 if (dwStatus > FX_RTFBREAK_PieceBreak)
1001 AppendTextLine(dwStatus, fLinePos, bSavePieces, true);
1002}
1003
1004void CXFA_TextLayout::DoTabstops(IFDE_CSSComputedStyle* pStyle,
1005 CXFA_PieceLine* pPieceLine) {
1006 if (!m_pTabstopContext || m_pTabstopContext->m_iTabCount == 0)
1007 return;
1008 if (!pStyle || !pPieceLine)
1009 return;
1010
1011 int32_t iPieces = pPieceLine->m_textPieces.GetSize();
1012 if (iPieces == 0)
1013 return;
1014
1015 XFA_TextPiece* pPiece = pPieceLine->m_textPieces.GetAt(iPieces - 1);
1016 int32_t& iTabstopsIndex = m_pTabstopContext->m_iTabIndex;
1017 int32_t iCount = m_textParser.CountTabs(pStyle);
1018 if (iTabstopsIndex > m_pTabstopContext->m_iTabCount - 1)
1019 return;
1020
1021 if (iCount > 0) {
1022 iTabstopsIndex++;
1023 m_pTabstopContext->m_bTabstops = true;
1024 FX_FLOAT fRight = 0;
1025 if (iPieces > 1) {
1026 XFA_TextPiece* p = pPieceLine->m_textPieces.GetAt(iPieces - 2);
1027 fRight = p->rtPiece.right();
1028 }
1029 m_pTabstopContext->m_fTabWidth =
1030 pPiece->rtPiece.width + pPiece->rtPiece.left - fRight;
1031 } else if (iTabstopsIndex > -1) {
1032 FX_FLOAT fLeft = 0;
1033 if (m_pTabstopContext->m_bTabstops) {
1034 XFA_TABSTOPS* pTabstops =
1035 m_pTabstopContext->m_tabstops.GetDataPtr(iTabstopsIndex);
1036 uint32_t dwAlign = pTabstops->dwAlign;
1037 if (dwAlign == FX_HashCode_GetW(L"center", false)) {
1038 fLeft = pPiece->rtPiece.width / 2.0f;
1039 } else if (dwAlign == FX_HashCode_GetW(L"right", false) ||
1040 dwAlign == FX_HashCode_GetW(L"before", false)) {
1041 fLeft = pPiece->rtPiece.width;
1042 } else if (dwAlign == FX_HashCode_GetW(L"decimal", false)) {
1043 int32_t iChars = pPiece->iChars;
1044 for (int32_t i = 0; i < iChars; i++) {
1045 if (pPiece->pszText[i] == L'.')
1046 break;
1047
1048 fLeft += pPiece->pWidths[i] / 20000.0f;
1049 }
1050 }
1051 m_pTabstopContext->m_fLeft =
1052 std::min(fLeft, m_pTabstopContext->m_fTabWidth);
1053 m_pTabstopContext->m_bTabstops = false;
1054 m_pTabstopContext->m_fTabWidth = 0;
1055 }
1056 pPiece->rtPiece.left -= m_pTabstopContext->m_fLeft;
1057 }
1058}
1059
1060void CXFA_TextLayout::AppendTextLine(uint32_t dwStatus,
1061 FX_FLOAT& fLinePos,
1062 bool bSavePieces,
1063 bool bEndBreak) {
1064 int32_t iPieces = m_pBreak->CountBreakPieces();
1065 if (iPieces < 1)
1066 return;
1067
1068 IFDE_CSSComputedStyle* pStyle = nullptr;
1069 if (bSavePieces) {
Dan Sinclair0cb9b8c2017-01-10 16:38:10 -05001070 CXFA_PieceLine* pPieceLine = new CXFA_PieceLine;
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001071 m_pieceLines.Add(pPieceLine);
1072 if (m_pTabstopContext)
1073 m_pTabstopContext->Reset();
1074
1075 FX_FLOAT fLineStep = 0, fBaseLine = 0;
1076 int32_t i = 0;
1077 for (i = 0; i < iPieces; i++) {
1078 const CFX_RTFPiece* pPiece = m_pBreak->GetBreakPiece(i);
1079 CXFA_TextUserData* pUserData = (CXFA_TextUserData*)pPiece->m_pUserData;
1080 if (pUserData)
1081 pStyle = pUserData->m_pStyle;
1082 FX_FLOAT fVerScale = pPiece->m_iVerticalScale / 100.0f;
1083
Dan Sinclair0cb9b8c2017-01-10 16:38:10 -05001084 XFA_TextPiece* pTP = new XFA_TextPiece();
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001085 pTP->pszText =
Dan Sinclair0cb9b8c2017-01-10 16:38:10 -05001086 (FX_WCHAR*)FX_Alloc(uint8_t, pPiece->m_iChars * sizeof(FX_WCHAR));
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001087 pTP->pWidths =
Dan Sinclair0cb9b8c2017-01-10 16:38:10 -05001088 (int32_t*)FX_Alloc(uint8_t, pPiece->m_iChars * sizeof(int32_t));
Dan Sinclair1f5d4982017-01-10 16:37:32 -05001089 pTP->iChars = pPiece->m_iChars;
1090 pPiece->GetString(pTP->pszText);
1091 pPiece->GetWidths(pTP->pWidths);
1092 pTP->iBidiLevel = pPiece->m_iBidiLevel;
1093 pTP->iHorScale = pPiece->m_iHorizontalScale;
1094 pTP->iVerScale = pPiece->m_iVerticalScale;
1095 m_textParser.GetUnderline(m_pTextProvider, pStyle, pTP->iUnderline,
1096 pTP->iPeriod);
1097 m_textParser.GetLinethrough(m_pTextProvider, pStyle, pTP->iLineThrough);
1098 pTP->dwColor = m_textParser.GetColor(m_pTextProvider, pStyle);
1099 pTP->pFont = m_textParser.GetFont(m_pTextProvider, pStyle);
1100 pTP->fFontSize = m_textParser.GetFontSize(m_pTextProvider, pStyle);
1101 pTP->rtPiece.left = pPiece->m_iStartPos / 20000.0f;
1102 pTP->rtPiece.width = pPiece->m_iWidth / 20000.0f;
1103 pTP->rtPiece.height = (FX_FLOAT)pPiece->m_iFontSize * fVerScale / 20.0f;
1104 FX_FLOAT fBaseLineTemp =
1105 m_textParser.GetBaseline(m_pTextProvider, pStyle);
1106 pTP->rtPiece.top = fBaseLineTemp;
1107 pPieceLine->m_textPieces.Add(pTP);
1108
1109 FX_FLOAT fLineHeight = m_textParser.GetLineHeight(
1110 m_pTextProvider, pStyle, m_iLines == 0, fVerScale);
1111 if (fBaseLineTemp > 0) {
1112 FX_FLOAT fLineHeightTmp = fBaseLineTemp + pTP->rtPiece.height;
1113 if (fLineHeight < fLineHeightTmp)
1114 fLineHeight = fLineHeightTmp;
1115 else
1116 fBaseLineTemp = 0;
1117 } else if (fBaseLine < -fBaseLineTemp) {
1118 fBaseLine = -fBaseLineTemp;
1119 }
1120 fLineStep = std::max(fLineStep, fLineHeight);
1121 if (pUserData && pUserData->m_pLinkData) {
1122 pUserData->m_pLinkData->Retain();
1123 pTP->pLinkData = pUserData->m_pLinkData;
1124 } else {
1125 pTP->pLinkData = nullptr;
1126 }
1127 DoTabstops(pStyle, pPieceLine);
1128 }
1129 for (i = 0; i < iPieces; i++) {
1130 XFA_TextPiece* pTP = pPieceLine->m_textPieces.GetAt(i);
1131 FX_FLOAT& fTop = pTP->rtPiece.top;
1132 FX_FLOAT fBaseLineTemp = fTop;
1133 fTop = fLinePos + fLineStep - pTP->rtPiece.height - fBaseLineTemp;
1134 fTop = std::max(0.0f, fTop);
1135 }
1136 fLinePos += fLineStep + fBaseLine;
1137 } else {
1138 FX_FLOAT fLineStep = 0;
1139 FX_FLOAT fLineWidth = 0;
1140 for (int32_t i = 0; i < iPieces; i++) {
1141 const CFX_RTFPiece* pPiece = m_pBreak->GetBreakPiece(i);
1142 CXFA_TextUserData* pUserData = (CXFA_TextUserData*)pPiece->m_pUserData;
1143 if (pUserData)
1144 pStyle = pUserData->m_pStyle;
1145 FX_FLOAT fVerScale = pPiece->m_iVerticalScale / 100.0f;
1146 FX_FLOAT fBaseLine = m_textParser.GetBaseline(m_pTextProvider, pStyle);
1147 FX_FLOAT fLineHeight = m_textParser.GetLineHeight(
1148 m_pTextProvider, pStyle, m_iLines == 0, fVerScale);
1149 if (fBaseLine > 0) {
1150 FX_FLOAT fLineHeightTmp =
1151 fBaseLine + (FX_FLOAT)pPiece->m_iFontSize * fVerScale / 20.0f;
1152 if (fLineHeight < fLineHeightTmp) {
1153 fLineHeight = fLineHeightTmp;
1154 }
1155 }
1156 fLineStep = std::max(fLineStep, fLineHeight);
1157 fLineWidth += pPiece->m_iWidth / 20000.0f;
1158 }
1159 fLinePos += fLineStep;
1160 m_fMaxWidth = std::max(m_fMaxWidth, fLineWidth);
1161 if (m_pLoader && m_pLoader->m_bSaveLineHeight) {
1162 FX_FLOAT fHeight = fLinePos - m_pLoader->m_fLastPos;
1163 m_pLoader->m_fLastPos = fLinePos;
1164 m_pLoader->m_lineHeights.Add(fHeight);
1165 }
1166 }
1167 if (pStyle)
1168 pStyle->Retain();
1169
1170 m_pBreak->ClearBreakPieces();
1171 if (dwStatus == FX_RTFBREAK_ParagraphBreak) {
1172 m_pBreak->Reset();
1173 if (!pStyle && bEndBreak) {
1174 CXFA_Para para = m_pTextProvider->GetParaNode();
1175 if (para) {
1176 FX_FLOAT fStartPos = para.GetMarginLeft();
1177 FX_FLOAT fIndent = para.GetTextIndent();
1178 if (fIndent > 0)
1179 fStartPos += fIndent;
1180
1181 FX_FLOAT fSpaceBelow = para.GetSpaceBelow();
1182 if (fSpaceBelow < 0.1f)
1183 fSpaceBelow = 0;
1184
1185 m_pBreak->SetLineStartPos(fStartPos);
1186 fLinePos += fSpaceBelow;
1187 }
1188 }
1189 }
1190
1191 if (pStyle) {
1192 FX_FLOAT fStart = 0;
1193 const FDE_CSSRECT* pRect = pStyle->GetBoundaryStyles()->GetMarginWidth();
1194 if (pRect)
1195 fStart = pRect->left.GetValue();
1196
1197 FX_FLOAT fTextIndent =
1198 pStyle->GetParagraphStyles()->GetTextIndent().GetValue();
1199 if (fTextIndent < 0)
1200 fStart -= fTextIndent;
1201
1202 m_pBreak->SetLineStartPos(fStart);
1203 pStyle->Release();
1204 }
1205 m_iLines++;
1206}
1207
1208void CXFA_TextLayout::RenderString(CFDE_RenderDevice* pDevice,
1209 CFDE_Brush* pBrush,
1210 CXFA_PieceLine* pPieceLine,
1211 int32_t iPiece,
1212 FXTEXT_CHARPOS* pCharPos,
1213 const CFX_Matrix& tmDoc2Device) {
1214 const XFA_TextPiece* pPiece = pPieceLine->m_textPieces.GetAt(iPiece);
1215 int32_t iCount = GetDisplayPos(pPiece, pCharPos);
1216 if (iCount > 0) {
1217 pBrush->SetColor(pPiece->dwColor);
1218 pDevice->DrawString(pBrush, pPiece->pFont, pCharPos, iCount,
1219 pPiece->fFontSize, &tmDoc2Device);
1220 }
1221 pPieceLine->m_charCounts.Add(iCount);
1222}
1223
1224void CXFA_TextLayout::RenderPath(CFDE_RenderDevice* pDevice,
1225 CFDE_Pen* pPen,
1226 CXFA_PieceLine* pPieceLine,
1227 int32_t iPiece,
1228 FXTEXT_CHARPOS* pCharPos,
1229 const CFX_Matrix& tmDoc2Device) {
1230 XFA_TextPiece* pPiece = pPieceLine->m_textPieces.GetAt(iPiece);
1231 bool bNoUnderline = pPiece->iUnderline < 1 || pPiece->iUnderline > 2;
1232 bool bNoLineThrough = pPiece->iLineThrough < 1 || pPiece->iLineThrough > 2;
1233 if (bNoUnderline && bNoLineThrough)
1234 return;
1235
1236 pPen->SetColor(pPiece->dwColor);
1237 std::unique_ptr<CFDE_Path> pPath(new CFDE_Path);
1238 int32_t iChars = GetDisplayPos(pPiece, pCharPos);
1239 if (iChars > 0) {
1240 CFX_PointF pt1, pt2;
1241 FX_FLOAT fEndY = pCharPos[0].m_OriginY + 1.05f;
1242 if (pPiece->iPeriod == XFA_ATTRIBUTEENUM_Word) {
1243 for (int32_t i = 0; i < pPiece->iUnderline; i++) {
1244 for (int32_t j = 0; j < iChars; j++) {
1245 pt1.x = pCharPos[j].m_OriginX;
1246 pt2.x =
1247 pt1.x + pCharPos[j].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
1248 pt1.y = pt2.y = fEndY;
1249 pPath->AddLine(pt1, pt2);
1250 }
1251 fEndY += 2.0f;
1252 }
1253 } else {
1254 pt1.x = pCharPos[0].m_OriginX;
1255 pt2.x =
1256 pCharPos[iChars - 1].m_OriginX +
1257 pCharPos[iChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
1258 for (int32_t i = 0; i < pPiece->iUnderline; i++) {
1259 pt1.y = pt2.y = fEndY;
1260 pPath->AddLine(pt1, pt2);
1261 fEndY += 2.0f;
1262 }
1263 }
1264 fEndY = pCharPos[0].m_OriginY - pPiece->rtPiece.height * 0.25f;
1265 pt1.x = pCharPos[0].m_OriginX;
1266 pt2.x = pCharPos[iChars - 1].m_OriginX +
1267 pCharPos[iChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
1268 for (int32_t i = 0; i < pPiece->iLineThrough; i++) {
1269 pt1.y = pt2.y = fEndY;
1270 pPath->AddLine(pt1, pt2);
1271 fEndY += 2.0f;
1272 }
1273 } else {
1274 if (bNoLineThrough &&
1275 (bNoUnderline || pPiece->iPeriod != XFA_ATTRIBUTEENUM_All)) {
1276 return;
1277 }
1278 int32_t iCharsTmp = 0;
1279 int32_t iPiecePrev = iPiece, iPieceNext = iPiece;
1280 while (iPiecePrev > 0) {
1281 iPiecePrev--;
1282 iCharsTmp = pPieceLine->m_charCounts.GetAt(iPiecePrev);
1283 if (iCharsTmp > 0)
1284 break;
1285 }
1286 if (iCharsTmp == 0)
1287 return;
1288
1289 iCharsTmp = 0;
1290 int32_t iPieces = pPieceLine->m_textPieces.GetSize();
1291 while (iPieceNext < iPieces - 1) {
1292 iPieceNext++;
1293 iCharsTmp = pPieceLine->m_charCounts.GetAt(iPieceNext);
1294 if (iCharsTmp > 0)
1295 break;
1296 }
1297 if (iCharsTmp == 0)
1298 return;
1299
1300 FX_FLOAT fOrgX = 0.0f;
1301 FX_FLOAT fEndX = 0.0f;
1302 pPiece = pPieceLine->m_textPieces.GetAt(iPiecePrev);
1303 iChars = GetDisplayPos(pPiece, pCharPos);
1304 if (iChars < 1)
1305 return;
1306
1307 fOrgX = pCharPos[iChars - 1].m_OriginX +
1308 pCharPos[iChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
1309 pPiece = pPieceLine->m_textPieces.GetAt(iPieceNext);
1310 iChars = GetDisplayPos(pPiece, pCharPos);
1311 if (iChars < 1)
1312 return;
1313
1314 fEndX = pCharPos[0].m_OriginX;
1315 CFX_PointF pt1, pt2;
1316 pt1.x = fOrgX, pt2.x = fEndX;
1317 FX_FLOAT fEndY = pCharPos[0].m_OriginY + 1.05f;
1318 for (int32_t i = 0; i < pPiece->iUnderline; i++) {
1319 pt1.y = pt2.y = fEndY;
1320 pPath->AddLine(pt1, pt2);
1321 fEndY += 2.0f;
1322 }
1323 fEndY = pCharPos[0].m_OriginY - pPiece->rtPiece.height * 0.25f;
1324 for (int32_t i = 0; i < pPiece->iLineThrough; i++) {
1325 pt1.y = pt2.y = fEndY;
1326 pPath->AddLine(pt1, pt2);
1327 fEndY += 2.0f;
1328 }
1329 }
1330 pDevice->DrawPath(pPen, 1, pPath.get(), &tmDoc2Device);
1331}
1332
1333int32_t CXFA_TextLayout::GetDisplayPos(const XFA_TextPiece* pPiece,
1334 FXTEXT_CHARPOS* pCharPos,
1335 bool bCharCode) {
1336 if (!pPiece)
1337 return 0;
1338
1339 FX_RTFTEXTOBJ tr;
1340 if (!ToRun(pPiece, tr))
1341 return 0;
1342 return m_pBreak->GetDisplayPos(&tr, pCharPos, bCharCode);
1343}
1344
1345bool CXFA_TextLayout::ToRun(const XFA_TextPiece* pPiece, FX_RTFTEXTOBJ& tr) {
1346 int32_t iLength = pPiece->iChars;
1347 if (iLength < 1)
1348 return false;
1349
1350 tr.pStr = pPiece->pszText;
1351 tr.pFont = pPiece->pFont;
1352 tr.pRect = &pPiece->rtPiece;
1353 tr.pWidths = pPiece->pWidths;
1354 tr.iLength = iLength;
1355 tr.fFontSize = pPiece->fFontSize;
1356 tr.iBidiLevel = pPiece->iBidiLevel;
1357 tr.iCharRotation = 0;
1358 tr.wLineBreakChar = L'\n';
1359 tr.iVerticalScale = pPiece->iVerScale;
1360 tr.dwLayoutStyles = FX_RTFLAYOUTSTYLE_ExpandTab;
1361 tr.iHorizontalScale = pPiece->iHorScale;
1362 return true;
1363}