xref: /aosp_15_r20/external/pdfium/xfa/fgas/layout/cfgas_break.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1 // Copyright 2017 The PDFium Authors
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/cfgas_break.h"
8 
9 #include <algorithm>
10 #include <utility>
11 #include <vector>
12 
13 #include "core/fxcrt/fx_safe_types.h"
14 #include "core/fxcrt/stl_util.h"
15 #include "xfa/fgas/font/cfgas_gefont.h"
16 
17 const float CFGAS_Break::kConversionFactor = 20000.0f;
18 const int CFGAS_Break::kMinimumTabWidth = 160000;
19 
CFGAS_Break(Mask<LayoutStyle> dwLayoutStyles)20 CFGAS_Break::CFGAS_Break(Mask<LayoutStyle> dwLayoutStyles)
21     : m_dwLayoutStyles(dwLayoutStyles), m_pCurLine(&m_Lines[0]) {}
22 
23 CFGAS_Break::~CFGAS_Break() = default;
24 
Reset()25 void CFGAS_Break::Reset() {
26   m_eCharType = FX_CHARTYPE::kUnknown;
27   for (CFGAS_BreakLine& line : m_Lines)
28     line.Clear();
29 }
30 
SetLayoutStyles(Mask<LayoutStyle> dwLayoutStyles)31 void CFGAS_Break::SetLayoutStyles(Mask<LayoutStyle> dwLayoutStyles) {
32   m_dwLayoutStyles = dwLayoutStyles;
33   m_bSingleLine = !!(m_dwLayoutStyles & LayoutStyle::kSingleLine);
34   m_bCombText = !!(m_dwLayoutStyles & LayoutStyle::kCombText);
35 }
36 
SetHorizontalScale(int32_t iScale)37 void CFGAS_Break::SetHorizontalScale(int32_t iScale) {
38   iScale = std::max(iScale, 0);
39   if (m_iHorizontalScale == iScale)
40     return;
41 
42   SetBreakStatus();
43   m_iHorizontalScale = iScale;
44 }
45 
SetVerticalScale(int32_t iScale)46 void CFGAS_Break::SetVerticalScale(int32_t iScale) {
47   if (iScale < 0)
48     iScale = 0;
49   if (m_iVerticalScale == iScale)
50     return;
51 
52   SetBreakStatus();
53   m_iVerticalScale = iScale;
54 }
55 
SetFont(RetainPtr<CFGAS_GEFont> pFont)56 void CFGAS_Break::SetFont(RetainPtr<CFGAS_GEFont> pFont) {
57   if (!pFont || pFont == m_pFont)
58     return;
59 
60   SetBreakStatus();
61   m_pFont = std::move(pFont);
62 }
63 
SetFontSize(float fFontSize)64 void CFGAS_Break::SetFontSize(float fFontSize) {
65   int32_t iFontSize = FXSYS_roundf(fFontSize * 20.0f);
66   if (m_iFontSize == iFontSize)
67     return;
68 
69   SetBreakStatus();
70   m_iFontSize = iFontSize;
71 }
72 
SetBreakStatus()73 void CFGAS_Break::SetBreakStatus() {
74   ++m_dwIdentity;
75 
76   CFGAS_Char* tc = m_pCurLine->LastChar();
77   if (tc && tc->m_dwStatus == CFGAS_Char::BreakType::kNone)
78     tc->m_dwStatus = CFGAS_Char::BreakType::kPiece;
79 }
80 
IsGreaterThanLineWidth(int32_t width) const81 bool CFGAS_Break::IsGreaterThanLineWidth(int32_t width) const {
82   FX_SAFE_INT32 line_width = m_iLineWidth;
83   line_width += m_iTolerance;
84   return line_width.IsValid() && width > line_width.ValueOrDie();
85 }
86 
GetUnifiedCharType(FX_CHARTYPE chartype) const87 FX_CHARTYPE CFGAS_Break::GetUnifiedCharType(FX_CHARTYPE chartype) const {
88   return chartype >= FX_CHARTYPE::kArabicAlef ? FX_CHARTYPE::kArabic : chartype;
89 }
90 
SetTabWidth(float fTabWidth)91 void CFGAS_Break::SetTabWidth(float fTabWidth) {
92   // Note, the use of max here was only done in the TxtBreak code. Leaving this
93   // in for the RTFBreak code for consistency. If we see issues with tab widths
94   // we may need to fix this.
95   m_iTabWidth =
96       std::max(FXSYS_roundf(fTabWidth * kConversionFactor), kMinimumTabWidth);
97 }
98 
SetParagraphBreakChar(wchar_t wch)99 void CFGAS_Break::SetParagraphBreakChar(wchar_t wch) {
100   if (wch != L'\r' && wch != L'\n')
101     return;
102   m_wParagraphBreakChar = wch;
103 }
104 
SetLineBreakTolerance(float fTolerance)105 void CFGAS_Break::SetLineBreakTolerance(float fTolerance) {
106   m_iTolerance = FXSYS_roundf(fTolerance * kConversionFactor);
107 }
108 
SetCharSpace(float fCharSpace)109 void CFGAS_Break::SetCharSpace(float fCharSpace) {
110   m_iCharSpace = FXSYS_roundf(fCharSpace * kConversionFactor);
111 }
112 
SetLineBoundary(float fLineStart,float fLineEnd)113 void CFGAS_Break::SetLineBoundary(float fLineStart, float fLineEnd) {
114   if (fLineStart > fLineEnd)
115     return;
116 
117   m_iLineStart = FXSYS_roundf(fLineStart * kConversionFactor);
118   m_iLineWidth = FXSYS_roundf(fLineEnd * kConversionFactor);
119   m_pCurLine->m_iStart = std::min(m_pCurLine->m_iStart, m_iLineWidth);
120   m_pCurLine->m_iStart = std::max(m_pCurLine->m_iStart, m_iLineStart);
121 }
122 
GetLastChar(int32_t index,bool bOmitChar,bool bRichText) const123 CFGAS_Char* CFGAS_Break::GetLastChar(int32_t index,
124                                      bool bOmitChar,
125                                      bool bRichText) const {
126   std::vector<CFGAS_Char>& tca = m_pCurLine->m_LineChars;
127   if (!fxcrt::IndexInBounds(tca, index))
128     return nullptr;
129 
130   int32_t iStart = fxcrt::CollectionSize<int32_t>(tca) - 1;
131   while (iStart > -1) {
132     CFGAS_Char* pTC = &tca[iStart--];
133     if (((bRichText && pTC->m_iCharWidth < 0) || bOmitChar) &&
134         pTC->GetCharType() == FX_CHARTYPE::kCombination) {
135       continue;
136     }
137     if (--index < 0)
138       return pTC;
139   }
140   return nullptr;
141 }
142 
CountBreakPieces() const143 int32_t CFGAS_Break::CountBreakPieces() const {
144   return HasLine() ? fxcrt::CollectionSize<int32_t>(
145                          m_Lines[m_iReadyLineIndex].m_LinePieces)
146                    : 0;
147 }
148 
GetBreakPieceUnstable(int32_t index) const149 const CFGAS_BreakPiece* CFGAS_Break::GetBreakPieceUnstable(
150     int32_t index) const {
151   if (!HasLine())
152     return nullptr;
153   if (!fxcrt::IndexInBounds(m_Lines[m_iReadyLineIndex].m_LinePieces, index))
154     return nullptr;
155   return &m_Lines[m_iReadyLineIndex].m_LinePieces[index];
156 }
157 
ClearBreakPieces()158 void CFGAS_Break::ClearBreakPieces() {
159   if (HasLine())
160     m_Lines[m_iReadyLineIndex].Clear();
161   m_iReadyLineIndex = -1;
162 }
163