1 // Copyright 2017 PDFium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com 6 7 #include "xfa/fgas/layout/cfx_break.h" 8 9 #include <algorithm> 10 #include <vector> 11 12 #include "third_party/base/stl_util.h" 13 #include "xfa/fgas/font/cfgas_gefont.h" 14 15 namespace { 16 17 const int kMinimumTabWidth = 160000; 18 19 } // namespace 20 21 CFX_Break::CFX_Break(uint32_t dwLayoutStyles) 22 : m_eCharType(FX_CHARTYPE_Unknown), 23 m_bSingleLine(false), 24 m_bCombText(false), 25 m_dwIdentity(0), 26 m_dwLayoutStyles(dwLayoutStyles), 27 m_iLineStart(0), 28 m_iLineWidth(2000000), 29 m_wParagraphBreakChar(L'\n'), 30 m_iFontSize(240), 31 m_iTabWidth(720000), 32 m_iHorizontalScale(100), 33 m_iVerticalScale(100), 34 m_iTolerance(0), 35 m_iCharSpace(0), 36 m_iDefChar(0), 37 m_wDefChar(0xFEFF), 38 m_pFont(nullptr), 39 m_pCurLine(nullptr), 40 m_iReadyLineIndex(-1) { 41 m_pCurLine = &m_Line[0]; 42 } 43 44 CFX_Break::~CFX_Break() {} 45 46 void CFX_Break::Reset() { 47 m_eCharType = FX_CHARTYPE_Unknown; 48 m_Line[0].Clear(); 49 m_Line[1].Clear(); 50 } 51 52 void CFX_Break::SetLayoutStyles(uint32_t dwLayoutStyles) { 53 m_dwLayoutStyles = dwLayoutStyles; 54 m_bSingleLine = (m_dwLayoutStyles & FX_LAYOUTSTYLE_SingleLine) != 0; 55 m_bCombText = (m_dwLayoutStyles & FX_LAYOUTSTYLE_CombText) != 0; 56 } 57 58 void CFX_Break::SetHorizontalScale(int32_t iScale) { 59 iScale = std::max(iScale, 0); 60 if (m_iHorizontalScale == iScale) 61 return; 62 63 SetBreakStatus(); 64 m_iHorizontalScale = iScale; 65 } 66 67 void CFX_Break::SetVerticalScale(int32_t iScale) { 68 if (iScale < 0) 69 iScale = 0; 70 if (m_iVerticalScale == iScale) 71 return; 72 73 SetBreakStatus(); 74 m_iVerticalScale = iScale; 75 } 76 77 void CFX_Break::SetFont(const RetainPtr<CFGAS_GEFont>& pFont) { 78 if (!pFont || pFont == m_pFont) 79 return; 80 81 SetBreakStatus(); 82 m_pFont = pFont; 83 FontChanged(); 84 } 85 86 void CFX_Break::SetFontSize(float fFontSize) { 87 int32_t iFontSize = FXSYS_round(fFontSize * 20.0f); 88 if (m_iFontSize == iFontSize) 89 return; 90 91 SetBreakStatus(); 92 m_iFontSize = iFontSize; 93 FontChanged(); 94 } 95 96 void CFX_Break::SetBreakStatus() { 97 ++m_dwIdentity; 98 int32_t iCount = m_pCurLine->CountChars(); 99 if (iCount < 1) 100 return; 101 102 CFX_Char* tc = m_pCurLine->GetChar(iCount - 1); 103 if (tc->m_dwStatus == CFX_BreakType::None) 104 tc->m_dwStatus = CFX_BreakType::Piece; 105 } 106 107 FX_CHARTYPE CFX_Break::GetUnifiedCharType(FX_CHARTYPE chartype) const { 108 return chartype >= FX_CHARTYPE_ArabicAlef ? FX_CHARTYPE_Arabic : chartype; 109 } 110 111 void CFX_Break::FontChanged() { 112 m_iDefChar = 0; 113 if (!m_pFont || m_wDefChar == 0xFEFF) 114 return; 115 116 m_pFont->GetCharWidth(m_wDefChar, m_iDefChar); 117 m_iDefChar *= m_iFontSize; 118 } 119 120 void CFX_Break::SetTabWidth(float fTabWidth) { 121 // Note, the use of max here was only done in the TxtBreak code. Leaving this 122 // in for the RTFBreak code for consistency. If we see issues with tab widths 123 // we may need to fix this. 124 m_iTabWidth = std::max(FXSYS_round(fTabWidth * 20000.0f), kMinimumTabWidth); 125 } 126 127 void CFX_Break::SetDefaultChar(wchar_t wch) { 128 m_wDefChar = wch; 129 m_iDefChar = 0; 130 if (m_wDefChar == 0xFEFF || !m_pFont) 131 return; 132 133 m_pFont->GetCharWidth(m_wDefChar, m_iDefChar); 134 if (m_iDefChar < 0) 135 m_iDefChar = 0; 136 else 137 m_iDefChar *= m_iFontSize; 138 } 139 140 void CFX_Break::SetParagraphBreakChar(wchar_t wch) { 141 if (wch != L'\r' && wch != L'\n') 142 return; 143 m_wParagraphBreakChar = wch; 144 } 145 146 void CFX_Break::SetLineBreakTolerance(float fTolerance) { 147 m_iTolerance = FXSYS_round(fTolerance * 20000.0f); 148 } 149 150 void CFX_Break::SetCharSpace(float fCharSpace) { 151 m_iCharSpace = FXSYS_round(fCharSpace * 20000.0f); 152 } 153 154 void CFX_Break::SetLineBoundary(float fLineStart, float fLineEnd) { 155 if (fLineStart > fLineEnd) 156 return; 157 158 m_iLineStart = FXSYS_round(fLineStart * 20000.0f); 159 m_iLineWidth = FXSYS_round(fLineEnd * 20000.0f); 160 m_pCurLine->m_iStart = std::min(m_pCurLine->m_iStart, m_iLineWidth); 161 m_pCurLine->m_iStart = std::max(m_pCurLine->m_iStart, m_iLineStart); 162 } 163 164 CFX_Char* CFX_Break::GetLastChar(int32_t index, 165 bool bOmitChar, 166 bool bRichText) const { 167 std::vector<CFX_Char>& tca = m_pCurLine->m_LineChars; 168 if (!pdfium::IndexInBounds(tca, index)) 169 return nullptr; 170 171 int32_t iStart = pdfium::CollectionSize<int32_t>(tca) - 1; 172 while (iStart > -1) { 173 CFX_Char* pTC = &tca[iStart--]; 174 if (((bRichText && pTC->m_iCharWidth < 0) || bOmitChar) && 175 pTC->GetCharType() == FX_CHARTYPE_Combination) { 176 continue; 177 } 178 if (--index < 0) 179 return pTC; 180 } 181 return nullptr; 182 } 183 184 int32_t CFX_Break::CountBreakPieces() const { 185 return HasLine() ? pdfium::CollectionSize<int32_t>( 186 m_Line[m_iReadyLineIndex].m_LinePieces) 187 : 0; 188 } 189 190 const CFX_BreakPiece* CFX_Break::GetBreakPieceUnstable(int32_t index) const { 191 if (!HasLine()) 192 return nullptr; 193 if (!pdfium::IndexInBounds(m_Line[m_iReadyLineIndex].m_LinePieces, index)) 194 return nullptr; 195 return &m_Line[m_iReadyLineIndex].m_LinePieces[index]; 196 } 197 198 void CFX_Break::ClearBreakPieces() { 199 if (HasLine()) 200 m_Line[m_iReadyLineIndex].Clear(); 201 m_iReadyLineIndex = -1; 202 } 203