1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "xfa/fgas/layout/cfx_rtfbreak.h"
8
9 #include <algorithm>
10
11 #include "build/build_config.h"
12 #include "core/fxcrt/fx_safe_types.h"
13 #include "core/fxge/text_char_pos.h"
14 #include "third_party/base/numerics/safe_math.h"
15 #include "third_party/base/stl_util.h"
16 #include "xfa/fgas/font/cfgas_gefont.h"
17 #include "xfa/fgas/layout/cfx_char.h"
18 #include "xfa/fgas/layout/cfx_textpiece.h"
19 #include "xfa/fgas/layout/cfx_textuserdata.h"
20 #include "xfa/fgas/layout/fx_arabic.h"
21 #include "xfa/fgas/layout/fx_linebreak.h"
22
CFX_RTFBreak(uint32_t dwLayoutStyles)23 CFX_RTFBreak::CFX_RTFBreak(uint32_t dwLayoutStyles)
24 : CFX_Break(dwLayoutStyles),
25 m_bPagination(false),
26 m_iAlignment(CFX_RTFLineAlignment::Left) {
27 SetBreakStatus();
28 m_bPagination = !!(m_dwLayoutStyles & FX_LAYOUTSTYLE_Pagination);
29 }
30
~CFX_RTFBreak()31 CFX_RTFBreak::~CFX_RTFBreak() {}
32
SetLineStartPos(float fLinePos)33 void CFX_RTFBreak::SetLineStartPos(float fLinePos) {
34 int32_t iLinePos = FXSYS_roundf(fLinePos * kConversionFactor);
35 iLinePos = std::min(iLinePos, m_iLineWidth);
36 iLinePos = std::max(iLinePos, m_iLineStart);
37 m_pCurLine->m_iStart = iLinePos;
38 }
39
AddPositionedTab(float fTabPos)40 void CFX_RTFBreak::AddPositionedTab(float fTabPos) {
41 int32_t iTabPos = std::min(
42 FXSYS_roundf(fTabPos * kConversionFactor) + m_iLineStart, m_iLineWidth);
43 auto it = std::lower_bound(m_PositionedTabs.begin(), m_PositionedTabs.end(),
44 iTabPos);
45 if (it != m_PositionedTabs.end() && *it == iTabPos)
46 return;
47 m_PositionedTabs.insert(it, iTabPos);
48 }
49
SetUserData(const RetainPtr<CFX_TextUserData> & pUserData)50 void CFX_RTFBreak::SetUserData(const RetainPtr<CFX_TextUserData>& pUserData) {
51 if (m_pUserData == pUserData)
52 return;
53
54 SetBreakStatus();
55 m_pUserData = pUserData;
56 }
57
GetPositionedTab(int32_t * iTabPos) const58 bool CFX_RTFBreak::GetPositionedTab(int32_t* iTabPos) const {
59 auto it = std::upper_bound(m_PositionedTabs.begin(), m_PositionedTabs.end(),
60 *iTabPos);
61 if (it == m_PositionedTabs.end())
62 return false;
63
64 *iTabPos = *it;
65 return true;
66 }
67
AppendChar(wchar_t wch)68 CFX_BreakType CFX_RTFBreak::AppendChar(wchar_t wch) {
69 ASSERT(m_pCurLine);
70
71 FX_CHARTYPE chartype = FX_GetCharType(wch);
72 m_pCurLine->m_LineChars.emplace_back(wch, m_iHorizontalScale,
73 m_iVerticalScale);
74 CFX_Char* pCurChar = &m_pCurLine->m_LineChars.back();
75 pCurChar->m_iFontSize = m_iFontSize;
76 pCurChar->m_dwIdentity = m_dwIdentity;
77 pCurChar->m_pUserData = m_pUserData;
78
79 CFX_BreakType dwRet1 = CFX_BreakType::None;
80 if (chartype != FX_CHARTYPE::kCombination &&
81 GetUnifiedCharType(m_eCharType) != GetUnifiedCharType(chartype) &&
82 m_eCharType != FX_CHARTYPE::kUnknown &&
83 IsGreaterThanLineWidth(m_pCurLine->GetLineEnd()) &&
84 (m_eCharType != FX_CHARTYPE::kSpace ||
85 chartype != FX_CHARTYPE::kControl)) {
86 dwRet1 = EndBreak(CFX_BreakType::Line);
87 if (!m_pCurLine->m_LineChars.empty())
88 pCurChar = &m_pCurLine->m_LineChars.back();
89 }
90
91 CFX_BreakType dwRet2 = CFX_BreakType::None;
92 switch (chartype) {
93 case FX_CHARTYPE::kTab:
94 AppendChar_Tab(pCurChar);
95 break;
96 case FX_CHARTYPE::kControl:
97 dwRet2 = AppendChar_Control(pCurChar);
98 break;
99 case FX_CHARTYPE::kCombination:
100 AppendChar_Combination(pCurChar);
101 break;
102 case FX_CHARTYPE::kArabicAlef:
103 case FX_CHARTYPE::kArabicSpecial:
104 case FX_CHARTYPE::kArabicDistortion:
105 case FX_CHARTYPE::kArabicNormal:
106 case FX_CHARTYPE::kArabicForm:
107 case FX_CHARTYPE::kArabic:
108 dwRet2 = AppendChar_Arabic(pCurChar);
109 break;
110 case FX_CHARTYPE::kUnknown:
111 case FX_CHARTYPE::kSpace:
112 case FX_CHARTYPE::kNumeric:
113 case FX_CHARTYPE::kNormal:
114 default:
115 dwRet2 = AppendChar_Others(pCurChar);
116 break;
117 }
118
119 m_eCharType = chartype;
120 return std::max(dwRet1, dwRet2);
121 }
122
AppendChar_Combination(CFX_Char * pCurChar)123 void CFX_RTFBreak::AppendChar_Combination(CFX_Char* pCurChar) {
124 FX_SAFE_INT32 iCharWidth = 0;
125 int32_t iCharWidthOut;
126 if (m_pFont && m_pFont->GetCharWidth(pCurChar->char_code(), &iCharWidthOut))
127 iCharWidth = iCharWidthOut;
128
129 iCharWidth *= m_iFontSize;
130 iCharWidth *= m_iHorizontalScale;
131 iCharWidth /= 100;
132 CFX_Char* pLastChar = GetLastChar(0, false, true);
133 if (pLastChar && pLastChar->GetCharType() > FX_CHARTYPE::kCombination)
134 iCharWidth *= -1;
135 else
136 m_eCharType = FX_CHARTYPE::kCombination;
137
138 int32_t iCharWidthValid = iCharWidth.ValueOrDefault(0);
139 pCurChar->m_iCharWidth = iCharWidthValid;
140 if (iCharWidthValid > 0) {
141 FX_SAFE_INT32 checked_width = m_pCurLine->m_iWidth;
142 checked_width += iCharWidthValid;
143 if (!checked_width.IsValid())
144 return;
145
146 m_pCurLine->m_iWidth = checked_width.ValueOrDie();
147 }
148 }
149
AppendChar_Tab(CFX_Char * pCurChar)150 void CFX_RTFBreak::AppendChar_Tab(CFX_Char* pCurChar) {
151 if (!(m_dwLayoutStyles & FX_LAYOUTSTYLE_ExpandTab))
152 return;
153
154 int32_t& iLineWidth = m_pCurLine->m_iWidth;
155 int32_t iCharWidth = iLineWidth;
156 FX_SAFE_INT32 iSafeCharWidth;
157 if (GetPositionedTab(&iCharWidth)) {
158 iSafeCharWidth = iCharWidth;
159 } else {
160 // Tab width is >= 160000, so this part does not need to be checked.
161 ASSERT(m_iTabWidth >= kMinimumTabWidth);
162 iSafeCharWidth = iLineWidth / m_iTabWidth + 1;
163 iSafeCharWidth *= m_iTabWidth;
164 }
165 iSafeCharWidth -= iLineWidth;
166
167 iCharWidth = iSafeCharWidth.ValueOrDefault(0);
168
169 pCurChar->m_iCharWidth = iCharWidth;
170 iLineWidth += iCharWidth;
171 }
172
AppendChar_Control(CFX_Char * pCurChar)173 CFX_BreakType CFX_RTFBreak::AppendChar_Control(CFX_Char* pCurChar) {
174 CFX_BreakType dwRet2 = CFX_BreakType::None;
175 switch (pCurChar->char_code()) {
176 case L'\v':
177 case 0x2028:
178 dwRet2 = CFX_BreakType::Line;
179 break;
180 case L'\f':
181 dwRet2 = CFX_BreakType::Page;
182 break;
183 case 0x2029:
184 dwRet2 = CFX_BreakType::Paragraph;
185 break;
186 default:
187 if (pCurChar->char_code() == m_wParagraphBreakChar)
188 dwRet2 = CFX_BreakType::Paragraph;
189 break;
190 }
191 if (dwRet2 != CFX_BreakType::None)
192 dwRet2 = EndBreak(dwRet2);
193
194 return dwRet2;
195 }
196
AppendChar_Arabic(CFX_Char * pCurChar)197 CFX_BreakType CFX_RTFBreak::AppendChar_Arabic(CFX_Char* pCurChar) {
198 m_pCurLine->IncrementArabicCharCount();
199
200 CFX_Char* pLastChar = nullptr;
201 wchar_t wForm;
202 bool bAlef = false;
203 if (m_eCharType >= FX_CHARTYPE::kArabicAlef &&
204 m_eCharType <= FX_CHARTYPE::kArabicDistortion) {
205 pLastChar = GetLastChar(1, false, true);
206 if (pLastChar) {
207 m_pCurLine->m_iWidth -= pLastChar->m_iCharWidth;
208 CFX_Char* pPrevChar = GetLastChar(2, false, true);
209 wForm = pdfium::arabic::GetFormChar(pLastChar, pPrevChar, pCurChar);
210 bAlef = (wForm == 0xFEFF &&
211 pLastChar->GetCharType() == FX_CHARTYPE::kArabicAlef);
212 FX_SAFE_INT32 iCharWidth;
213 int32_t iCharWidthOut;
214 if (m_pFont &&
215 (m_pFont->GetCharWidth(wForm, &iCharWidthOut) ||
216 m_pFont->GetCharWidth(pLastChar->char_code(), &iCharWidthOut))) {
217 iCharWidth = iCharWidthOut;
218 } else {
219 iCharWidth = 0;
220 }
221
222 iCharWidth *= m_iFontSize;
223 iCharWidth *= m_iHorizontalScale;
224 iCharWidth /= 100;
225
226 int iCharWidthValid = iCharWidth.ValueOrDefault(0);
227 pLastChar->m_iCharWidth = iCharWidthValid;
228
229 FX_SAFE_INT32 checked_width = m_pCurLine->m_iWidth;
230 checked_width += iCharWidthValid;
231 if (!checked_width.IsValid())
232 return CFX_BreakType::None;
233
234 m_pCurLine->m_iWidth = checked_width.ValueOrDie();
235 iCharWidth = 0;
236 }
237 }
238
239 wForm = pdfium::arabic::GetFormChar(pCurChar, bAlef ? nullptr : pLastChar,
240 nullptr);
241 FX_SAFE_INT32 iCharWidth;
242 int32_t iCharWidthOut;
243 if (m_pFont &&
244 (m_pFont->GetCharWidth(wForm, &iCharWidthOut) ||
245 m_pFont->GetCharWidth(pCurChar->char_code(), &iCharWidthOut))) {
246 iCharWidth = iCharWidthOut;
247 } else {
248 iCharWidth = 0;
249 }
250
251 iCharWidth *= m_iFontSize;
252 iCharWidth *= m_iHorizontalScale;
253 iCharWidth /= 100;
254
255 int iCharWidthValid = iCharWidth.ValueOrDefault(0);
256 pCurChar->m_iCharWidth = iCharWidthValid;
257
258 FX_SAFE_INT32 checked_width = m_pCurLine->m_iWidth;
259 checked_width += iCharWidthValid;
260 if (!checked_width.IsValid())
261 return CFX_BreakType::None;
262
263 m_pCurLine->m_iWidth = checked_width.ValueOrDie();
264
265 if (IsGreaterThanLineWidth(m_pCurLine->GetLineEnd()))
266 return EndBreak(CFX_BreakType::Line);
267 return CFX_BreakType::None;
268 }
269
AppendChar_Others(CFX_Char * pCurChar)270 CFX_BreakType CFX_RTFBreak::AppendChar_Others(CFX_Char* pCurChar) {
271 FX_CHARTYPE chartype = pCurChar->GetCharType();
272 wchar_t wForm = pCurChar->char_code();
273 FX_SAFE_INT32 iCharWidth;
274 int32_t iCharWidthOut;
275 if (m_pFont && m_pFont->GetCharWidth(wForm, &iCharWidthOut))
276 iCharWidth = iCharWidthOut;
277 else
278 iCharWidth = 0;
279
280 iCharWidth *= m_iFontSize;
281 iCharWidth *= m_iHorizontalScale;
282 iCharWidth /= 100;
283 iCharWidth += m_iCharSpace;
284
285 int iCharWidthValid = iCharWidth.ValueOrDefault(0);
286 pCurChar->m_iCharWidth = iCharWidthValid;
287
288 FX_SAFE_INT32 checked_width = m_pCurLine->m_iWidth;
289 checked_width += iCharWidthValid;
290 if (!checked_width.IsValid())
291 return CFX_BreakType::None;
292
293 m_pCurLine->m_iWidth = checked_width.ValueOrDie();
294 if (chartype != FX_CHARTYPE::kSpace &&
295 IsGreaterThanLineWidth(m_pCurLine->GetLineEnd())) {
296 return EndBreak(CFX_BreakType::Line);
297 }
298 return CFX_BreakType::None;
299 }
300
EndBreak(CFX_BreakType dwStatus)301 CFX_BreakType CFX_RTFBreak::EndBreak(CFX_BreakType dwStatus) {
302 ASSERT(dwStatus != CFX_BreakType::None);
303
304 ++m_dwIdentity;
305 if (!m_pCurLine->m_LinePieces.empty()) {
306 if (dwStatus != CFX_BreakType::Piece)
307 m_pCurLine->m_LinePieces.back().m_dwStatus = dwStatus;
308 return m_pCurLine->m_LinePieces.back().m_dwStatus;
309 }
310
311 if (HasLine()) {
312 if (m_Lines[m_iReadyLineIndex].m_LinePieces.empty())
313 return CFX_BreakType::None;
314
315 if (dwStatus != CFX_BreakType::Piece)
316 m_Lines[m_iReadyLineIndex].m_LinePieces.back().m_dwStatus = dwStatus;
317 return m_Lines[m_iReadyLineIndex].m_LinePieces.back().m_dwStatus;
318 }
319
320 if (m_pCurLine->m_LineChars.empty())
321 return CFX_BreakType::None;
322
323 CFX_Char* tc = m_pCurLine->GetChar(m_pCurLine->m_LineChars.size() - 1);
324 tc->m_dwStatus = dwStatus;
325 if (dwStatus == CFX_BreakType::Piece)
326 return dwStatus;
327
328 m_iReadyLineIndex = m_pCurLine == &m_Lines[0] ? 0 : 1;
329 CFX_BreakLine* pNextLine = &m_Lines[1 - m_iReadyLineIndex];
330 bool bAllChars = m_iAlignment == CFX_RTFLineAlignment::Justified ||
331 m_iAlignment == CFX_RTFLineAlignment::Distributed;
332
333 if (!EndBreak_SplitLine(pNextLine, bAllChars, dwStatus)) {
334 std::deque<FX_TPO> tpos;
335 EndBreak_BidiLine(&tpos, dwStatus);
336 if (!m_bPagination && m_iAlignment != CFX_RTFLineAlignment::Left)
337 EndBreak_Alignment(tpos, bAllChars, dwStatus);
338 }
339 m_pCurLine = pNextLine;
340 m_pCurLine->m_iStart = m_iLineStart;
341
342 CFX_Char* pTC = GetLastChar(0, false, true);
343 m_eCharType = pTC ? pTC->GetCharType() : FX_CHARTYPE::kUnknown;
344 return dwStatus;
345 }
346
EndBreak_SplitLine(CFX_BreakLine * pNextLine,bool bAllChars,CFX_BreakType dwStatus)347 bool CFX_RTFBreak::EndBreak_SplitLine(CFX_BreakLine* pNextLine,
348 bool bAllChars,
349 CFX_BreakType dwStatus) {
350 bool bDone = false;
351 if (IsGreaterThanLineWidth(m_pCurLine->GetLineEnd())) {
352 const CFX_Char* tc =
353 m_pCurLine->GetChar(m_pCurLine->m_LineChars.size() - 1);
354 switch (tc->GetCharType()) {
355 case FX_CHARTYPE::kTab:
356 case FX_CHARTYPE::kControl:
357 case FX_CHARTYPE::kSpace:
358 break;
359 default:
360 SplitTextLine(m_pCurLine.Get(), pNextLine, !m_bPagination && bAllChars);
361 bDone = true;
362 break;
363 }
364 }
365
366 if (!m_bPagination) {
367 if (bAllChars && !bDone) {
368 int32_t endPos = m_pCurLine->GetLineEnd();
369 GetBreakPos(m_pCurLine->m_LineChars, bAllChars, true, &endPos);
370 }
371 return false;
372 }
373
374 const CFX_Char* pCurChars = m_pCurLine->m_LineChars.data();
375 CFX_BreakPiece tp;
376 tp.m_pChars = &m_pCurLine->m_LineChars;
377 bool bNew = true;
378 uint32_t dwIdentity = static_cast<uint32_t>(-1);
379 int32_t iLast = pdfium::CollectionSize<int32_t>(m_pCurLine->m_LineChars) - 1;
380 int32_t j = 0;
381 for (int32_t i = 0; i <= iLast;) {
382 const CFX_Char* pTC = pCurChars + i;
383 if (bNew) {
384 tp.m_iStartChar = i;
385 tp.m_iStartPos += tp.m_iWidth;
386 tp.m_iWidth = 0;
387 tp.m_dwStatus = pTC->m_dwStatus;
388 tp.m_iFontSize = pTC->m_iFontSize;
389 tp.m_iHorizontalScale = pTC->horizonal_scale();
390 tp.m_iVerticalScale = pTC->vertical_scale();
391 dwIdentity = pTC->m_dwIdentity;
392 tp.m_dwIdentity = dwIdentity;
393 tp.m_pUserData = pTC->m_pUserData;
394 j = i;
395 bNew = false;
396 }
397
398 if (i == iLast || pTC->m_dwStatus != CFX_BreakType::None ||
399 pTC->m_dwIdentity != dwIdentity) {
400 tp.m_iChars = i - j;
401 if (pTC->m_dwIdentity == dwIdentity) {
402 tp.m_dwStatus = pTC->m_dwStatus;
403 tp.m_iWidth += pTC->m_iCharWidth;
404 tp.m_iChars += 1;
405 ++i;
406 }
407 m_pCurLine->m_LinePieces.push_back(tp);
408 bNew = true;
409 } else {
410 tp.m_iWidth += pTC->m_iCharWidth;
411 ++i;
412 }
413 }
414 return true;
415 }
416
EndBreak_BidiLine(std::deque<FX_TPO> * tpos,CFX_BreakType dwStatus)417 void CFX_RTFBreak::EndBreak_BidiLine(std::deque<FX_TPO>* tpos,
418 CFX_BreakType dwStatus) {
419 CFX_Char* pTC;
420 std::vector<CFX_Char>& chars = m_pCurLine->m_LineChars;
421 if (!m_bPagination && m_pCurLine->HasArabicChar()) {
422 size_t iBidiNum = 0;
423 for (size_t i = 0; i < m_pCurLine->m_LineChars.size(); ++i) {
424 pTC = &chars[i];
425 pTC->m_iBidiPos = static_cast<int32_t>(i);
426 if (pTC->GetCharType() != FX_CHARTYPE::kControl)
427 iBidiNum = i;
428 if (i == 0)
429 pTC->m_iBidiLevel = 1;
430 }
431 CFX_Char::BidiLine(&chars, iBidiNum + 1);
432 } else {
433 for (size_t i = 0; i < m_pCurLine->m_LineChars.size(); ++i) {
434 pTC = &chars[i];
435 pTC->m_iBidiLevel = 0;
436 pTC->m_iBidiPos = 0;
437 pTC->m_iBidiOrder = 0;
438 }
439 }
440
441 CFX_BreakPiece tp;
442 tp.m_dwStatus = CFX_BreakType::Piece;
443 tp.m_iStartPos = m_pCurLine->m_iStart;
444 tp.m_pChars = &chars;
445
446 int32_t iBidiLevel = -1;
447 int32_t iCharWidth;
448 FX_TPO tpo;
449 uint32_t dwIdentity = static_cast<uint32_t>(-1);
450 int32_t i = 0;
451 int32_t j = 0;
452 int32_t iCount = pdfium::CollectionSize<int32_t>(m_pCurLine->m_LineChars);
453 while (i < iCount) {
454 pTC = &chars[i];
455 if (iBidiLevel < 0) {
456 iBidiLevel = pTC->m_iBidiLevel;
457 iCharWidth = pTC->m_iCharWidth;
458 tp.m_iWidth = iCharWidth < 1 ? 0 : iCharWidth;
459 tp.m_iBidiLevel = iBidiLevel;
460 tp.m_iBidiPos = pTC->m_iBidiOrder;
461 tp.m_iFontSize = pTC->m_iFontSize;
462 tp.m_iHorizontalScale = pTC->horizonal_scale();
463 tp.m_iVerticalScale = pTC->vertical_scale();
464 dwIdentity = pTC->m_dwIdentity;
465 tp.m_dwIdentity = dwIdentity;
466 tp.m_pUserData = pTC->m_pUserData;
467 tp.m_dwStatus = CFX_BreakType::Piece;
468 ++i;
469 } else if (iBidiLevel != pTC->m_iBidiLevel ||
470 pTC->m_dwIdentity != dwIdentity) {
471 tp.m_iChars = i - tp.m_iStartChar;
472 m_pCurLine->m_LinePieces.push_back(tp);
473
474 tp.m_iStartPos += tp.m_iWidth;
475 tp.m_iStartChar = i;
476 tpo.index = j++;
477 tpo.pos = tp.m_iBidiPos;
478 tpos->push_back(tpo);
479 iBidiLevel = -1;
480 } else {
481 iCharWidth = pTC->m_iCharWidth;
482 if (iCharWidth > 0)
483 tp.m_iWidth += iCharWidth;
484 ++i;
485 }
486 }
487
488 if (i > tp.m_iStartChar) {
489 tp.m_dwStatus = dwStatus;
490 tp.m_iChars = i - tp.m_iStartChar;
491 m_pCurLine->m_LinePieces.push_back(tp);
492
493 tpo.index = j;
494 tpo.pos = tp.m_iBidiPos;
495 tpos->push_back(tpo);
496 }
497
498 std::sort(tpos->begin(), tpos->end());
499 int32_t iStartPos = m_pCurLine->m_iStart;
500 for (const auto& it : *tpos) {
501 CFX_BreakPiece& ttp = m_pCurLine->m_LinePieces[it.index];
502 ttp.m_iStartPos = iStartPos;
503 iStartPos += ttp.m_iWidth;
504 }
505 }
506
EndBreak_Alignment(const std::deque<FX_TPO> & tpos,bool bAllChars,CFX_BreakType dwStatus)507 void CFX_RTFBreak::EndBreak_Alignment(const std::deque<FX_TPO>& tpos,
508 bool bAllChars,
509 CFX_BreakType dwStatus) {
510 int32_t iNetWidth = m_pCurLine->m_iWidth;
511 int32_t iGapChars = 0;
512 bool bFind = false;
513 for (auto it = tpos.rbegin(); it != tpos.rend(); it++) {
514 CFX_BreakPiece& ttp = m_pCurLine->m_LinePieces[it->index];
515 if (!bFind)
516 iNetWidth = ttp.GetEndPos();
517
518 bool bArabic = FX_IsOdd(ttp.m_iBidiLevel);
519 int32_t j = bArabic ? 0 : ttp.m_iChars - 1;
520 while (j > -1 && j < ttp.m_iChars) {
521 const CFX_Char* tc = ttp.GetChar(j);
522 if (tc->m_eLineBreakType == FX_LINEBREAKTYPE::kDIRECT_BRK)
523 ++iGapChars;
524
525 if (!bFind || !bAllChars) {
526 FX_CHARTYPE dwCharType = tc->GetCharType();
527 if (dwCharType == FX_CHARTYPE::kSpace ||
528 dwCharType == FX_CHARTYPE::kControl) {
529 if (!bFind) {
530 int32_t iCharWidth = tc->m_iCharWidth;
531 if (bAllChars && iCharWidth > 0)
532 iNetWidth -= iCharWidth;
533 }
534 } else {
535 bFind = true;
536 if (!bAllChars)
537 break;
538 }
539 }
540 j += bArabic ? 1 : -1;
541 }
542 if (!bAllChars && bFind)
543 break;
544 }
545
546 int32_t iOffset = m_iLineWidth - iNetWidth;
547 if (iGapChars > 0 && (m_iAlignment == CFX_RTFLineAlignment::Distributed ||
548 (m_iAlignment == CFX_RTFLineAlignment::Justified &&
549 dwStatus != CFX_BreakType::Paragraph))) {
550 int32_t iStart = -1;
551 for (const auto& tpo : tpos) {
552 CFX_BreakPiece& ttp = m_pCurLine->m_LinePieces[tpo.index];
553 if (iStart < 0)
554 iStart = ttp.m_iStartPos;
555 else
556 ttp.m_iStartPos = iStart;
557
558 for (int32_t j = 0; j < ttp.m_iChars; ++j) {
559 CFX_Char* tc = ttp.GetChar(j);
560 if (tc->m_eLineBreakType != FX_LINEBREAKTYPE::kDIRECT_BRK ||
561 tc->m_iCharWidth < 0) {
562 continue;
563 }
564 int32_t k = iOffset / iGapChars;
565 tc->m_iCharWidth += k;
566 ttp.m_iWidth += k;
567 iOffset -= k;
568 --iGapChars;
569 if (iGapChars < 1)
570 break;
571 }
572 iStart += ttp.m_iWidth;
573 }
574 } else if (m_iAlignment == CFX_RTFLineAlignment::Right ||
575 m_iAlignment == CFX_RTFLineAlignment::Center) {
576 if (m_iAlignment == CFX_RTFLineAlignment::Center)
577 iOffset /= 2;
578 if (iOffset > 0) {
579 for (auto& ttp : m_pCurLine->m_LinePieces)
580 ttp.m_iStartPos += iOffset;
581 }
582 }
583 }
584
GetBreakPos(std::vector<CFX_Char> & tca,bool bAllChars,bool bOnlyBrk,int32_t * pEndPos)585 int32_t CFX_RTFBreak::GetBreakPos(std::vector<CFX_Char>& tca,
586 bool bAllChars,
587 bool bOnlyBrk,
588 int32_t* pEndPos) {
589 int32_t iLength = pdfium::CollectionSize<int32_t>(tca) - 1;
590 if (iLength < 1)
591 return iLength;
592
593 int32_t iBreak = -1;
594 int32_t iBreakPos = -1;
595 int32_t iIndirect = -1;
596 int32_t iIndirectPos = -1;
597 int32_t iLast = -1;
598 int32_t iLastPos = -1;
599 if (*pEndPos <= m_iLineWidth) {
600 if (!bAllChars)
601 return iLength;
602
603 iBreak = iLength;
604 iBreakPos = *pEndPos;
605 }
606
607 CFX_Char* pCharArray = tca.data();
608 CFX_Char* pCur = pCharArray + iLength;
609 --iLength;
610 if (bAllChars)
611 pCur->m_eLineBreakType = FX_LINEBREAKTYPE::kUNKNOWN;
612
613 FX_BREAKPROPERTY nNext = FX_GetBreakProperty(pCur->char_code());
614 int32_t iCharWidth = pCur->m_iCharWidth;
615 if (iCharWidth > 0)
616 *pEndPos -= iCharWidth;
617
618 while (iLength >= 0) {
619 pCur = pCharArray + iLength;
620 FX_BREAKPROPERTY nCur = FX_GetBreakProperty(pCur->char_code());
621 bool bNeedBreak = false;
622 FX_LINEBREAKTYPE eType;
623 if (nCur == FX_BREAKPROPERTY::kTB) {
624 bNeedBreak = true;
625 eType = nNext == FX_BREAKPROPERTY::kTB
626 ? FX_LINEBREAKTYPE::kPROHIBITED_BRK
627 : GetLineBreakTypeFromPair(nCur, nNext);
628 } else {
629 if (nCur == FX_BREAKPROPERTY::kSP)
630 bNeedBreak = true;
631
632 eType = nNext == FX_BREAKPROPERTY::kSP
633 ? FX_LINEBREAKTYPE::kPROHIBITED_BRK
634 : GetLineBreakTypeFromPair(nCur, nNext);
635 }
636 if (bAllChars)
637 pCur->m_eLineBreakType = eType;
638
639 if (!bOnlyBrk) {
640 iCharWidth = pCur->m_iCharWidth;
641 if (*pEndPos <= m_iLineWidth || bNeedBreak) {
642 if (eType == FX_LINEBREAKTYPE::kDIRECT_BRK && iBreak < 0) {
643 iBreak = iLength;
644 iBreakPos = *pEndPos;
645 if (!bAllChars)
646 return iLength;
647 } else if (eType == FX_LINEBREAKTYPE::kINDIRECT_BRK && iIndirect < 0) {
648 iIndirect = iLength;
649 iIndirectPos = *pEndPos;
650 }
651 if (iLast < 0) {
652 iLast = iLength;
653 iLastPos = *pEndPos;
654 }
655 }
656 if (iCharWidth > 0)
657 *pEndPos -= iCharWidth;
658 }
659 nNext = nCur;
660 --iLength;
661 }
662 if (bOnlyBrk)
663 return 0;
664
665 if (iBreak > -1) {
666 *pEndPos = iBreakPos;
667 return iBreak;
668 }
669 if (iIndirect > -1) {
670 *pEndPos = iIndirectPos;
671 return iIndirect;
672 }
673 if (iLast > -1) {
674 *pEndPos = iLastPos;
675 return iLast;
676 }
677 return 0;
678 }
679
SplitTextLine(CFX_BreakLine * pCurLine,CFX_BreakLine * pNextLine,bool bAllChars)680 void CFX_RTFBreak::SplitTextLine(CFX_BreakLine* pCurLine,
681 CFX_BreakLine* pNextLine,
682 bool bAllChars) {
683 ASSERT(pCurLine);
684 ASSERT(pNextLine);
685
686 if (pCurLine->m_LineChars.size() < 2)
687 return;
688
689 int32_t iEndPos = pCurLine->GetLineEnd();
690 std::vector<CFX_Char>& curChars = pCurLine->m_LineChars;
691 int32_t iCharPos = GetBreakPos(curChars, bAllChars, false, &iEndPos);
692 if (iCharPos < 0)
693 iCharPos = 0;
694
695 ++iCharPos;
696 if (iCharPos >= pdfium::CollectionSize<int32_t>(pCurLine->m_LineChars)) {
697 pNextLine->Clear();
698 curChars[iCharPos - 1].m_eLineBreakType = FX_LINEBREAKTYPE::kUNKNOWN;
699 return;
700 }
701
702 pNextLine->m_LineChars =
703 std::vector<CFX_Char>(curChars.begin() + iCharPos, curChars.end());
704 curChars.erase(curChars.begin() + iCharPos, curChars.end());
705 pNextLine->m_iStart = pCurLine->m_iStart;
706 pNextLine->m_iWidth = pCurLine->GetLineEnd() - iEndPos;
707 pCurLine->m_iWidth = iEndPos;
708 curChars[iCharPos - 1].m_eLineBreakType = FX_LINEBREAKTYPE::kUNKNOWN;
709
710 for (size_t i = 0; i < pNextLine->m_LineChars.size(); ++i) {
711 if (pNextLine->m_LineChars[i].GetCharType() >= FX_CHARTYPE::kArabicAlef) {
712 pCurLine->DecrementArabicCharCount();
713 pNextLine->IncrementArabicCharCount();
714 }
715 pNextLine->m_LineChars[i].m_dwStatus = CFX_BreakType::None;
716 }
717 }
718
GetDisplayPos(const CFX_TextPiece * pPiece,std::vector<TextCharPos> * pCharPos) const719 size_t CFX_RTFBreak::GetDisplayPos(const CFX_TextPiece* pPiece,
720 std::vector<TextCharPos>* pCharPos) const {
721 ASSERT(pPiece->iChars > 0);
722 ASSERT(pPiece->pFont);
723
724 RetainPtr<CFGAS_GEFont> pFont = pPiece->pFont;
725 CFX_RectF rtText(pPiece->rtPiece);
726 bool bRTLPiece = FX_IsOdd(pPiece->iBidiLevel);
727 float fFontSize = pPiece->fFontSize;
728 int32_t iFontSize = FXSYS_roundf(fFontSize * 20.0f);
729 if (iFontSize == 0)
730 return 0;
731
732 int32_t iAscent = pFont->GetAscent();
733 int32_t iDescent = pFont->GetDescent();
734 int32_t iMaxHeight = iAscent - iDescent;
735 float fFontHeight = fFontSize;
736 float fAscent = fFontHeight * static_cast<float>(iAscent) /
737 static_cast<float>(iMaxHeight);
738 wchar_t wPrev = 0xFEFF;
739 wchar_t wNext;
740 float fX = rtText.left;
741 int32_t iHorScale = pPiece->iHorScale;
742 int32_t iVerScale = pPiece->iVerScale;
743 if (bRTLPiece)
744 fX = rtText.right();
745
746 float fY = rtText.top + fAscent;
747 size_t szCount = 0;
748 for (int32_t i = 0; i < pPiece->iChars; ++i) {
749 TextCharPos& current_char_pos = (*pCharPos)[szCount];
750 wchar_t wch = pPiece->szText[i];
751 int32_t iWidth = pPiece->Widths[i];
752 FX_CHARTYPE dwCharType = FX_GetCharType(wch);
753 if (iWidth == 0) {
754 if (dwCharType == FX_CHARTYPE::kArabicAlef)
755 wPrev = 0xFEFF;
756 continue;
757 }
758
759 uint32_t iCharWidth = abs(iWidth);
760 const bool bEmptyChar = (dwCharType >= FX_CHARTYPE::kTab &&
761 dwCharType <= FX_CHARTYPE::kControl);
762 if (!bEmptyChar)
763 ++szCount;
764
765 iCharWidth /= iFontSize;
766 wchar_t wForm = wch;
767 if (dwCharType >= FX_CHARTYPE::kArabicAlef) {
768 if (i + 1 < pPiece->iChars) {
769 wNext = pPiece->szText[i + 1];
770 if (pPiece->Widths[i + 1] < 0 && i + 2 < pPiece->iChars)
771 wNext = pPiece->szText[i + 2];
772 } else {
773 wNext = 0xFEFF;
774 }
775 wForm = pdfium::arabic::GetFormChar(wch, wPrev, wNext);
776 } else if (bRTLPiece) {
777 wForm = FX_GetMirrorChar(wch);
778 }
779
780 if (!bEmptyChar) {
781 current_char_pos.m_GlyphIndex = pFont->GetGlyphIndex(wForm);
782 if (current_char_pos.m_GlyphIndex == 0xFFFF)
783 current_char_pos.m_GlyphIndex = pFont->GetGlyphIndex(wch);
784 #if defined(OS_MACOSX)
785 current_char_pos.m_ExtGID = current_char_pos.m_GlyphIndex;
786 #endif
787 current_char_pos.m_FontCharWidth = iCharWidth;
788 }
789
790 float fCharWidth = fFontSize * iCharWidth / 1000.0f;
791 if (bRTLPiece && dwCharType != FX_CHARTYPE::kCombination)
792 fX -= fCharWidth;
793
794 if (!bEmptyChar)
795 current_char_pos.m_Origin = CFX_PointF(fX, fY);
796 if (!bRTLPiece && dwCharType != FX_CHARTYPE::kCombination)
797 fX += fCharWidth;
798
799 if (!bEmptyChar) {
800 current_char_pos.m_bGlyphAdjust = true;
801 current_char_pos.m_AdjustMatrix[0] = -1;
802 current_char_pos.m_AdjustMatrix[1] = 0;
803 current_char_pos.m_AdjustMatrix[2] = 0;
804 current_char_pos.m_AdjustMatrix[3] = 1;
805 current_char_pos.m_Origin.y += fAscent * iVerScale / 100.0f;
806 current_char_pos.m_Origin.y -= fAscent;
807
808 if (iHorScale != 100 || iVerScale != 100) {
809 current_char_pos.m_AdjustMatrix[0] =
810 current_char_pos.m_AdjustMatrix[0] * iHorScale / 100.0f;
811 current_char_pos.m_AdjustMatrix[1] =
812 current_char_pos.m_AdjustMatrix[1] * iHorScale / 100.0f;
813 current_char_pos.m_AdjustMatrix[2] =
814 current_char_pos.m_AdjustMatrix[2] * iVerScale / 100.0f;
815 current_char_pos.m_AdjustMatrix[3] =
816 current_char_pos.m_AdjustMatrix[3] * iVerScale / 100.0f;
817 }
818 }
819 if (iWidth > 0)
820 wPrev = wch;
821 }
822 return szCount;
823 }
824