1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
|
// Copyright 2016 The Chromium Authors
// 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 FontDescription& font_description) {
return SetSpacing(TextRunLayoutUnit(font_description.LetterSpacing()),
TextRunLayoutUnit(font_description.WordSpacing()));
}
template <typename TextContainerType>
bool ShapeResultSpacing<TextContainerType>::SetSpacing(
TextRunLayoutUnit letter_spacing,
TextRunLayoutUnit word_spacing) {
if (!letter_spacing && !word_spacing) {
has_spacing_ = false;
return false;
}
letter_spacing_ = letter_spacing;
word_spacing_ = word_spacing;
DCHECK(!normalize_space_);
allow_tabs_ = true;
has_spacing_ = true;
return true;
}
template <typename TextContainerType>
void ShapeResultSpacing<TextContainerType>::SetExpansion(
InlineLayoutUnit expansion,
TextDirection direction,
bool allows_leading_expansion,
bool allows_trailing_expansion) {
DCHECK_GT(expansion, InlineLayoutUnit());
expansion_ = expansion;
ComputeExpansion(allows_leading_expansion, allows_trailing_expansion,
direction);
has_spacing_ |= HasExpansion();
}
template <typename TextContainerType>
void ShapeResultSpacing<TextContainerType>::SetSpacingAndExpansion(
const FontDescription& font_description) {
// Available only for TextRun since it has expansion data.
NOTREACHED();
}
template <>
void ShapeResultSpacing<TextRun>::SetSpacingAndExpansion(
const FontDescription& font_description) {
SetSpacingAndExpansion(font_description, text_.NormalizeSpace());
}
template <typename TextContentType>
void ShapeResultSpacing<TextContentType>::SetSpacingAndExpansion(
const FontDescription& font_description,
bool normalize_space) {
letter_spacing_ = TextRunLayoutUnit(font_description.LetterSpacing());
word_spacing_ = TextRunLayoutUnit(font_description.WordSpacing());
expansion_ = InlineLayoutUnit();
has_spacing_ = letter_spacing_ || word_spacing_;
if (!has_spacing_)
return;
normalize_space_ = normalize_space;
allow_tabs_ = false;
}
template <typename TextContainerType>
void ShapeResultSpacing<TextContainerType>::ComputeExpansion(
bool allows_leading_expansion,
bool allows_trailing_expansion,
TextDirection direction) {
DCHECK_GT(expansion_, InlineLayoutUnit());
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);
} else {
expansion_opportunity_count_ = Character::ExpansionOpportunityCount(
text_.Span16(), direction, is_after_expansion);
}
if (is_after_expansion && !allows_trailing_expansion &&
expansion_opportunity_count_ > 0) {
--expansion_opportunity_count_;
}
if (expansion_opportunity_count_) {
expansion_per_opportunity_ =
(expansion_ / expansion_opportunity_count_).To<TextRunLayoutUnit>();
}
}
template <typename TextContainerType>
TextRunLayoutUnit ShapeResultSpacing<TextContainerType>::NextExpansion() {
if (!expansion_opportunity_count_) {
NOTREACHED();
}
is_after_expansion_ = true;
if (!--expansion_opportunity_count_) [[unlikely]] {
const TextRunLayoutUnit remaining = expansion_.To<TextRunLayoutUnit>();
expansion_ = InlineLayoutUnit();
return remaining;
}
expansion_ -= expansion_per_opportunity_.To<InlineLayoutUnit>();
return expansion_per_opportunity_;
}
template <typename TextContainerType>
TextRunLayoutUnit ShapeResultSpacing<TextContainerType>::ComputeSpacing(
const ComputeSpacingParameters& parameters,
float& offset,
bool is_cursive_script) {
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;
TextRunLayoutUnit spacing;
bool has_letter_spacing = letter_spacing_;
bool apply_letter_spacing =
RuntimeEnabledFeatures::IgnoreLetterSpacingInCursiveScriptsEnabled()
? !is_cursive_script
: true;
if (has_letter_spacing && !Character::TreatAsZeroWidthSpace(character) &&
apply_letter_spacing) {
spacing += letter_spacing_;
is_letter_spacing_applied_ = true;
}
if (treat_as_space && (allow_word_spacing_anywhere_ || index ||
character == kNoBreakSpaceCharacter)) {
spacing += word_spacing_;
is_word_spacing_applied_ = true;
}
if (!HasExpansion())
return spacing;
if (treat_as_space)
return spacing + NextExpansion();
if (text_.Is8Bit())
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)) {
if (!Character::IsDefaultIgnorable(character)) {
is_after_expansion_ = false;
}
return spacing;
}
if (!is_after_expansion_) {
// Take the expansion opportunity before this ideograph.
TextRunLayoutUnit expand_before = NextExpansion();
if (expand_before) {
offset += expand_before.ToFloat();
spacing += expand_before;
}
if (!HasExpansion())
return spacing;
}
return spacing + NextExpansion();
}
// Instantiate the template class.
template class ShapeResultSpacing<TextRun>;
template class ShapeResultSpacing<String>;
} // namespace blink
|