| // 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 <algorithm> |
| #include <utility> |
| #include <vector> |
| |
| #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<LayoutStyle> dwLayoutStyles) |
| : layout_styles_(dwLayoutStyles), cur_line_(&lines_[0]) {} |
| |
| CFGAS_Break::~CFGAS_Break() = default; |
| |
| void CFGAS_Break::Reset() { |
| char_type_ = FX_CHARTYPE::kUnknown; |
| for (CFGAS_BreakLine& line : lines_) { |
| line.Clear(); |
| } |
| } |
| |
| void CFGAS_Break::SetLayoutStyles(Mask<LayoutStyle> dwLayoutStyles) { |
| layout_styles_ = dwLayoutStyles; |
| single_line_ = !!(layout_styles_ & LayoutStyle::kSingleLine); |
| comb_text_ = !!(layout_styles_ & LayoutStyle::kCombText); |
| } |
| |
| void CFGAS_Break::SetHorizontalScale(int32_t iScale) { |
| iScale = std::max(iScale, 0); |
| if (horizontal_scale_ == iScale) { |
| return; |
| } |
| |
| SetBreakStatus(); |
| horizontal_scale_ = iScale; |
| } |
| |
| void CFGAS_Break::SetVerticalScale(int32_t iScale) { |
| if (iScale < 0) |
| iScale = 0; |
| if (vertical_scale_ == iScale) { |
| return; |
| } |
| |
| SetBreakStatus(); |
| vertical_scale_ = iScale; |
| } |
| |
| void CFGAS_Break::SetFont(RetainPtr<CFGAS_GEFont> pFont) { |
| if (!pFont || pFont == font_) { |
| return; |
| } |
| |
| SetBreakStatus(); |
| font_ = std::move(pFont); |
| } |
| |
| void CFGAS_Break::SetFontSize(float fFontSize) { |
| int32_t iFontSize = FXSYS_roundf(fFontSize * 20.0f); |
| if (font_size_ == iFontSize) { |
| return; |
| } |
| |
| SetBreakStatus(); |
| font_size_ = iFontSize; |
| } |
| |
| void CFGAS_Break::SetBreakStatus() { |
| ++identity_; |
| |
| CFGAS_Char* tc = cur_line_->LastChar(); |
| if (tc && tc->status_ == CFGAS_Char::BreakType::kNone) { |
| tc->status_ = CFGAS_Char::BreakType::kPiece; |
| } |
| } |
| |
| bool CFGAS_Break::IsGreaterThanLineWidth(int32_t width) const { |
| FX_SAFE_INT32 line_width = line_width_; |
| line_width += tolerance_; |
| 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. |
| tab_width_ = |
| std::max(FXSYS_roundf(fTabWidth * kConversionFactor), kMinimumTabWidth); |
| } |
| |
| void CFGAS_Break::SetParagraphBreakChar(wchar_t wch) { |
| if (wch != L'\r' && wch != L'\n') |
| return; |
| w_paragraph_break_char_ = wch; |
| } |
| |
| void CFGAS_Break::SetLineBreakTolerance(float fTolerance) { |
| tolerance_ = FXSYS_roundf(fTolerance * kConversionFactor); |
| } |
| |
| void CFGAS_Break::SetCharSpace(float fCharSpace) { |
| char_space_ = FXSYS_roundf(fCharSpace * kConversionFactor); |
| } |
| |
| void CFGAS_Break::SetLineBoundary(float fLineStart, float fLineEnd) { |
| if (fLineStart > fLineEnd) |
| return; |
| |
| line_start_ = FXSYS_roundf(fLineStart * kConversionFactor); |
| line_width_ = FXSYS_roundf(fLineEnd * kConversionFactor); |
| cur_line_->start_ = std::min(cur_line_->start_, line_width_); |
| cur_line_->start_ = std::max(cur_line_->start_, line_start_); |
| } |
| |
| CFGAS_Char* CFGAS_Break::GetLastChar(int32_t index, |
| bool bOmitChar, |
| bool bRichText) const { |
| std::vector<CFGAS_Char>& tca = cur_line_->line_chars_; |
| if (!fxcrt::IndexInBounds(tca, index)) |
| return nullptr; |
| |
| int32_t iStart = fxcrt::CollectionSize<int32_t>(tca) - 1; |
| while (iStart > -1) { |
| CFGAS_Char* pTC = &tca[iStart--]; |
| if (((bRichText && pTC->char_width_ < 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<int32_t>( |
| lines_[ready_line_index_].line_pieces_) |
| : 0; |
| } |
| |
| const CFGAS_BreakPiece* CFGAS_Break::GetBreakPieceUnstable( |
| int32_t index) const { |
| if (!HasLine()) |
| return nullptr; |
| if (!fxcrt::IndexInBounds(lines_[ready_line_index_].line_pieces_, index)) { |
| return nullptr; |
| } |
| return &lines_[ready_line_index_].line_pieces_[index]; |
| } |
| |
| void CFGAS_Break::ClearBreakPieces() { |
| if (HasLine()) |
| lines_[ready_line_index_].Clear(); |
| ready_line_index_ = -1; |
| } |