blob: f26bd3fa115eb369165c4a7af7ca4f80aa3e0842 [file] [log] [blame]
// 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;
}