blob: 326648748f72e865eef7b17673fbd135d9f01714 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.h"
#include "third_party/blink/renderer/platform/fonts/font.h"
#include "third_party/blink/renderer/platform/fonts/font_description.h"
#include "third_party/blink/renderer/platform/text/text_run.h"
namespace blink {
template <typename TextContainerType>
bool ShapeResultSpacing<TextContainerType>::SetSpacing(const Font& font) {
const FontDescription& font_description = font.GetFontDescription();
if (!font_description.LetterSpacing() && !font_description.WordSpacing() &&
!font.HasAdvanceOverride()) {
has_spacing_ = false;
return false;
}
letter_spacing_ = font_description.LetterSpacing();
word_spacing_ = font_description.WordSpacing();
DCHECK(!normalize_space_);
allow_tabs_ = true;
has_spacing_ = true;
return true;
}
template <typename TextContainerType>
void ShapeResultSpacing<TextContainerType>::SetExpansion(
float expansion,
TextDirection direction,
TextJustify text_justify,
bool allows_leading_expansion,
bool allows_trailing_expansion) {
DCHECK_GT(expansion, 0);
expansion_ = expansion;
ComputeExpansion(allows_leading_expansion, allows_trailing_expansion,
direction, text_justify);
has_spacing_ |= HasExpansion();
}
template <typename TextContainerType>
void ShapeResultSpacing<TextContainerType>::SetSpacingAndExpansion(
const Font& font) {
// Available only for TextRun since it has expansion data.
NOTREACHED();
}
template <>
void ShapeResultSpacing<TextRun>::SetSpacingAndExpansion(const Font& font) {
const FontDescription& font_description = font.GetFontDescription();
letter_spacing_ = font_description.LetterSpacing();
word_spacing_ = font_description.WordSpacing();
expansion_ = text_.Expansion();
has_spacing_ = letter_spacing_ || word_spacing_ || expansion_ ||
font.HasAdvanceOverride();
if (!has_spacing_)
return;
normalize_space_ = text_.NormalizeSpace();
allow_tabs_ = text_.AllowTabs();
if (expansion_) {
ComputeExpansion(text_.AllowsLeadingExpansion(),
text_.AllowsTrailingExpansion(), text_.Direction(),
text_.GetTextJustify());
}
}
template <typename TextContainerType>
void ShapeResultSpacing<TextContainerType>::ComputeExpansion(
bool allows_leading_expansion,
bool allows_trailing_expansion,
TextDirection direction,
TextJustify text_justify) {
DCHECK_GT(expansion_, 0);
text_justify_ = text_justify;
if (text_justify_ == TextJustify::kNone) {
expansion_opportunity_count_ = 0;
return;
}
is_after_expansion_ = !allows_leading_expansion;
bool is_after_expansion = is_after_expansion_;
if (text_.Is8Bit()) {
expansion_opportunity_count_ = Character::ExpansionOpportunityCount(
text_.Span8(), direction, is_after_expansion, text_justify_);
} else {
expansion_opportunity_count_ = Character::ExpansionOpportunityCount(
text_.Span16(), direction, is_after_expansion, text_justify_);
}
if (is_after_expansion && !allows_trailing_expansion) {
DCHECK_GT(expansion_opportunity_count_, 0u);
--expansion_opportunity_count_;
}
if (expansion_opportunity_count_)
expansion_per_opportunity_ = expansion_ / expansion_opportunity_count_;
}
template <typename TextContainerType>
float ShapeResultSpacing<TextContainerType>::NextExpansion() {
if (!expansion_opportunity_count_) {
NOTREACHED();
return 0;
}
is_after_expansion_ = true;
if (!--expansion_opportunity_count_) {
float remaining = expansion_;
expansion_ = 0;
return remaining;
}
expansion_ -= expansion_per_opportunity_;
return expansion_per_opportunity_;
}
template <typename TextContainerType>
float ShapeResultSpacing<TextContainerType>::ComputeSpacing(
const ComputeSpacingParameters& parameters,
float& offset) {
DCHECK(has_spacing_);
unsigned index = parameters.index;
UChar32 character = text_[index];
bool treat_as_space =
(Character::TreatAsSpace(character) ||
(normalize_space_ &&
Character::IsNormalizedCanvasSpaceCharacter(character))) &&
(character != '\t' || !allow_tabs_);
if (treat_as_space && character != kNoBreakSpaceCharacter)
character = kSpaceCharacter;
float spacing = 0;
bool has_letter_spacing =
letter_spacing_ || (parameters.advance_override != 1.0);
if (has_letter_spacing && !Character::TreatAsZeroWidthSpace(character)) {
spacing +=
parameters.original_advance * (parameters.advance_override - 1.0) +
letter_spacing_;
}
if (treat_as_space && (index || character == kNoBreakSpaceCharacter))
spacing += word_spacing_;
if (!HasExpansion())
return spacing;
if (treat_as_space)
return spacing + NextExpansion();
if (text_.Is8Bit() || text_justify_ != TextJustify::kAuto)
return spacing;
// isCJKIdeographOrSymbol() has expansion opportunities both before and
// after each character.
// http://www.w3.org/TR/jlreq/#line_adjustment
if (U16_IS_LEAD(character) && index + 1 < text_.length() &&
U16_IS_TRAIL(text_[index + 1]))
character = U16_GET_SUPPLEMENTARY(character, text_[index + 1]);
if (!Character::IsCJKIdeographOrSymbol(character)) {
is_after_expansion_ = false;
return spacing;
}
if (!is_after_expansion_) {
// Take the expansion opportunity before this ideograph.
float expand_before = NextExpansion();
if (expand_before) {
offset += expand_before;
spacing += expand_before;
}
if (!HasExpansion())
return spacing;
}
return spacing + NextExpansion();
}
// Instantiate the template class.
template class ShapeResultSpacing<TextRun>;
template class ShapeResultSpacing<String>;
} // namespace blink