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/fgas_rtfbreak.h"
8
9 #include <algorithm>
10
11 #include "core/fxcrt/fx_arabic.h"
12 #include "core/fxcrt/fx_arb.h"
13 #include "third_party/base/stl_util.h"
14 #include "xfa/fgas/font/cfgas_gefont.h"
15 #include "xfa/fgas/layout/fgas_linebreak.h"
16
17 namespace {
18
19 typedef CFX_RTFBreakType (CFX_RTFBreak::*FX_RTFBreak_LPFAppendChar)(
20 CFX_RTFChar* pCurChar);
21 const FX_RTFBreak_LPFAppendChar g_FX_RTFBreak_lpfAppendChar[16] = {
22 &CFX_RTFBreak::AppendChar_Others, &CFX_RTFBreak::AppendChar_Tab,
23 &CFX_RTFBreak::AppendChar_Others, &CFX_RTFBreak::AppendChar_Control,
24 &CFX_RTFBreak::AppendChar_Combination, &CFX_RTFBreak::AppendChar_Others,
25 &CFX_RTFBreak::AppendChar_Others, &CFX_RTFBreak::AppendChar_Arabic,
26 &CFX_RTFBreak::AppendChar_Arabic, &CFX_RTFBreak::AppendChar_Arabic,
27 &CFX_RTFBreak::AppendChar_Arabic, &CFX_RTFBreak::AppendChar_Arabic,
28 &CFX_RTFBreak::AppendChar_Arabic, &CFX_RTFBreak::AppendChar_Others,
29 &CFX_RTFBreak::AppendChar_Others, &CFX_RTFBreak::AppendChar_Others,
30 };
31
32 } // namespace
33
CFX_RTFBreak(uint32_t dwLayoutStyles)34 CFX_RTFBreak::CFX_RTFBreak(uint32_t dwLayoutStyles)
35 : m_iBoundaryStart(0),
36 m_iBoundaryEnd(2000000),
37 m_dwLayoutStyles(dwLayoutStyles),
38 m_bPagination(false),
39 m_pFont(nullptr),
40 m_iFontHeight(240),
41 m_iFontSize(240),
42 m_iTabWidth(720000),
43 m_wDefChar(0xFEFF),
44 m_iDefChar(0),
45 m_wLineBreakChar(L'\n'),
46 m_iHorizontalScale(100),
47 m_iVerticalScale(100),
48 m_iCharSpace(0),
49 m_iAlignment(CFX_RTFLineAlignment::Left),
50 m_pUserData(nullptr),
51 m_eCharType(FX_CHARTYPE_Unknown),
52 m_dwIdentity(0),
53 m_RTFLine1(),
54 m_RTFLine2(),
55 m_pCurLine(nullptr),
56 m_iReady(0),
57 m_iTolerance(0) {
58 m_pCurLine = &m_RTFLine1;
59
60 SetBreakStatus();
61 m_bPagination = (m_dwLayoutStyles & FX_RTFLAYOUTSTYLE_Pagination) != 0;
62 }
63
~CFX_RTFBreak()64 CFX_RTFBreak::~CFX_RTFBreak() {
65 Reset();
66 }
67
SetLineBoundary(FX_FLOAT fLineStart,FX_FLOAT fLineEnd)68 void CFX_RTFBreak::SetLineBoundary(FX_FLOAT fLineStart, FX_FLOAT fLineEnd) {
69 if (fLineStart > fLineEnd)
70 return;
71
72 m_iBoundaryStart = FXSYS_round(fLineStart * 20000.0f);
73 m_iBoundaryEnd = FXSYS_round(fLineEnd * 20000.0f);
74 m_pCurLine->m_iStart = std::min(m_pCurLine->m_iStart, m_iBoundaryEnd);
75 m_pCurLine->m_iStart = std::max(m_pCurLine->m_iStart, m_iBoundaryStart);
76 }
77
SetLineStartPos(FX_FLOAT fLinePos)78 void CFX_RTFBreak::SetLineStartPos(FX_FLOAT fLinePos) {
79 int32_t iLinePos = FXSYS_round(fLinePos * 20000.0f);
80 iLinePos = std::min(iLinePos, m_iBoundaryEnd);
81 iLinePos = std::max(iLinePos, m_iBoundaryStart);
82 m_pCurLine->m_iStart = iLinePos;
83 }
84
SetFont(const CFX_RetainPtr<CFGAS_GEFont> & pFont)85 void CFX_RTFBreak::SetFont(const CFX_RetainPtr<CFGAS_GEFont>& pFont) {
86 if (!pFont || pFont == m_pFont)
87 return;
88
89 SetBreakStatus();
90 m_pFont = pFont;
91 FontChanged();
92 }
93
SetFontSize(FX_FLOAT fFontSize)94 void CFX_RTFBreak::SetFontSize(FX_FLOAT fFontSize) {
95 int32_t iFontSize = FXSYS_round(fFontSize * 20.0f);
96 if (m_iFontSize == iFontSize)
97 return;
98
99 SetBreakStatus();
100 m_iFontSize = iFontSize;
101 FontChanged();
102 }
103
FontChanged()104 void CFX_RTFBreak::FontChanged() {
105 m_iDefChar = 0;
106 if (!m_pFont)
107 return;
108
109 m_iFontHeight = m_iFontSize;
110 if (m_wDefChar == 0xFEFF)
111 return;
112
113 m_pFont->GetCharWidth(m_wDefChar, m_iDefChar, false);
114 m_iDefChar *= m_iFontSize;
115 }
116
SetTabWidth(FX_FLOAT fTabWidth)117 void CFX_RTFBreak::SetTabWidth(FX_FLOAT fTabWidth) {
118 m_iTabWidth = FXSYS_round(fTabWidth * 20000.0f);
119 }
120
AddPositionedTab(FX_FLOAT fTabPos)121 void CFX_RTFBreak::AddPositionedTab(FX_FLOAT fTabPos) {
122 int32_t iTabPos = std::min(FXSYS_round(fTabPos * 20000.0f) + m_iBoundaryStart,
123 m_iBoundaryEnd);
124 auto it = std::lower_bound(m_PositionedTabs.begin(), m_PositionedTabs.end(),
125 iTabPos);
126 if (it != m_PositionedTabs.end() && *it == iTabPos)
127 return;
128 m_PositionedTabs.insert(it, iTabPos);
129 }
130
SetLineBreakTolerance(FX_FLOAT fTolerance)131 void CFX_RTFBreak::SetLineBreakTolerance(FX_FLOAT fTolerance) {
132 m_iTolerance = FXSYS_round(fTolerance * 20000.0f);
133 }
134
SetHorizontalScale(int32_t iScale)135 void CFX_RTFBreak::SetHorizontalScale(int32_t iScale) {
136 if (iScale < 0)
137 iScale = 0;
138 if (m_iHorizontalScale == iScale)
139 return;
140
141 SetBreakStatus();
142 m_iHorizontalScale = iScale;
143 }
144
SetVerticalScale(int32_t iScale)145 void CFX_RTFBreak::SetVerticalScale(int32_t iScale) {
146 if (iScale < 0)
147 iScale = 0;
148 if (m_iVerticalScale == iScale)
149 return;
150
151 SetBreakStatus();
152 m_iVerticalScale = iScale;
153 }
154
SetCharSpace(FX_FLOAT fCharSpace)155 void CFX_RTFBreak::SetCharSpace(FX_FLOAT fCharSpace) {
156 m_iCharSpace = FXSYS_round(fCharSpace * 20000.0f);
157 }
158
SetUserData(const CFX_RetainPtr<CFX_Retainable> & pUserData)159 void CFX_RTFBreak::SetUserData(const CFX_RetainPtr<CFX_Retainable>& pUserData) {
160 if (m_pUserData == pUserData)
161 return;
162
163 SetBreakStatus();
164 m_pUserData = pUserData;
165 }
166
SetBreakStatus()167 void CFX_RTFBreak::SetBreakStatus() {
168 m_dwIdentity++;
169 int32_t iCount = m_pCurLine->CountChars();
170 if (iCount < 1)
171 return;
172
173 CFX_RTFChar& tc = m_pCurLine->GetChar(iCount - 1);
174 if (tc.m_dwStatus == CFX_RTFBreakType::None)
175 tc.m_dwStatus = CFX_RTFBreakType::Piece;
176 }
177
GetLastChar(int32_t index) const178 CFX_RTFChar* CFX_RTFBreak::GetLastChar(int32_t index) const {
179 std::vector<CFX_RTFChar>& tca = m_pCurLine->m_LineChars;
180 int32_t iCount = pdfium::CollectionSize<int32_t>(tca);
181 if (index < 0 || index >= iCount)
182 return nullptr;
183
184 int32_t iStart = iCount - 1;
185 while (iStart > -1) {
186 CFX_RTFChar* pTC = &tca[iStart--];
187 if (pTC->m_iCharWidth >= 0 ||
188 pTC->GetCharType() != FX_CHARTYPE_Combination) {
189 if (--index < 0)
190 return pTC;
191 }
192 }
193 return nullptr;
194 }
195
GetRTFLine() const196 const CFX_RTFLine* CFX_RTFBreak::GetRTFLine() const {
197 if (m_iReady == 1)
198 return &m_RTFLine1;
199 if (m_iReady == 2)
200 return &m_RTFLine2;
201 return nullptr;
202 }
203
GetRTFPieces() const204 const CFX_RTFPieceArray* CFX_RTFBreak::GetRTFPieces() const {
205 const CFX_RTFLine* pRTFLine = GetRTFLine();
206 return pRTFLine ? &pRTFLine->m_LinePieces : nullptr;
207 }
208
GetUnifiedCharType(FX_CHARTYPE chartype) const209 inline FX_CHARTYPE CFX_RTFBreak::GetUnifiedCharType(
210 FX_CHARTYPE chartype) const {
211 return chartype >= FX_CHARTYPE_ArabicAlef ? FX_CHARTYPE_Arabic : chartype;
212 }
213
GetLastPositionedTab() const214 int32_t CFX_RTFBreak::GetLastPositionedTab() const {
215 return m_PositionedTabs.empty() ? m_iBoundaryStart : m_PositionedTabs.back();
216 }
217
GetPositionedTab(int32_t * iTabPos) const218 bool CFX_RTFBreak::GetPositionedTab(int32_t* iTabPos) const {
219 auto it = std::upper_bound(m_PositionedTabs.begin(), m_PositionedTabs.end(),
220 *iTabPos);
221 if (it == m_PositionedTabs.end())
222 return false;
223
224 *iTabPos = *it;
225 return true;
226 }
227
AppendChar(FX_WCHAR wch)228 CFX_RTFBreakType CFX_RTFBreak::AppendChar(FX_WCHAR wch) {
229 ASSERT(m_pFont && m_pCurLine);
230
231 uint32_t dwProps = kTextLayoutCodeProperties[static_cast<uint16_t>(wch)];
232 FX_CHARTYPE chartype = GetCharTypeFromProp(dwProps);
233 m_pCurLine->m_LineChars.emplace_back();
234
235 CFX_RTFChar* pCurChar = &m_pCurLine->m_LineChars.back();
236 pCurChar->m_dwStatus = CFX_RTFBreakType::None;
237 pCurChar->m_wCharCode = wch;
238 pCurChar->m_dwCharProps = dwProps;
239 pCurChar->m_iFontSize = m_iFontSize;
240 pCurChar->m_iFontHeight = m_iFontHeight;
241 pCurChar->m_iHorizontalScale = m_iHorizontalScale;
242 pCurChar->m_iVerticalScale = m_iVerticalScale;
243 pCurChar->m_iCharWidth = 0;
244 pCurChar->m_dwIdentity = m_dwIdentity;
245 pCurChar->m_pUserData = m_pUserData;
246
247 CFX_RTFBreakType dwRet1 = CFX_RTFBreakType::None;
248 if (chartype != FX_CHARTYPE_Combination &&
249 GetUnifiedCharType(m_eCharType) != GetUnifiedCharType(chartype) &&
250 m_eCharType != FX_CHARTYPE_Unknown &&
251 m_pCurLine->GetLineEnd() > m_iBoundaryEnd + m_iTolerance &&
252 (m_eCharType != FX_CHARTYPE_Space || chartype != FX_CHARTYPE_Control)) {
253 dwRet1 = EndBreak(CFX_RTFBreakType::Line);
254 int32_t iCount = m_pCurLine->CountChars();
255 if (iCount > 0)
256 pCurChar = &m_pCurLine->m_LineChars[iCount - 1];
257 }
258
259 CFX_RTFBreakType dwRet2 =
260 (this->*g_FX_RTFBreak_lpfAppendChar[chartype >> FX_CHARTYPEBITS])(
261 pCurChar);
262 m_eCharType = chartype;
263 return std::max(dwRet1, dwRet2);
264 }
265
AppendChar_Combination(CFX_RTFChar * pCurChar)266 CFX_RTFBreakType CFX_RTFBreak::AppendChar_Combination(CFX_RTFChar* pCurChar) {
267 int32_t iCharWidth = 0;
268 if (!m_pFont->GetCharWidth(pCurChar->m_wCharCode, iCharWidth, false))
269 iCharWidth = 0;
270
271 iCharWidth *= m_iFontSize;
272 iCharWidth = iCharWidth * m_iHorizontalScale / 100;
273 CFX_RTFChar* pLastChar = GetLastChar(0);
274 if (pLastChar && pLastChar->GetCharType() > FX_CHARTYPE_Combination)
275 iCharWidth = -iCharWidth;
276 else
277 m_eCharType = FX_CHARTYPE_Combination;
278
279 pCurChar->m_iCharWidth = iCharWidth;
280 if (iCharWidth > 0)
281 m_pCurLine->m_iWidth += iCharWidth;
282
283 return CFX_RTFBreakType::None;
284 }
285
AppendChar_Tab(CFX_RTFChar * pCurChar)286 CFX_RTFBreakType CFX_RTFBreak::AppendChar_Tab(CFX_RTFChar* pCurChar) {
287 if (!(m_dwLayoutStyles & FX_RTFLAYOUTSTYLE_ExpandTab))
288 return CFX_RTFBreakType::None;
289
290 int32_t& iLineWidth = m_pCurLine->m_iWidth;
291 int32_t iCharWidth = iLineWidth;
292 if (GetPositionedTab(&iCharWidth))
293 iCharWidth -= iLineWidth;
294 else
295 iCharWidth = m_iTabWidth * (iLineWidth / m_iTabWidth + 1) - iLineWidth;
296
297 pCurChar->m_iCharWidth = iCharWidth;
298 iLineWidth += iCharWidth;
299 return CFX_RTFBreakType::None;
300 }
301
AppendChar_Control(CFX_RTFChar * pCurChar)302 CFX_RTFBreakType CFX_RTFBreak::AppendChar_Control(CFX_RTFChar* pCurChar) {
303 CFX_RTFBreakType dwRet2 = CFX_RTFBreakType::None;
304 switch (pCurChar->m_wCharCode) {
305 case L'\v':
306 case 0x2028:
307 dwRet2 = CFX_RTFBreakType::Line;
308 break;
309 case L'\f':
310 dwRet2 = CFX_RTFBreakType::Page;
311 break;
312 case 0x2029:
313 dwRet2 = CFX_RTFBreakType::Paragraph;
314 break;
315 default:
316 if (pCurChar->m_wCharCode == m_wLineBreakChar)
317 dwRet2 = CFX_RTFBreakType::Paragraph;
318 break;
319 }
320 if (dwRet2 != CFX_RTFBreakType::None)
321 dwRet2 = EndBreak(dwRet2);
322
323 return dwRet2;
324 }
325
AppendChar_Arabic(CFX_RTFChar * pCurChar)326 CFX_RTFBreakType CFX_RTFBreak::AppendChar_Arabic(CFX_RTFChar* pCurChar) {
327 CFX_RTFChar* pLastChar = nullptr;
328 int32_t iCharWidth = 0;
329 FX_WCHAR wForm;
330 bool bAlef = false;
331 if (m_eCharType >= FX_CHARTYPE_ArabicAlef &&
332 m_eCharType <= FX_CHARTYPE_ArabicDistortion) {
333 pLastChar = GetLastChar(1);
334 if (pLastChar) {
335 m_pCurLine->m_iWidth -= pLastChar->m_iCharWidth;
336 CFX_RTFChar* pPrevChar = GetLastChar(2);
337 wForm = pdfium::arabic::GetFormChar(pLastChar, pPrevChar, pCurChar);
338 bAlef = (wForm == 0xFEFF &&
339 pLastChar->GetCharType() == FX_CHARTYPE_ArabicAlef);
340 if (!m_pFont->GetCharWidth(wForm, iCharWidth, false) &&
341 !m_pFont->GetCharWidth(pLastChar->m_wCharCode, iCharWidth, false)) {
342 iCharWidth = m_iDefChar;
343 }
344
345 iCharWidth *= m_iFontSize;
346 iCharWidth = iCharWidth * m_iHorizontalScale / 100;
347 pLastChar->m_iCharWidth = iCharWidth;
348 m_pCurLine->m_iWidth += iCharWidth;
349 iCharWidth = 0;
350 }
351 }
352
353 wForm = pdfium::arabic::GetFormChar(pCurChar, bAlef ? nullptr : pLastChar,
354 nullptr);
355 if (!m_pFont->GetCharWidth(wForm, iCharWidth, false) &&
356 !m_pFont->GetCharWidth(pCurChar->m_wCharCode, iCharWidth, false)) {
357 iCharWidth = m_iDefChar;
358 }
359
360 iCharWidth *= m_iFontSize;
361 iCharWidth = iCharWidth * m_iHorizontalScale / 100;
362 pCurChar->m_iCharWidth = iCharWidth;
363 m_pCurLine->m_iWidth += iCharWidth;
364 m_pCurLine->m_iArabicChars++;
365
366 if (m_pCurLine->GetLineEnd() > m_iBoundaryEnd + m_iTolerance)
367 return EndBreak(CFX_RTFBreakType::Line);
368 return CFX_RTFBreakType::None;
369 }
370
AppendChar_Others(CFX_RTFChar * pCurChar)371 CFX_RTFBreakType CFX_RTFBreak::AppendChar_Others(CFX_RTFChar* pCurChar) {
372 FX_CHARTYPE chartype = pCurChar->GetCharType();
373 FX_WCHAR wForm = pCurChar->m_wCharCode;
374 int32_t iCharWidth = 0;
375 if (!m_pFont->GetCharWidth(wForm, iCharWidth, false))
376 iCharWidth = m_iDefChar;
377
378 iCharWidth *= m_iFontSize;
379 iCharWidth *= m_iHorizontalScale / 100;
380 iCharWidth += m_iCharSpace;
381
382 pCurChar->m_iCharWidth = iCharWidth;
383 m_pCurLine->m_iWidth += iCharWidth;
384 if (chartype != FX_CHARTYPE_Space &&
385 m_pCurLine->GetLineEnd() > m_iBoundaryEnd + m_iTolerance) {
386 return EndBreak(CFX_RTFBreakType::Line);
387 }
388 return CFX_RTFBreakType::None;
389 }
390
EndBreak(CFX_RTFBreakType dwStatus)391 CFX_RTFBreakType CFX_RTFBreak::EndBreak(CFX_RTFBreakType dwStatus) {
392 ASSERT(dwStatus != CFX_RTFBreakType::None);
393
394 m_dwIdentity++;
395 const CFX_RTFPieceArray* pCurPieces = &m_pCurLine->m_LinePieces;
396 int32_t iCount = pCurPieces->GetSize();
397 if (iCount > 0) {
398 CFX_RTFPiece* pLastPiece = pCurPieces->GetPtrAt(--iCount);
399 if (dwStatus != CFX_RTFBreakType::Piece)
400 pLastPiece->m_dwStatus = dwStatus;
401 else
402 dwStatus = pLastPiece->m_dwStatus;
403 return dwStatus;
404 }
405
406 const CFX_RTFLine* pLastLine = GetRTFLine();
407 if (pLastLine) {
408 pCurPieces = &pLastLine->m_LinePieces;
409 iCount = pCurPieces->GetSize();
410 if (iCount-- > 0) {
411 CFX_RTFPiece* pLastPiece = pCurPieces->GetPtrAt(iCount);
412 if (dwStatus != CFX_RTFBreakType::Piece)
413 pLastPiece->m_dwStatus = dwStatus;
414 else
415 dwStatus = pLastPiece->m_dwStatus;
416 return dwStatus;
417 }
418 return CFX_RTFBreakType::None;
419 }
420
421 iCount = m_pCurLine->CountChars();
422 if (iCount < 1)
423 return CFX_RTFBreakType::None;
424
425 CFX_RTFChar& tc = m_pCurLine->GetChar(iCount - 1);
426 tc.m_dwStatus = dwStatus;
427 if (dwStatus == CFX_RTFBreakType::Piece)
428 return dwStatus;
429
430 m_iReady = m_pCurLine == &m_RTFLine1 ? 1 : 2;
431 CFX_RTFLine* pNextLine =
432 m_pCurLine == &m_RTFLine1 ? &m_RTFLine2 : &m_RTFLine1;
433 bool bAllChars = m_iAlignment == CFX_RTFLineAlignment::Justified ||
434 m_iAlignment == CFX_RTFLineAlignment::Distributed;
435
436 if (!EndBreak_SplitLine(pNextLine, bAllChars, dwStatus)) {
437 std::deque<FX_TPO> tpos;
438 EndBreak_BidiLine(&tpos, dwStatus);
439 if (!m_bPagination && m_iAlignment != CFX_RTFLineAlignment::Left)
440 EndBreak_Alignment(tpos, bAllChars, dwStatus);
441 }
442 m_pCurLine = pNextLine;
443 m_pCurLine->m_iStart = m_iBoundaryStart;
444
445 CFX_RTFChar* pTC = GetLastChar(0);
446 m_eCharType = pTC ? pTC->GetCharType() : FX_CHARTYPE_Unknown;
447 return dwStatus;
448 }
449
EndBreak_SplitLine(CFX_RTFLine * pNextLine,bool bAllChars,CFX_RTFBreakType dwStatus)450 bool CFX_RTFBreak::EndBreak_SplitLine(CFX_RTFLine* pNextLine,
451 bool bAllChars,
452 CFX_RTFBreakType dwStatus) {
453 bool bDone = false;
454 if (m_pCurLine->GetLineEnd() > m_iBoundaryEnd + m_iTolerance) {
455 const CFX_RTFChar& tc = m_pCurLine->GetChar(m_pCurLine->CountChars() - 1);
456 switch (tc.GetCharType()) {
457 case FX_CHARTYPE_Tab:
458 case FX_CHARTYPE_Control:
459 case FX_CHARTYPE_Space:
460 break;
461 default:
462 SplitTextLine(m_pCurLine, pNextLine, !m_bPagination && bAllChars);
463 bDone = true;
464 break;
465 }
466 }
467
468 if (!m_bPagination && m_pCurLine->m_iMBCSChars <= 0) {
469 if (bAllChars && !bDone) {
470 int32_t endPos = m_pCurLine->GetLineEnd();
471 GetBreakPos(m_pCurLine->m_LineChars, endPos, bAllChars, true);
472 }
473 return false;
474 }
475
476 const CFX_RTFChar* pCurChars = m_pCurLine->m_LineChars.data();
477 const CFX_RTFChar* pTC;
478 CFX_RTFPieceArray* pCurPieces = &m_pCurLine->m_LinePieces;
479 CFX_RTFPiece tp;
480 tp.m_pChars = &m_pCurLine->m_LineChars;
481 bool bNew = true;
482 uint32_t dwIdentity = static_cast<uint32_t>(-1);
483 int32_t iLast = m_pCurLine->CountChars() - 1;
484 int32_t j = 0;
485 for (int32_t i = 0; i <= iLast;) {
486 pTC = pCurChars + i;
487 if (bNew) {
488 tp.m_iStartChar = i;
489 tp.m_iStartPos += tp.m_iWidth;
490 tp.m_iWidth = 0;
491 tp.m_dwStatus = pTC->m_dwStatus;
492 tp.m_iFontSize = pTC->m_iFontSize;
493 tp.m_iFontHeight = pTC->m_iFontHeight;
494 tp.m_iHorizontalScale = pTC->m_iHorizontalScale;
495 tp.m_iVerticalScale = pTC->m_iVerticalScale;
496 dwIdentity = pTC->m_dwIdentity;
497 tp.m_dwIdentity = dwIdentity;
498 tp.m_pUserData = pTC->m_pUserData;
499 j = i;
500 bNew = false;
501 }
502
503 if (i == iLast || pTC->m_dwStatus != CFX_RTFBreakType::None ||
504 pTC->m_dwIdentity != dwIdentity) {
505 tp.m_iChars = i - j;
506 if (pTC->m_dwIdentity == dwIdentity) {
507 tp.m_dwStatus = pTC->m_dwStatus;
508 tp.m_iWidth += pTC->m_iCharWidth;
509 tp.m_iChars += 1;
510 i++;
511 }
512 pCurPieces->Add(tp);
513 bNew = true;
514 } else {
515 tp.m_iWidth += pTC->m_iCharWidth;
516 i++;
517 }
518 }
519 return true;
520 }
521
EndBreak_BidiLine(std::deque<FX_TPO> * tpos,CFX_RTFBreakType dwStatus)522 void CFX_RTFBreak::EndBreak_BidiLine(std::deque<FX_TPO>* tpos,
523 CFX_RTFBreakType dwStatus) {
524 FX_TPO tpo;
525 CFX_RTFPiece tp;
526 CFX_RTFChar* pTC;
527 int32_t i;
528 int32_t j;
529 std::vector<CFX_RTFChar>& chars = m_pCurLine->m_LineChars;
530 int32_t iCount = m_pCurLine->CountChars();
531 if (!m_bPagination && m_pCurLine->m_iArabicChars > 0) {
532 int32_t iBidiNum = 0;
533 for (i = 0; i < iCount; i++) {
534 pTC = &chars[i];
535 pTC->m_iBidiPos = i;
536 if (pTC->GetCharType() != FX_CHARTYPE_Control)
537 iBidiNum = i;
538 if (i == 0)
539 pTC->m_iBidiLevel = 1;
540 }
541 FX_BidiLine(chars, iBidiNum + 1, 0);
542 } else {
543 for (i = 0; i < iCount; i++) {
544 pTC = &chars[i];
545 pTC->m_iBidiLevel = 0;
546 pTC->m_iBidiPos = 0;
547 pTC->m_iBidiOrder = 0;
548 }
549 }
550
551 tp.m_dwStatus = CFX_RTFBreakType::Piece;
552 tp.m_iStartPos = m_pCurLine->m_iStart;
553 tp.m_pChars = &chars;
554 CFX_RTFPieceArray* pCurPieces = &m_pCurLine->m_LinePieces;
555 int32_t iBidiLevel = -1;
556 int32_t iCharWidth;
557 uint32_t dwIdentity = static_cast<uint32_t>(-1);
558 i = 0;
559 j = 0;
560 while (i < iCount) {
561 pTC = &chars[i];
562 if (iBidiLevel < 0) {
563 iBidiLevel = pTC->m_iBidiLevel;
564 iCharWidth = pTC->m_iCharWidth;
565 tp.m_iWidth = iCharWidth < 1 ? 0 : iCharWidth;
566 tp.m_iBidiLevel = iBidiLevel;
567 tp.m_iBidiPos = pTC->m_iBidiOrder;
568 tp.m_iFontSize = pTC->m_iFontSize;
569 tp.m_iFontHeight = pTC->m_iFontHeight;
570 tp.m_iHorizontalScale = pTC->m_iHorizontalScale;
571 tp.m_iVerticalScale = pTC->m_iVerticalScale;
572 dwIdentity = pTC->m_dwIdentity;
573 tp.m_dwIdentity = dwIdentity;
574 tp.m_pUserData = pTC->m_pUserData;
575 tp.m_dwStatus = CFX_RTFBreakType::Piece;
576 i++;
577 } else if (iBidiLevel != pTC->m_iBidiLevel ||
578 pTC->m_dwIdentity != dwIdentity) {
579 tp.m_iChars = i - tp.m_iStartChar;
580 pCurPieces->Add(tp);
581 tp.m_iStartPos += tp.m_iWidth;
582 tp.m_iStartChar = i;
583 tpo.index = j++;
584 tpo.pos = tp.m_iBidiPos;
585 tpos->push_back(tpo);
586 iBidiLevel = -1;
587 } else {
588 iCharWidth = pTC->m_iCharWidth;
589 if (iCharWidth > 0)
590 tp.m_iWidth += iCharWidth;
591 i++;
592 }
593 }
594
595 if (i > tp.m_iStartChar) {
596 tp.m_dwStatus = dwStatus;
597 tp.m_iChars = i - tp.m_iStartChar;
598 pCurPieces->Add(tp);
599 tpo.index = j;
600 tpo.pos = tp.m_iBidiPos;
601 tpos->push_back(tpo);
602 }
603
604 std::sort(tpos->begin(), tpos->end());
605 int32_t iStartPos = m_pCurLine->m_iStart;
606 for (const auto& it : *tpos) {
607 CFX_RTFPiece& ttp = pCurPieces->GetAt(it.index);
608 ttp.m_iStartPos = iStartPos;
609 iStartPos += ttp.m_iWidth;
610 }
611 }
612
EndBreak_Alignment(const std::deque<FX_TPO> & tpos,bool bAllChars,CFX_RTFBreakType dwStatus)613 void CFX_RTFBreak::EndBreak_Alignment(const std::deque<FX_TPO>& tpos,
614 bool bAllChars,
615 CFX_RTFBreakType dwStatus) {
616 CFX_RTFPieceArray* pCurPieces = &m_pCurLine->m_LinePieces;
617 int32_t iNetWidth = m_pCurLine->m_iWidth;
618 int32_t iGapChars = 0;
619 int32_t iCharWidth;
620 int32_t iCount = pCurPieces->GetSize();
621 bool bFind = false;
622 uint32_t dwCharType;
623 int32_t i;
624 int32_t j;
625 FX_TPO tpo;
626 for (i = iCount - 1; i > -1; i--) {
627 tpo = tpos[i];
628 CFX_RTFPiece& ttp = pCurPieces->GetAt(tpo.index);
629 if (!bFind)
630 iNetWidth = ttp.GetEndPos();
631
632 bool bArabic = FX_IsOdd(ttp.m_iBidiLevel);
633 j = bArabic ? 0 : ttp.m_iChars - 1;
634 while (j > -1 && j < ttp.m_iChars) {
635 const CFX_RTFChar& tc = ttp.GetChar(j);
636 if (tc.m_nBreakType == FX_LBT_DIRECT_BRK)
637 iGapChars++;
638
639 if (!bFind || !bAllChars) {
640 dwCharType = tc.GetCharType();
641 if (dwCharType == FX_CHARTYPE_Space ||
642 dwCharType == FX_CHARTYPE_Control) {
643 if (!bFind) {
644 iCharWidth = tc.m_iCharWidth;
645 if (bAllChars && iCharWidth > 0)
646 iNetWidth -= iCharWidth;
647 }
648 } else {
649 bFind = true;
650 if (!bAllChars)
651 break;
652 }
653 }
654 j += bArabic ? 1 : -1;
655 }
656 if (!bAllChars && bFind)
657 break;
658 }
659
660 int32_t iOffset = m_iBoundaryEnd - iNetWidth;
661 if (iGapChars > 0 && (m_iAlignment == CFX_RTFLineAlignment::Distributed ||
662 (m_iAlignment == CFX_RTFLineAlignment::Justified &&
663 dwStatus != CFX_RTFBreakType::Paragraph))) {
664 int32_t iStart = -1;
665 for (i = 0; i < iCount; i++) {
666 tpo = tpos[i];
667 CFX_RTFPiece& ttp = pCurPieces->GetAt(tpo.index);
668 if (iStart < 0)
669 iStart = ttp.m_iStartPos;
670 else
671 ttp.m_iStartPos = iStart;
672
673 for (j = 0; j < ttp.m_iChars; j++) {
674 CFX_RTFChar& tc = ttp.GetChar(j);
675 if (tc.m_nBreakType != FX_LBT_DIRECT_BRK || tc.m_iCharWidth < 0)
676 continue;
677
678 int32_t k = iOffset / iGapChars;
679 tc.m_iCharWidth += k;
680 ttp.m_iWidth += k;
681 iOffset -= k;
682 iGapChars--;
683 if (iGapChars < 1)
684 break;
685 }
686 iStart += ttp.m_iWidth;
687 }
688 } else if (m_iAlignment == CFX_RTFLineAlignment::Right ||
689 m_iAlignment == CFX_RTFLineAlignment::Center) {
690 if (m_iAlignment == CFX_RTFLineAlignment::Center)
691 iOffset /= 2;
692 if (iOffset > 0) {
693 for (i = 0; i < iCount; i++) {
694 CFX_RTFPiece& ttp = pCurPieces->GetAt(i);
695 ttp.m_iStartPos += iOffset;
696 }
697 }
698 }
699 }
700
GetBreakPos(std::vector<CFX_RTFChar> & tca,int32_t & iEndPos,bool bAllChars,bool bOnlyBrk)701 int32_t CFX_RTFBreak::GetBreakPos(std::vector<CFX_RTFChar>& tca,
702 int32_t& iEndPos,
703 bool bAllChars,
704 bool bOnlyBrk) {
705 int32_t iLength = pdfium::CollectionSize<int32_t>(tca) - 1;
706 if (iLength < 1)
707 return iLength;
708
709 int32_t iBreak = -1;
710 int32_t iBreakPos = -1;
711 int32_t iIndirect = -1;
712 int32_t iIndirectPos = -1;
713 int32_t iLast = -1;
714 int32_t iLastPos = -1;
715 if (iEndPos <= m_iBoundaryEnd) {
716 if (!bAllChars)
717 return iLength;
718
719 iBreak = iLength;
720 iBreakPos = iEndPos;
721 }
722
723 CFX_RTFChar* pCharArray = tca.data();
724 CFX_RTFChar* pCur = pCharArray + iLength;
725 --iLength;
726 if (bAllChars)
727 pCur->m_nBreakType = FX_LBT_UNKNOWN;
728
729 uint32_t nCodeProp = pCur->m_dwCharProps;
730 uint32_t nNext = nCodeProp & 0x003F;
731 int32_t iCharWidth = pCur->m_iCharWidth;
732 if (iCharWidth > 0)
733 iEndPos -= iCharWidth;
734
735 while (iLength >= 0) {
736 pCur = pCharArray + iLength;
737 nCodeProp = pCur->m_dwCharProps;
738 uint32_t nCur = nCodeProp & 0x003F;
739 bool bNeedBreak = false;
740 FX_LINEBREAKTYPE eType;
741 if (nCur == FX_CBP_TB) {
742 bNeedBreak = true;
743 eType = nNext == FX_CBP_TB ? FX_LBT_PROHIBITED_BRK
744 : gs_FX_LineBreak_PairTable[nCur][nNext];
745 } else {
746 if (nCur == FX_CBP_SP)
747 bNeedBreak = true;
748
749 eType = nNext == FX_CBP_SP ? FX_LBT_PROHIBITED_BRK
750 : gs_FX_LineBreak_PairTable[nCur][nNext];
751 }
752 if (bAllChars)
753 pCur->m_nBreakType = eType;
754
755 if (!bOnlyBrk) {
756 iCharWidth = pCur->m_iCharWidth;
757 if (iEndPos <= m_iBoundaryEnd || bNeedBreak) {
758 if (eType == FX_LBT_DIRECT_BRK && iBreak < 0) {
759 iBreak = iLength;
760 iBreakPos = iEndPos;
761 if (!bAllChars)
762 return iLength;
763 } else if (eType == FX_LBT_INDIRECT_BRK && iIndirect < 0) {
764 iIndirect = iLength;
765 iIndirectPos = iEndPos;
766 }
767 if (iLast < 0) {
768 iLast = iLength;
769 iLastPos = iEndPos;
770 }
771 }
772 if (iCharWidth > 0)
773 iEndPos -= iCharWidth;
774 }
775 nNext = nCodeProp & 0x003F;
776 iLength--;
777 }
778 if (bOnlyBrk)
779 return 0;
780
781 if (iBreak > -1) {
782 iEndPos = iBreakPos;
783 return iBreak;
784 }
785 if (iIndirect > -1) {
786 iEndPos = iIndirectPos;
787 return iIndirect;
788 }
789 if (iLast > -1) {
790 iEndPos = iLastPos;
791 return iLast;
792 }
793 return 0;
794 }
795
SplitTextLine(CFX_RTFLine * pCurLine,CFX_RTFLine * pNextLine,bool bAllChars)796 void CFX_RTFBreak::SplitTextLine(CFX_RTFLine* pCurLine,
797 CFX_RTFLine* pNextLine,
798 bool bAllChars) {
799 ASSERT(pCurLine && pNextLine);
800 int32_t iCount = pCurLine->CountChars();
801 if (iCount < 2)
802 return;
803
804 int32_t iEndPos = pCurLine->GetLineEnd();
805 std::vector<CFX_RTFChar>& curChars = pCurLine->m_LineChars;
806 int32_t iCharPos = GetBreakPos(curChars, iEndPos, bAllChars, false);
807 if (iCharPos < 0)
808 iCharPos = 0;
809
810 iCharPos++;
811 if (iCharPos >= iCount) {
812 pNextLine->RemoveAll(true);
813 CFX_Char* pTC = &curChars[iCharPos - 1];
814 pTC->m_nBreakType = FX_LBT_UNKNOWN;
815 return;
816 }
817
818 pNextLine->m_LineChars =
819 std::vector<CFX_RTFChar>(curChars.begin() + iCharPos, curChars.end());
820 curChars.erase(curChars.begin() + iCharPos, curChars.end());
821 pNextLine->m_iStart = pCurLine->m_iStart;
822 pNextLine->m_iWidth = pCurLine->GetLineEnd() - iEndPos;
823 pCurLine->m_iWidth = iEndPos;
824 curChars[iCharPos - 1].m_nBreakType = FX_LBT_UNKNOWN;
825
826 for (size_t i = 0; i < pNextLine->m_LineChars.size(); i++) {
827 if (pNextLine->m_LineChars[i].GetCharType() >= FX_CHARTYPE_ArabicAlef) {
828 pCurLine->m_iArabicChars--;
829 pNextLine->m_iArabicChars++;
830 }
831 pNextLine->m_LineChars[i].m_dwStatus = CFX_RTFBreakType::None;
832 }
833 }
834
CountBreakPieces() const835 int32_t CFX_RTFBreak::CountBreakPieces() const {
836 const CFX_RTFPieceArray* pRTFPieces = GetRTFPieces();
837 return pRTFPieces ? pRTFPieces->GetSize() : 0;
838 }
839
GetBreakPiece(int32_t index) const840 const CFX_RTFPiece* CFX_RTFBreak::GetBreakPiece(int32_t index) const {
841 const CFX_RTFPieceArray* pRTFPieces = GetRTFPieces();
842 if (!pRTFPieces)
843 return nullptr;
844 if (index < 0 || index >= pRTFPieces->GetSize())
845 return nullptr;
846 return pRTFPieces->GetPtrAt(index);
847 }
848
ClearBreakPieces()849 void CFX_RTFBreak::ClearBreakPieces() {
850 const CFX_RTFLine* pRTFLine = GetRTFLine();
851 if (pRTFLine)
852 const_cast<CFX_RTFLine*>(pRTFLine)->RemoveAll(true);
853 m_iReady = 0;
854 }
855
Reset()856 void CFX_RTFBreak::Reset() {
857 m_eCharType = FX_CHARTYPE_Unknown;
858 m_RTFLine1.RemoveAll(true);
859 m_RTFLine2.RemoveAll(true);
860 }
861
GetDisplayPos(const FX_RTFTEXTOBJ * pText,FXTEXT_CHARPOS * pCharPos,bool bCharCode) const862 int32_t CFX_RTFBreak::GetDisplayPos(const FX_RTFTEXTOBJ* pText,
863 FXTEXT_CHARPOS* pCharPos,
864 bool bCharCode) const {
865 if (!pText || pText->iLength < 1)
866 return 0;
867
868 ASSERT(pText->pFont && pText->pRect);
869
870 CFX_RetainPtr<CFGAS_GEFont> pFont = pText->pFont;
871 CFX_RectF rtText(*pText->pRect);
872 bool bRTLPiece = FX_IsOdd(pText->iBidiLevel);
873 FX_FLOAT fFontSize = pText->fFontSize;
874 int32_t iFontSize = FXSYS_round(fFontSize * 20.0f);
875 int32_t iAscent = pFont->GetAscent();
876 int32_t iDescent = pFont->GetDescent();
877 int32_t iMaxHeight = iAscent - iDescent;
878 FX_FLOAT fFontHeight = fFontSize;
879 FX_FLOAT fAscent = fFontHeight * static_cast<FX_FLOAT>(iAscent) /
880 static_cast<FX_FLOAT>(iMaxHeight);
881 FX_WCHAR wch;
882 FX_WCHAR wPrev = 0xFEFF;
883 FX_WCHAR wNext;
884 FX_WCHAR wForm;
885 int32_t iWidth;
886 int32_t iCharWidth;
887 int32_t iCharHeight;
888 FX_FLOAT fX = rtText.left;
889 FX_FLOAT fY = rtText.top;
890 FX_FLOAT fCharWidth;
891 FX_FLOAT fCharHeight;
892 int32_t iHorScale = pText->iHorizontalScale;
893 int32_t iVerScale = pText->iVerticalScale;
894 bool bEmptyChar;
895 uint32_t dwProps;
896 uint32_t dwCharType;
897
898 if (bRTLPiece)
899 fX = rtText.right();
900
901 fY += fAscent;
902 int32_t iCount = 0;
903 for (int32_t i = 0; i < pText->iLength; i++) {
904 wch = pText->pStr[i];
905 iWidth = pText->pWidths[i];
906 dwProps = FX_GetUnicodeProperties(wch);
907 dwCharType = (dwProps & FX_CHARTYPEBITSMASK);
908 if (iWidth == 0) {
909 if (dwCharType == FX_CHARTYPE_ArabicAlef)
910 wPrev = 0xFEFF;
911 continue;
912 }
913
914 iCharWidth = FXSYS_abs(iWidth);
915 bEmptyChar =
916 (dwCharType >= FX_CHARTYPE_Tab && dwCharType <= FX_CHARTYPE_Control);
917 if (!bEmptyChar)
918 iCount++;
919
920 if (pCharPos) {
921 iCharWidth /= iFontSize;
922 wForm = wch;
923 if (dwCharType >= FX_CHARTYPE_ArabicAlef) {
924 if (i + 1 < pText->iLength) {
925 wNext = pText->pStr[i + 1];
926 if (pText->pWidths[i + 1] < 0 && i + 2 < pText->iLength)
927 wNext = pText->pStr[i + 2];
928 } else {
929 wNext = 0xFEFF;
930 }
931 wForm = pdfium::arabic::GetFormChar(wch, wPrev, wNext);
932 } else if (bRTLPiece) {
933 wForm = FX_GetMirrorChar(wch, dwProps, bRTLPiece, false);
934 }
935 dwProps = FX_GetUnicodeProperties(wForm);
936
937 if (!bEmptyChar) {
938 if (bCharCode) {
939 pCharPos->m_GlyphIndex = wch;
940 } else {
941 pCharPos->m_GlyphIndex = pFont->GetGlyphIndex(wForm, false);
942 if (pCharPos->m_GlyphIndex == 0xFFFF)
943 pCharPos->m_GlyphIndex = pFont->GetGlyphIndex(wch, false);
944 }
945 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
946 pCharPos->m_ExtGID = pCharPos->m_GlyphIndex;
947 #endif
948 pCharPos->m_FontCharWidth = iCharWidth;
949 }
950 iCharHeight = 1000;
951
952 fCharWidth = fFontSize * iCharWidth / 1000.0f;
953 fCharHeight = fFontSize * iCharHeight / 1000.0f;
954 if (bRTLPiece && dwCharType != FX_CHARTYPE_Combination)
955 fX -= fCharWidth;
956
957 if (!bEmptyChar)
958 pCharPos->m_Origin = CFX_PointF(fX, fY);
959 if (!bRTLPiece && dwCharType != FX_CHARTYPE_Combination)
960 fX += fCharWidth;
961
962 if (!bEmptyChar) {
963 pCharPos->m_bGlyphAdjust = true;
964 pCharPos->m_AdjustMatrix[0] = -1;
965 pCharPos->m_AdjustMatrix[1] = 0;
966 pCharPos->m_AdjustMatrix[2] = 0;
967 pCharPos->m_AdjustMatrix[3] = 1;
968 pCharPos->m_Origin.y += fAscent * iVerScale / 100.0f;
969 pCharPos->m_Origin.y -= fAscent;
970
971 if (iHorScale != 100 || iVerScale != 100) {
972 pCharPos->m_AdjustMatrix[0] =
973 pCharPos->m_AdjustMatrix[0] * iHorScale / 100.0f;
974 pCharPos->m_AdjustMatrix[1] =
975 pCharPos->m_AdjustMatrix[1] * iHorScale / 100.0f;
976 pCharPos->m_AdjustMatrix[2] =
977 pCharPos->m_AdjustMatrix[2] * iVerScale / 100.0f;
978 pCharPos->m_AdjustMatrix[3] =
979 pCharPos->m_AdjustMatrix[3] * iVerScale / 100.0f;
980 }
981 pCharPos++;
982 }
983 }
984 if (iWidth > 0)
985 wPrev = wch;
986 }
987 return iCount;
988 }
989
CFX_RTFPiece()990 CFX_RTFPiece::CFX_RTFPiece()
991 : m_dwStatus(CFX_RTFBreakType::Piece),
992 m_iStartPos(0),
993 m_iWidth(-1),
994 m_iStartChar(0),
995 m_iChars(0),
996 m_iBidiLevel(0),
997 m_iBidiPos(0),
998 m_iFontSize(0),
999 m_iFontHeight(0),
1000 m_iHorizontalScale(100),
1001 m_iVerticalScale(100),
1002 m_dwIdentity(0),
1003 m_pChars(nullptr),
1004 m_pUserData(nullptr) {}
1005
~CFX_RTFPiece()1006 CFX_RTFPiece::~CFX_RTFPiece() {
1007 Reset();
1008 }
1009
CFX_RTFLine()1010 CFX_RTFLine::CFX_RTFLine()
1011 : m_LinePieces(16),
1012 m_iStart(0),
1013 m_iWidth(0),
1014 m_iArabicChars(0),
1015 m_iMBCSChars(0) {}
1016
~CFX_RTFLine()1017 CFX_RTFLine::~CFX_RTFLine() {
1018 RemoveAll(false);
1019 }
1020
FX_RTFTEXTOBJ()1021 FX_RTFTEXTOBJ::FX_RTFTEXTOBJ()
1022 : pFont(nullptr),
1023 pRect(nullptr),
1024 wLineBreakChar(L'\n'),
1025 fFontSize(12.0f),
1026 iLength(0),
1027 iBidiLevel(0),
1028 iHorizontalScale(100),
1029 iVerticalScale(100) {}
1030
~FX_RTFTEXTOBJ()1031 FX_RTFTEXTOBJ::~FX_RTFTEXTOBJ() {}
1032