Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(101)

Side by Side Diff: third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBuffer.cpp

Issue 2835103002: Move blobalizer implementation to ShapeResultBloberizer (Closed)
Patch Set: Fix canvas tests Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBuffer.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "platform/fonts/shaping/ShapeResultBuffer.h" 5 #include "platform/fonts/shaping/ShapeResultBuffer.h"
6 6
7 #include "platform/fonts/CharacterRange.h" 7 #include "platform/fonts/CharacterRange.h"
8 #include "platform/fonts/SimpleFontData.h" 8 #include "platform/fonts/SimpleFontData.h"
9 #include "platform/fonts/shaping/ShapeResultBloberizer.h"
10 #include "platform/fonts/shaping/ShapeResultInlineHeaders.h" 9 #include "platform/fonts/shaping/ShapeResultInlineHeaders.h"
11 #include "platform/geometry/FloatPoint.h" 10 #include "platform/geometry/FloatPoint.h"
12 #include "platform/text/Character.h"
13 #include "platform/text/TextBreakIterator.h"
14 #include "platform/text/TextDirection.h" 11 #include "platform/text/TextDirection.h"
15 12
16 namespace blink { 13 namespace blink {
17 14
18 namespace {
19
20 inline bool IsSkipInkException(const ShapeResultBloberizer& bloberizer,
21 const TextRun& run,
22 unsigned character_index) {
23 // We want to skip descenders in general, but it is undesirable renderings for
24 // CJK characters.
25 return bloberizer.GetType() == ShapeResultBloberizer::Type::kTextIntercepts &&
26 !run.Is8Bit() &&
27 Character::IsCJKIdeographOrSymbol(run.CodepointAt(character_index));
28 }
29
30 inline void AddGlyphToBloberizer(ShapeResultBloberizer& bloberizer,
31 float advance,
32 hb_direction_t direction,
33 const SimpleFontData* font_data,
34 const HarfBuzzRunGlyphData& glyph_data,
35 const TextRun& run,
36 unsigned character_index) {
37 FloatPoint start_offset = HB_DIRECTION_IS_HORIZONTAL(direction)
38 ? FloatPoint(advance, 0)
39 : FloatPoint(0, advance);
40 if (!IsSkipInkException(bloberizer, run, character_index))
41 bloberizer.Add(glyph_data.glyph, font_data,
42 start_offset + glyph_data.offset);
43 }
44
45 inline void AddEmphasisMark(ShapeResultBloberizer& bloberizer,
46 const GlyphData& emphasis_data,
47 FloatPoint glyph_center,
48 float mid_glyph_offset) {
49 const SimpleFontData* emphasis_font_data = emphasis_data.font_data;
50 DCHECK(emphasis_font_data);
51
52 bool is_vertical =
53 emphasis_font_data->PlatformData().IsVerticalAnyUpright() &&
54 emphasis_font_data->VerticalData();
55
56 if (!is_vertical) {
57 bloberizer.Add(emphasis_data.glyph, emphasis_font_data,
58 mid_glyph_offset - glyph_center.X());
59 } else {
60 bloberizer.Add(
61 emphasis_data.glyph, emphasis_font_data,
62 FloatPoint(-glyph_center.X(), mid_glyph_offset - glyph_center.Y()));
63 }
64 }
65
66 inline unsigned CountGraphemesInCluster(const UChar* str,
67 unsigned str_length,
68 uint16_t start_index,
69 uint16_t end_index) {
70 if (start_index > end_index) {
71 uint16_t temp_index = start_index;
72 start_index = end_index;
73 end_index = temp_index;
74 }
75 uint16_t length = end_index - start_index;
76 DCHECK_LE(static_cast<unsigned>(start_index + length), str_length);
77 TextBreakIterator* cursor_pos_iterator =
78 CursorMovementIterator(&str[start_index], length);
79
80 int cursor_pos = cursor_pos_iterator->current();
81 int num_graphemes = -1;
82 while (0 <= cursor_pos) {
83 cursor_pos = cursor_pos_iterator->next();
84 num_graphemes++;
85 }
86 return std::max(0, num_graphemes);
87 }
88
89 } // anonymous namespace
90
91 float ShapeResultBuffer::FillGlyphsForResult(ShapeResultBloberizer& bloberizer,
92 const ShapeResult& result,
93 const TextRunPaintInfo& run_info,
94 float initial_advance,
95 unsigned run_offset) {
96 auto total_advance = initial_advance;
97
98 for (const auto& run : result.runs_) {
99 total_advance = run->ForEachGlyphInRange(
100 total_advance, run_info.from, run_info.to, run_offset,
101 [&](const HarfBuzzRunGlyphData& glyph_data, float total_advance,
102 uint16_t character_index) -> bool {
103
104 AddGlyphToBloberizer(bloberizer, total_advance, run->direction_,
105 run->font_data_.Get(), glyph_data, run_info.run,
106 character_index);
107 return true;
108 });
109 }
110
111 return total_advance;
112 }
113
114 float ShapeResultBuffer::FillTextEmphasisGlyphsForRun(
115 ShapeResultBloberizer& bloberizer,
116 const ShapeResult::RunInfo* run,
117 const TextRunPaintInfo& run_info,
118 const GlyphData& emphasis_data,
119 float initial_advance,
120 unsigned run_offset) {
121 if (!run)
122 return 0;
123
124 unsigned graphemes_in_cluster = 1;
125 float cluster_advance = 0;
126
127 FloatPoint glyph_center =
128 emphasis_data.font_data->BoundsForGlyph(emphasis_data.glyph).Center();
129
130 const auto& text_run = run_info.run;
131 const auto from = run_info.from;
132 const auto to = run_info.to;
133
134 TextDirection direction = text_run.Direction();
135
136 // A "cluster" in this context means a cluster as it is used by HarfBuzz:
137 // The minimal group of characters and corresponding glyphs, that cannot be
138 // broken down further from a text shaping point of view. A cluster can
139 // contain multiple glyphs and grapheme clusters, with mutually overlapping
140 // boundaries. Below we count grapheme clusters per HarfBuzz clusters, then
141 // linearly split the sum of corresponding glyph advances by the number of
142 // grapheme clusters in order to find positions for emphasis mark drawing.
143 uint16_t cluster_start = static_cast<uint16_t>(
144 direction == TextDirection::kRtl
145 ? run->start_index_ + run->num_characters_ + run_offset
146 : run->GlyphToCharacterIndex(0) + run_offset);
147
148 float advance_so_far = initial_advance;
149 const unsigned num_glyphs = run->glyph_data_.size();
150 for (unsigned i = 0; i < num_glyphs; ++i) {
151 const HarfBuzzRunGlyphData& glyph_data = run->glyph_data_[i];
152 uint16_t current_character_index =
153 run->start_index_ + glyph_data.character_index + run_offset;
154 bool is_run_end = (i + 1 == num_glyphs);
155 bool is_cluster_end =
156 is_run_end || (run->GlyphToCharacterIndex(i + 1) + run_offset !=
157 current_character_index);
158
159 if ((direction == TextDirection::kRtl && current_character_index >= to) ||
160 (direction != TextDirection::kRtl && current_character_index < from)) {
161 advance_so_far += glyph_data.advance;
162 direction == TextDirection::kRtl ? --cluster_start : ++cluster_start;
163 continue;
164 }
165
166 cluster_advance += glyph_data.advance;
167
168 if (text_run.Is8Bit()) {
169 float glyph_advance_x = glyph_data.advance;
170 if (Character::CanReceiveTextEmphasis(
171 text_run[current_character_index])) {
172 AddEmphasisMark(bloberizer, emphasis_data, glyph_center,
173 advance_so_far + glyph_advance_x / 2);
174 }
175 advance_so_far += glyph_advance_x;
176 } else if (is_cluster_end) {
177 uint16_t cluster_end;
178 if (direction == TextDirection::kRtl)
179 cluster_end = current_character_index;
180 else
181 cluster_end = static_cast<uint16_t>(
182 is_run_end ? run->start_index_ + run->num_characters_ + run_offset
183 : run->GlyphToCharacterIndex(i + 1) + run_offset);
184
185 graphemes_in_cluster = CountGraphemesInCluster(
186 text_run.Characters16(), text_run.CharactersLength(), cluster_start,
187 cluster_end);
188 if (!graphemes_in_cluster || !cluster_advance)
189 continue;
190
191 float glyph_advance_x = cluster_advance / graphemes_in_cluster;
192 for (unsigned j = 0; j < graphemes_in_cluster; ++j) {
193 // Do not put emphasis marks on space, separator, and control
194 // characters.
195 if (Character::CanReceiveTextEmphasis(
196 text_run[current_character_index]))
197 AddEmphasisMark(bloberizer, emphasis_data, glyph_center,
198 advance_so_far + glyph_advance_x / 2);
199 advance_so_far += glyph_advance_x;
200 }
201 cluster_start = cluster_end;
202 cluster_advance = 0;
203 }
204 }
205 return advance_so_far - initial_advance;
206 }
207
208 float ShapeResultBuffer::FillFastHorizontalGlyphs(
209 const TextRun& text_run,
210 ShapeResultBloberizer& bloberizer) const {
211 DCHECK(!HasVerticalOffsets());
212 DCHECK_NE(bloberizer.GetType(), ShapeResultBloberizer::Type::kTextIntercepts);
213
214 float advance = 0;
215
216 for (unsigned i = 0; i < results_.size(); ++i) {
217 const auto& word_result = IsLeftToRightDirection(text_run.Direction())
218 ? results_[i]
219 : results_[results_.size() - 1 - i];
220 DCHECK(!word_result->HasVerticalOffsets());
221
222 for (const auto& run : word_result->runs_) {
223 DCHECK(run);
224 DCHECK(HB_DIRECTION_IS_HORIZONTAL(run->direction_));
225
226 advance = run->ForEachGlyph(
227 advance,
228 [&](const HarfBuzzRunGlyphData& glyph_data,
229 float total_advance) -> bool {
230 DCHECK(!glyph_data.offset.Height());
231 bloberizer.Add(glyph_data.glyph, run->font_data_.Get(),
232 total_advance + glyph_data.offset.Width());
233 return true;
234 });
235 }
236 }
237
238 return advance;
239 }
240
241 float ShapeResultBuffer::FillGlyphs(const TextRunPaintInfo& run_info,
242 ShapeResultBloberizer& bloberizer) const {
243 // Fast path: full run with no vertical offsets, no text intercepts.
244 if (!run_info.from && run_info.to == run_info.run.length() &&
245 !HasVerticalOffsets() &&
246 bloberizer.GetType() != ShapeResultBloberizer::Type::kTextIntercepts) {
247 return FillFastHorizontalGlyphs(run_info.run, bloberizer);
248 }
249
250 float advance = 0;
251
252 if (run_info.run.Rtl()) {
253 unsigned word_offset = run_info.run.length();
254 for (unsigned j = 0; j < results_.size(); j++) {
255 unsigned resolved_index = results_.size() - 1 - j;
256 const RefPtr<const ShapeResult>& word_result = results_[resolved_index];
257 word_offset -= word_result->NumCharacters();
258 advance = FillGlyphsForResult(bloberizer, *word_result, run_info, advance,
259 word_offset);
260 }
261 } else {
262 unsigned word_offset = 0;
263 for (const auto& word_result : results_) {
264 advance = FillGlyphsForResult(bloberizer, *word_result, run_info, advance,
265 word_offset);
266 word_offset += word_result->NumCharacters();
267 }
268 }
269
270 return advance;
271 }
272
273 void ShapeResultBuffer::FillTextEmphasisGlyphs(
274 const TextRunPaintInfo& run_info,
275 const GlyphData& emphasis_data,
276 ShapeResultBloberizer& bloberizer) const {
277 float advance = 0;
278 unsigned word_offset = run_info.run.Rtl() ? run_info.run.length() : 0;
279
280 for (unsigned j = 0; j < results_.size(); j++) {
281 unsigned resolved_index = run_info.run.Rtl() ? results_.size() - 1 - j : j;
282 const RefPtr<const ShapeResult>& word_result = results_[resolved_index];
283 for (unsigned i = 0; i < word_result->runs_.size(); i++) {
284 unsigned resolved_offset =
285 word_offset - (run_info.run.Rtl() ? word_result->NumCharacters() : 0);
286 advance += FillTextEmphasisGlyphsForRun(
287 bloberizer, word_result->runs_[i].get(), run_info, emphasis_data,
288 advance, resolved_offset);
289 }
290 word_offset += word_result->NumCharacters() * (run_info.run.Rtl() ? -1 : 1);
291 }
292 }
293
294 // TODO(eae): This is a bit of a hack to allow reuse of the implementation 15 // TODO(eae): This is a bit of a hack to allow reuse of the implementation
295 // for both ShapeResultBuffer and single ShapeResult use cases. Ideally the 16 // for both ShapeResultBuffer and single ShapeResult use cases. Ideally the
296 // logic should move into ShapeResult itself and then the ShapeResultBuffer 17 // logic should move into ShapeResult itself and then the ShapeResultBuffer
297 // implementation may wrap that. 18 // implementation may wrap that.
298 CharacterRange ShapeResultBuffer::GetCharacterRange( 19 CharacterRange ShapeResultBuffer::GetCharacterRange(
299 RefPtr<const ShapeResult> result, 20 RefPtr<const ShapeResult> result,
300 TextDirection direction, 21 TextDirection direction,
301 float total_width, 22 float total_width,
302 unsigned from, 23 unsigned from,
303 unsigned to) { 24 unsigned to) {
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after
502 return GlyphData( 223 return GlyphData(
503 run->glyph_data_[0].glyph, 224 run->glyph_data_[0].glyph,
504 run->font_data_->EmphasisMarkFontData(font_description).Get()); 225 run->font_data_->EmphasisMarkFontData(font_description).Get());
505 } 226 }
506 } 227 }
507 228
508 return GlyphData(); 229 return GlyphData();
509 } 230 }
510 231
511 } // namespace blink 232 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBuffer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698