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

Unified 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, 8 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 side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBloberizer.cpp
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBloberizer.cpp b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBloberizer.cpp
index f04be8e616aa1197b0f8fbfb90b5e51654e4a262..ad1a6b7ebac3fafde8e619a96584abdffa9caa9a 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBloberizer.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBloberizer.cpp
@@ -4,8 +4,12 @@
#include "platform/fonts/shaping/ShapeResultBloberizer.h"
+#include <hb.h>
#include "platform/fonts/Font.h"
#include "platform/fonts/shaping/CachingWordShaper.h"
+#include "platform/fonts/shaping/ShapeResult.h"
+#include "platform/fonts/shaping/ShapeResultInlineHeaders.h"
+#include "platform/text/TextBreakIterator.h"
#include "platform/text/TextRun.h"
namespace blink {
@@ -81,4 +85,285 @@ ShapeResultBloberizer::BlobRotation ShapeResultBloberizer::GetBlobRotation(
: BlobRotation::kNoRotation;
}
+float ShapeResultBloberizer::FillGlyphs(
+ const TextRunPaintInfo& run_info,
+ const ShapeResultBuffer& result_buffer) {
+ // Fast path: full run with no vertical offsets, no text intercepts.
+ if (!run_info.from && run_info.to == run_info.run.length() &&
+ !result_buffer.HasVerticalOffsets() &&
+ GetType() != ShapeResultBloberizer::Type::kTextIntercepts) {
+ return FillFastHorizontalGlyphs(result_buffer, run_info.run);
+ }
+
+ float advance = 0;
+ auto results = result_buffer.results_;
+
+ if (run_info.run.Rtl()) {
+ unsigned word_offset = run_info.run.length();
+ for (unsigned j = 0; j < results.size(); j++) {
+ unsigned resolved_index = results.size() - 1 - j;
+ const RefPtr<const ShapeResult>& word_result = results[resolved_index];
+ word_offset -= word_result->NumCharacters();
+ advance =
+ FillGlyphsForResult(*word_result, run_info, advance, word_offset);
+ }
+ } else {
+ unsigned word_offset = 0;
+ for (const auto& word_result : results) {
+ advance =
+ FillGlyphsForResult(*word_result, run_info, advance, word_offset);
+ word_offset += word_result->NumCharacters();
+ }
+ }
+
+ return advance;
+}
+
+void ShapeResultBloberizer::FillTextEmphasisGlyphs(
+ const TextRunPaintInfo& run_info,
+ const GlyphData& emphasis_data,
+ const ShapeResultBuffer& result_buffer) {
+ float advance = 0;
+ unsigned word_offset = run_info.run.Rtl() ? run_info.run.length() : 0;
+ auto results = result_buffer.results_;
+
+ for (unsigned j = 0; j < results.size(); j++) {
+ unsigned resolved_index = run_info.run.Rtl() ? results.size() - 1 - j : j;
+ const RefPtr<const ShapeResult>& word_result = results[resolved_index];
+ for (unsigned i = 0; i < word_result->runs_.size(); i++) {
+ unsigned resolved_offset =
+ word_offset - (run_info.run.Rtl() ? word_result->NumCharacters() : 0);
+ advance +=
+ FillTextEmphasisGlyphsForRun(word_result->runs_[i].get(), run_info,
+ emphasis_data, advance, resolved_offset);
+ }
+ word_offset += word_result->NumCharacters() * (run_info.run.Rtl() ? -1 : 1);
+ }
+}
+
+namespace {
+
+inline bool IsSkipInkException(const ShapeResultBloberizer& bloberizer,
+ const TextRun& run,
+ unsigned character_index) {
+ // We want to skip descenders in general, but it is undesirable renderings for
+ // CJK characters.
+ return bloberizer.GetType() == ShapeResultBloberizer::Type::kTextIntercepts &&
+ !run.Is8Bit() &&
+ Character::IsCJKIdeographOrSymbol(run.CodepointAt(character_index));
+}
+
+inline void AddGlyphToBloberizer(ShapeResultBloberizer& bloberizer,
+ float advance,
+ hb_direction_t direction,
+ const SimpleFontData* font_data,
+ const HarfBuzzRunGlyphData& glyph_data,
+ const TextRun& run,
+ unsigned character_index) {
+ FloatPoint start_offset = HB_DIRECTION_IS_HORIZONTAL(direction)
+ ? FloatPoint(advance, 0)
+ : FloatPoint(0, advance);
+ if (!IsSkipInkException(bloberizer, run, character_index)) {
+ bloberizer.Add(glyph_data.glyph, font_data,
+ start_offset + glyph_data.offset);
+ }
+}
+
+inline void AddEmphasisMark(ShapeResultBloberizer& bloberizer,
+ const GlyphData& emphasis_data,
+ FloatPoint glyph_center,
+ float mid_glyph_offset) {
+ const SimpleFontData* emphasis_font_data = emphasis_data.font_data;
+ DCHECK(emphasis_font_data);
+
+ bool is_vertical =
+ emphasis_font_data->PlatformData().IsVerticalAnyUpright() &&
+ emphasis_font_data->VerticalData();
+
+ if (!is_vertical) {
+ bloberizer.Add(emphasis_data.glyph, emphasis_font_data,
+ mid_glyph_offset - glyph_center.X());
+ } else {
+ bloberizer.Add(
+ emphasis_data.glyph, emphasis_font_data,
+ FloatPoint(-glyph_center.X(), mid_glyph_offset - glyph_center.Y()));
+ }
+}
+
+inline unsigned CountGraphemesInCluster(const UChar* str,
+ unsigned str_length,
+ uint16_t start_index,
+ uint16_t end_index) {
+ if (start_index > end_index) {
+ uint16_t temp_index = start_index;
+ start_index = end_index;
+ end_index = temp_index;
+ }
+ uint16_t length = end_index - start_index;
+ DCHECK_LE(static_cast<unsigned>(start_index + length), str_length);
+ TextBreakIterator* cursor_pos_iterator =
+ CursorMovementIterator(&str[start_index], length);
+
+ int cursor_pos = cursor_pos_iterator->current();
+ int num_graphemes = -1;
+ while (0 <= cursor_pos) {
+ cursor_pos = cursor_pos_iterator->next();
+ num_graphemes++;
+ }
+ return std::max(0, num_graphemes);
+}
+
+} // namespace
+
+float ShapeResultBloberizer::FillGlyphsForResult(
+ const ShapeResult& result,
+ const TextRunPaintInfo& run_info,
+ float initial_advance,
+ unsigned run_offset) {
+ auto total_advance = initial_advance;
+
+ for (const auto& run : result.runs_) {
+ total_advance = run->ForEachGlyphInRange(
+ total_advance, run_info.from, run_info.to, run_offset,
+ [&](const HarfBuzzRunGlyphData& glyph_data, float total_advance,
+ uint16_t character_index) -> bool {
+
+ AddGlyphToBloberizer(*this, total_advance, run->direction_,
+ run->font_data_.Get(), glyph_data, run_info.run,
+ character_index);
+ return true;
+ });
+ }
+
+ return total_advance;
+}
+
+float ShapeResultBloberizer::FillFastHorizontalGlyphs(
+ const ShapeResultBuffer& result_buffer,
+ const TextRun& text_run) {
+ DCHECK(!result_buffer.HasVerticalOffsets());
+ DCHECK_NE(GetType(), ShapeResultBloberizer::Type::kTextIntercepts);
+
+ float advance = 0;
+ auto results = result_buffer.results_;
+
+ for (unsigned i = 0; i < results.size(); ++i) {
+ const auto& word_result = IsLeftToRightDirection(text_run.Direction())
+ ? results[i]
+ : results[results.size() - 1 - i];
+ DCHECK(!word_result->HasVerticalOffsets());
+
+ for (const auto& run : word_result->runs_) {
+ DCHECK(run);
+ DCHECK(HB_DIRECTION_IS_HORIZONTAL(run->direction_));
+
+ advance =
+ run->ForEachGlyph(advance,
+ [&](const HarfBuzzRunGlyphData& glyph_data,
+ float total_advance) -> bool {
+ DCHECK(!glyph_data.offset.Height());
+ Add(glyph_data.glyph, run->font_data_.Get(),
+ total_advance + glyph_data.offset.Width());
+ return true;
+ });
+ }
+ }
+
+ return advance;
+}
+
+float ShapeResultBloberizer::FillTextEmphasisGlyphsForRun(
+ const ShapeResult::RunInfo* run,
+ const TextRunPaintInfo& run_info,
+ const GlyphData& emphasis_data,
+ float initial_advance,
+ unsigned run_offset) {
+ if (!run)
+ return 0;
+
+ unsigned graphemes_in_cluster = 1;
+ float cluster_advance = 0;
+
+ FloatPoint glyph_center =
+ emphasis_data.font_data->BoundsForGlyph(emphasis_data.glyph).Center();
+
+ const auto& text_run = run_info.run;
+ const auto from = run_info.from;
+ const auto to = run_info.to;
+
+ TextDirection direction = text_run.Direction();
+
+ // A "cluster" in this context means a cluster as it is used by HarfBuzz:
+ // The minimal group of characters and corresponding glyphs, that cannot be
+ // broken down further from a text shaping point of view. A cluster can
+ // contain multiple glyphs and grapheme clusters, with mutually overlapping
+ // boundaries. Below we count grapheme clusters per HarfBuzz clusters, then
+ // linearly split the sum of corresponding glyph advances by the number of
+ // grapheme clusters in order to find positions for emphasis mark drawing.
+ uint16_t cluster_start = static_cast<uint16_t>(
+ direction == TextDirection::kRtl
+ ? run->start_index_ + run->num_characters_ + run_offset
+ : run->GlyphToCharacterIndex(0) + run_offset);
+
+ float advance_so_far = initial_advance;
+ const unsigned num_glyphs = run->glyph_data_.size();
+ for (unsigned i = 0; i < num_glyphs; ++i) {
+ const HarfBuzzRunGlyphData& glyph_data = run->glyph_data_[i];
+ uint16_t current_character_index =
+ run->start_index_ + glyph_data.character_index + run_offset;
+ bool is_run_end = (i + 1 == num_glyphs);
+ bool is_cluster_end =
+ is_run_end || (run->GlyphToCharacterIndex(i + 1) + run_offset !=
+ current_character_index);
+
+ if ((direction == TextDirection::kRtl && current_character_index >= to) ||
+ (direction != TextDirection::kRtl && current_character_index < from)) {
+ advance_so_far += glyph_data.advance;
+ direction == TextDirection::kRtl ? --cluster_start : ++cluster_start;
+ continue;
+ }
+
+ cluster_advance += glyph_data.advance;
+
+ if (text_run.Is8Bit()) {
+ float glyph_advance_x = glyph_data.advance;
+ if (Character::CanReceiveTextEmphasis(
+ text_run[current_character_index])) {
+ AddEmphasisMark(*this, emphasis_data, glyph_center,
+ advance_so_far + glyph_advance_x / 2);
+ }
+ advance_so_far += glyph_advance_x;
+ } else if (is_cluster_end) {
+ uint16_t cluster_end;
+ if (direction == TextDirection::kRtl) {
+ cluster_end = current_character_index;
+ } else {
+ cluster_end = static_cast<uint16_t>(
+ is_run_end ? run->start_index_ + run->num_characters_ + run_offset
+ : run->GlyphToCharacterIndex(i + 1) + run_offset);
+ }
+ graphemes_in_cluster = CountGraphemesInCluster(
+ text_run.Characters16(), text_run.CharactersLength(), cluster_start,
+ cluster_end);
+ if (!graphemes_in_cluster || !cluster_advance)
+ continue;
+
+ float glyph_advance_x = cluster_advance / graphemes_in_cluster;
+ for (unsigned j = 0; j < graphemes_in_cluster; ++j) {
+ // Do not put emphasis marks on space, separator, and control
+ // characters.
+ if (Character::CanReceiveTextEmphasis(
+ text_run[current_character_index])) {
+ AddEmphasisMark(*this, emphasis_data, glyph_center,
+ advance_so_far + glyph_advance_x / 2);
+ }
+ advance_so_far += glyph_advance_x;
+ }
+ cluster_start = cluster_end;
+ cluster_advance = 0;
+ }
+ }
+ return advance_so_far - initial_advance;
+}
+
} // namespace blink

Powered by Google App Engine
This is Rietveld 408576698