// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #include "xfa/fgas/layout/cfgas_break.h" #include #include #include #include "core/fxcrt/fx_safe_types.h" #include "core/fxcrt/stl_util.h" #include "xfa/fgas/font/cfgas_gefont.h" const float CFGAS_Break::kConversionFactor = 20000.0f; const int CFGAS_Break::kMinimumTabWidth = 160000; CFGAS_Break::CFGAS_Break(Mask dwLayoutStyles) : m_dwLayoutStyles(dwLayoutStyles), m_pCurLine(&m_Lines[0]) {} CFGAS_Break::~CFGAS_Break() = default; void CFGAS_Break::Reset() { m_eCharType = FX_CHARTYPE::kUnknown; for (CFGAS_BreakLine& line : m_Lines) line.Clear(); } void CFGAS_Break::SetLayoutStyles(Mask dwLayoutStyles) { m_dwLayoutStyles = dwLayoutStyles; m_bSingleLine = !!(m_dwLayoutStyles & LayoutStyle::kSingleLine); m_bCombText = !!(m_dwLayoutStyles & LayoutStyle::kCombText); } void CFGAS_Break::SetHorizontalScale(int32_t iScale) { iScale = std::max(iScale, 0); if (m_iHorizontalScale == iScale) return; SetBreakStatus(); m_iHorizontalScale = iScale; } void CFGAS_Break::SetVerticalScale(int32_t iScale) { if (iScale < 0) iScale = 0; if (m_iVerticalScale == iScale) return; SetBreakStatus(); m_iVerticalScale = iScale; } void CFGAS_Break::SetFont(RetainPtr pFont) { if (!pFont || pFont == m_pFont) return; SetBreakStatus(); m_pFont = std::move(pFont); } void CFGAS_Break::SetFontSize(float fFontSize) { int32_t iFontSize = FXSYS_roundf(fFontSize * 20.0f); if (m_iFontSize == iFontSize) return; SetBreakStatus(); m_iFontSize = iFontSize; } void CFGAS_Break::SetBreakStatus() { ++m_dwIdentity; CFGAS_Char* tc = m_pCurLine->LastChar(); if (tc && tc->m_dwStatus == CFGAS_Char::BreakType::kNone) tc->m_dwStatus = CFGAS_Char::BreakType::kPiece; } bool CFGAS_Break::IsGreaterThanLineWidth(int32_t width) const { FX_SAFE_INT32 line_width = m_iLineWidth; line_width += m_iTolerance; return line_width.IsValid() && width > line_width.ValueOrDie(); } FX_CHARTYPE CFGAS_Break::GetUnifiedCharType(FX_CHARTYPE chartype) const { return chartype >= FX_CHARTYPE::kArabicAlef ? FX_CHARTYPE::kArabic : chartype; } void CFGAS_Break::SetTabWidth(float fTabWidth) { // Note, the use of max here was only done in the TxtBreak code. Leaving this // in for the RTFBreak code for consistency. If we see issues with tab widths // we may need to fix this. m_iTabWidth = std::max(FXSYS_roundf(fTabWidth * kConversionFactor), kMinimumTabWidth); } void CFGAS_Break::SetParagraphBreakChar(wchar_t wch) { if (wch != L'\r' && wch != L'\n') return; m_wParagraphBreakChar = wch; } void CFGAS_Break::SetLineBreakTolerance(float fTolerance) { m_iTolerance = FXSYS_roundf(fTolerance * kConversionFactor); } void CFGAS_Break::SetCharSpace(float fCharSpace) { m_iCharSpace = FXSYS_roundf(fCharSpace * kConversionFactor); } void CFGAS_Break::SetLineBoundary(float fLineStart, float fLineEnd) { if (fLineStart > fLineEnd) return; m_iLineStart = FXSYS_roundf(fLineStart * kConversionFactor); m_iLineWidth = FXSYS_roundf(fLineEnd * kConversionFactor); m_pCurLine->m_iStart = std::min(m_pCurLine->m_iStart, m_iLineWidth); m_pCurLine->m_iStart = std::max(m_pCurLine->m_iStart, m_iLineStart); } CFGAS_Char* CFGAS_Break::GetLastChar(int32_t index, bool bOmitChar, bool bRichText) const { std::vector& tca = m_pCurLine->m_LineChars; if (!fxcrt::IndexInBounds(tca, index)) return nullptr; int32_t iStart = fxcrt::CollectionSize(tca) - 1; while (iStart > -1) { CFGAS_Char* pTC = &tca[iStart--]; if (((bRichText && pTC->m_iCharWidth < 0) || bOmitChar) && pTC->GetCharType() == FX_CHARTYPE::kCombination) { continue; } if (--index < 0) return pTC; } return nullptr; } int32_t CFGAS_Break::CountBreakPieces() const { return HasLine() ? fxcrt::CollectionSize( m_Lines[m_iReadyLineIndex].m_LinePieces) : 0; } const CFGAS_BreakPiece* CFGAS_Break::GetBreakPieceUnstable( int32_t index) const { if (!HasLine()) return nullptr; if (!fxcrt::IndexInBounds(m_Lines[m_iReadyLineIndex].m_LinePieces, index)) return nullptr; return &m_Lines[m_iReadyLineIndex].m_LinePieces[index]; } void CFGAS_Break::ClearBreakPieces() { if (HasLine()) m_Lines[m_iReadyLineIndex].Clear(); m_iReadyLineIndex = -1; }