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