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

Side by Side Diff: third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBloberizer.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
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 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/ShapeResultBloberizer.h" 5 #include "platform/fonts/shaping/ShapeResultBloberizer.h"
6 6
7 #include <hb.h>
7 #include "platform/fonts/Font.h" 8 #include "platform/fonts/Font.h"
8 #include "platform/fonts/shaping/CachingWordShaper.h" 9 #include "platform/fonts/shaping/CachingWordShaper.h"
10 #include "platform/fonts/shaping/ShapeResult.h"
11 #include "platform/fonts/shaping/ShapeResultInlineHeaders.h"
12 #include "platform/text/TextBreakIterator.h"
9 #include "platform/text/TextRun.h" 13 #include "platform/text/TextRun.h"
10 14
11 namespace blink { 15 namespace blink {
12 16
13 ShapeResultBloberizer::ShapeResultBloberizer(const Font& font, 17 ShapeResultBloberizer::ShapeResultBloberizer(const Font& font,
14 float device_scale_factor, 18 float device_scale_factor,
15 Type type) 19 Type type)
16 : font_(font), device_scale_factor_(device_scale_factor), type_(type) {} 20 : font_(font), device_scale_factor_(device_scale_factor), type_(type) {}
17 21
18 bool ShapeResultBloberizer::HasPendingVerticalOffsets() const { 22 bool ShapeResultBloberizer::HasPendingVerticalOffsets() const {
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
74 ShapeResultBloberizer::BlobRotation ShapeResultBloberizer::GetBlobRotation( 78 ShapeResultBloberizer::BlobRotation ShapeResultBloberizer::GetBlobRotation(
75 const SimpleFontData* font_data) { 79 const SimpleFontData* font_data) {
76 // For vertical upright text we need to compensate the inherited 90deg CW 80 // For vertical upright text we need to compensate the inherited 90deg CW
77 // rotation (using a 90deg CCW rotation). 81 // rotation (using a 90deg CCW rotation).
78 return (font_data->PlatformData().IsVerticalAnyUpright() && 82 return (font_data->PlatformData().IsVerticalAnyUpright() &&
79 font_data->VerticalData()) 83 font_data->VerticalData())
80 ? BlobRotation::kCCWRotation 84 ? BlobRotation::kCCWRotation
81 : BlobRotation::kNoRotation; 85 : BlobRotation::kNoRotation;
82 } 86 }
83 87
88 float ShapeResultBloberizer::FillGlyphs(
89 const TextRunPaintInfo& run_info,
90 const ShapeResultBuffer& result_buffer) {
91 // Fast path: full run with no vertical offsets, no text intercepts.
92 if (!run_info.from && run_info.to == run_info.run.length() &&
93 !result_buffer.HasVerticalOffsets() &&
94 GetType() != ShapeResultBloberizer::Type::kTextIntercepts) {
95 return FillFastHorizontalGlyphs(result_buffer, run_info.run);
96 }
97
98 float advance = 0;
99 auto results = result_buffer.results_;
100
101 if (run_info.run.Rtl()) {
102 unsigned word_offset = run_info.run.length();
103 for (unsigned j = 0; j < results.size(); j++) {
104 unsigned resolved_index = results.size() - 1 - j;
105 const RefPtr<const ShapeResult>& word_result = results[resolved_index];
106 word_offset -= word_result->NumCharacters();
107 advance =
108 FillGlyphsForResult(*word_result, run_info, advance, word_offset);
109 }
110 } else {
111 unsigned word_offset = 0;
112 for (const auto& word_result : results) {
113 advance =
114 FillGlyphsForResult(*word_result, run_info, advance, word_offset);
115 word_offset += word_result->NumCharacters();
116 }
117 }
118
119 return advance;
120 }
121
122 void ShapeResultBloberizer::FillTextEmphasisGlyphs(
123 const TextRunPaintInfo& run_info,
124 const GlyphData& emphasis_data,
125 const ShapeResultBuffer& result_buffer) {
126 float advance = 0;
127 unsigned word_offset = run_info.run.Rtl() ? run_info.run.length() : 0;
128 auto results = result_buffer.results_;
129
130 for (unsigned j = 0; j < results.size(); j++) {
131 unsigned resolved_index = run_info.run.Rtl() ? results.size() - 1 - j : j;
132 const RefPtr<const ShapeResult>& word_result = results[resolved_index];
133 for (unsigned i = 0; i < word_result->runs_.size(); i++) {
134 unsigned resolved_offset =
135 word_offset - (run_info.run.Rtl() ? word_result->NumCharacters() : 0);
136 advance +=
137 FillTextEmphasisGlyphsForRun(word_result->runs_[i].get(), run_info,
138 emphasis_data, advance, resolved_offset);
139 }
140 word_offset += word_result->NumCharacters() * (run_info.run.Rtl() ? -1 : 1);
141 }
142 }
143
144 namespace {
145
146 inline bool IsSkipInkException(const ShapeResultBloberizer& bloberizer,
147 const TextRun& run,
148 unsigned character_index) {
149 // We want to skip descenders in general, but it is undesirable renderings for
150 // CJK characters.
151 return bloberizer.GetType() == ShapeResultBloberizer::Type::kTextIntercepts &&
152 !run.Is8Bit() &&
153 Character::IsCJKIdeographOrSymbol(run.CodepointAt(character_index));
154 }
155
156 inline void AddGlyphToBloberizer(ShapeResultBloberizer& bloberizer,
157 float advance,
158 hb_direction_t direction,
159 const SimpleFontData* font_data,
160 const HarfBuzzRunGlyphData& glyph_data,
161 const TextRun& run,
162 unsigned character_index) {
163 FloatPoint start_offset = HB_DIRECTION_IS_HORIZONTAL(direction)
164 ? FloatPoint(advance, 0)
165 : FloatPoint(0, advance);
166 if (!IsSkipInkException(bloberizer, run, character_index)) {
167 bloberizer.Add(glyph_data.glyph, font_data,
168 start_offset + glyph_data.offset);
169 }
170 }
171
172 inline void AddEmphasisMark(ShapeResultBloberizer& bloberizer,
173 const GlyphData& emphasis_data,
174 FloatPoint glyph_center,
175 float mid_glyph_offset) {
176 const SimpleFontData* emphasis_font_data = emphasis_data.font_data;
177 DCHECK(emphasis_font_data);
178
179 bool is_vertical =
180 emphasis_font_data->PlatformData().IsVerticalAnyUpright() &&
181 emphasis_font_data->VerticalData();
182
183 if (!is_vertical) {
184 bloberizer.Add(emphasis_data.glyph, emphasis_font_data,
185 mid_glyph_offset - glyph_center.X());
186 } else {
187 bloberizer.Add(
188 emphasis_data.glyph, emphasis_font_data,
189 FloatPoint(-glyph_center.X(), mid_glyph_offset - glyph_center.Y()));
190 }
191 }
192
193 inline unsigned CountGraphemesInCluster(const UChar* str,
194 unsigned str_length,
195 uint16_t start_index,
196 uint16_t end_index) {
197 if (start_index > end_index) {
198 uint16_t temp_index = start_index;
199 start_index = end_index;
200 end_index = temp_index;
201 }
202 uint16_t length = end_index - start_index;
203 DCHECK_LE(static_cast<unsigned>(start_index + length), str_length);
204 TextBreakIterator* cursor_pos_iterator =
205 CursorMovementIterator(&str[start_index], length);
206
207 int cursor_pos = cursor_pos_iterator->current();
208 int num_graphemes = -1;
209 while (0 <= cursor_pos) {
210 cursor_pos = cursor_pos_iterator->next();
211 num_graphemes++;
212 }
213 return std::max(0, num_graphemes);
214 }
215
216 } // namespace
217
218 float ShapeResultBloberizer::FillGlyphsForResult(
219 const ShapeResult& result,
220 const TextRunPaintInfo& run_info,
221 float initial_advance,
222 unsigned run_offset) {
223 auto total_advance = initial_advance;
224
225 for (const auto& run : result.runs_) {
226 total_advance = run->ForEachGlyphInRange(
227 total_advance, run_info.from, run_info.to, run_offset,
228 [&](const HarfBuzzRunGlyphData& glyph_data, float total_advance,
229 uint16_t character_index) -> bool {
230
231 AddGlyphToBloberizer(*this, total_advance, run->direction_,
232 run->font_data_.Get(), glyph_data, run_info.run,
233 character_index);
234 return true;
235 });
236 }
237
238 return total_advance;
239 }
240
241 float ShapeResultBloberizer::FillFastHorizontalGlyphs(
242 const ShapeResultBuffer& result_buffer,
243 const TextRun& text_run) {
244 DCHECK(!result_buffer.HasVerticalOffsets());
245 DCHECK_NE(GetType(), ShapeResultBloberizer::Type::kTextIntercepts);
246
247 float advance = 0;
248 auto results = result_buffer.results_;
249
250 for (unsigned i = 0; i < results.size(); ++i) {
251 const auto& word_result = IsLeftToRightDirection(text_run.Direction())
252 ? results[i]
253 : results[results.size() - 1 - i];
254 DCHECK(!word_result->HasVerticalOffsets());
255
256 for (const auto& run : word_result->runs_) {
257 DCHECK(run);
258 DCHECK(HB_DIRECTION_IS_HORIZONTAL(run->direction_));
259
260 advance =
261 run->ForEachGlyph(advance,
262 [&](const HarfBuzzRunGlyphData& glyph_data,
263 float total_advance) -> bool {
264 DCHECK(!glyph_data.offset.Height());
265 Add(glyph_data.glyph, run->font_data_.Get(),
266 total_advance + glyph_data.offset.Width());
267 return true;
268 });
269 }
270 }
271
272 return advance;
273 }
274
275 float ShapeResultBloberizer::FillTextEmphasisGlyphsForRun(
276 const ShapeResult::RunInfo* run,
277 const TextRunPaintInfo& run_info,
278 const GlyphData& emphasis_data,
279 float initial_advance,
280 unsigned run_offset) {
281 if (!run)
282 return 0;
283
284 unsigned graphemes_in_cluster = 1;
285 float cluster_advance = 0;
286
287 FloatPoint glyph_center =
288 emphasis_data.font_data->BoundsForGlyph(emphasis_data.glyph).Center();
289
290 const auto& text_run = run_info.run;
291 const auto from = run_info.from;
292 const auto to = run_info.to;
293
294 TextDirection direction = text_run.Direction();
295
296 // A "cluster" in this context means a cluster as it is used by HarfBuzz:
297 // The minimal group of characters and corresponding glyphs, that cannot be
298 // broken down further from a text shaping point of view. A cluster can
299 // contain multiple glyphs and grapheme clusters, with mutually overlapping
300 // boundaries. Below we count grapheme clusters per HarfBuzz clusters, then
301 // linearly split the sum of corresponding glyph advances by the number of
302 // grapheme clusters in order to find positions for emphasis mark drawing.
303 uint16_t cluster_start = static_cast<uint16_t>(
304 direction == TextDirection::kRtl
305 ? run->start_index_ + run->num_characters_ + run_offset
306 : run->GlyphToCharacterIndex(0) + run_offset);
307
308 float advance_so_far = initial_advance;
309 const unsigned num_glyphs = run->glyph_data_.size();
310 for (unsigned i = 0; i < num_glyphs; ++i) {
311 const HarfBuzzRunGlyphData& glyph_data = run->glyph_data_[i];
312 uint16_t current_character_index =
313 run->start_index_ + glyph_data.character_index + run_offset;
314 bool is_run_end = (i + 1 == num_glyphs);
315 bool is_cluster_end =
316 is_run_end || (run->GlyphToCharacterIndex(i + 1) + run_offset !=
317 current_character_index);
318
319 if ((direction == TextDirection::kRtl && current_character_index >= to) ||
320 (direction != TextDirection::kRtl && current_character_index < from)) {
321 advance_so_far += glyph_data.advance;
322 direction == TextDirection::kRtl ? --cluster_start : ++cluster_start;
323 continue;
324 }
325
326 cluster_advance += glyph_data.advance;
327
328 if (text_run.Is8Bit()) {
329 float glyph_advance_x = glyph_data.advance;
330 if (Character::CanReceiveTextEmphasis(
331 text_run[current_character_index])) {
332 AddEmphasisMark(*this, emphasis_data, glyph_center,
333 advance_so_far + glyph_advance_x / 2);
334 }
335 advance_so_far += glyph_advance_x;
336 } else if (is_cluster_end) {
337 uint16_t cluster_end;
338 if (direction == TextDirection::kRtl) {
339 cluster_end = current_character_index;
340 } else {
341 cluster_end = static_cast<uint16_t>(
342 is_run_end ? run->start_index_ + run->num_characters_ + run_offset
343 : run->GlyphToCharacterIndex(i + 1) + run_offset);
344 }
345 graphemes_in_cluster = CountGraphemesInCluster(
346 text_run.Characters16(), text_run.CharactersLength(), cluster_start,
347 cluster_end);
348 if (!graphemes_in_cluster || !cluster_advance)
349 continue;
350
351 float glyph_advance_x = cluster_advance / graphemes_in_cluster;
352 for (unsigned j = 0; j < graphemes_in_cluster; ++j) {
353 // Do not put emphasis marks on space, separator, and control
354 // characters.
355 if (Character::CanReceiveTextEmphasis(
356 text_run[current_character_index])) {
357 AddEmphasisMark(*this, emphasis_data, glyph_center,
358 advance_so_far + glyph_advance_x / 2);
359 }
360 advance_so_far += glyph_advance_x;
361 }
362 cluster_start = cluster_end;
363 cluster_advance = 0;
364 }
365 }
366 return advance_so_far - initial_advance;
367 }
368
84 } // namespace blink 369 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698