Commit 84ab4dfd authored by Etienne Bergeron's avatar Etienne Bergeron Committed by Commit Bot

Implement control characters substitution in RenderText

This CL is adding special handling for the the control codepoints
(block C0). Previously, only the control character \n was
replaced by its visual symbols. Other control characters
are not handled by ShapeRuns which is leading to expensive
fallback fonts calls. (see http://crbug.com/993100)

Control codes:
  https://en.wikipedia.org/wiki/C0_and_C1_control_codes

The symbols used to display these control characters:
  https://www.compart.com/en/unicode/block/U+2400

Bug: 1011818, 1014119
Change-Id: I924dcb13c9e0e11d321ef375cd4285432aaf6cab
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1863394
Commit-Queue: Etienne Bergeron <etienneb@chromium.org>
Reviewed-by: default avatarAlexei Svitkine <asvitkine@chromium.org>
Reviewed-by: default avatarRobert Liao <robliao@chromium.org>
Reviewed-by: default avatarMichael Wasserman <msw@chromium.org>
Cr-Commit-Position: refs/heads/master@{#707401}
parent 58ee77c4
...@@ -192,6 +192,29 @@ void RestoreBreakList(RenderText* render_text, BreakList<T>* break_list) { ...@@ -192,6 +192,29 @@ void RestoreBreakList(RenderText* render_text, BreakList<T>* break_list) {
} }
} }
// Replace the unicode control characters ISO 6429 (block C0) by their
// corresponsing visual symbols. Control chracters can't be displayed but
// their visual symbols can.
void ReplaceControlCharactersWithSymbols(bool multiline, base::string16* text) {
// Control Pictures block (see: https://unicode.org/charts/PDF/U2400.pdf).
constexpr base::char16 kSymbolsCodepoint = 0x2400;
for (size_t offset = 0; offset < text->size(); ++offset) {
base::char16 control_codepoint = (*text)[offset];
if (control_codepoint >= 0 && control_codepoint <= 0x1F) {
// The newline character should be kept as-is when rendertext is
// multiline.
if (control_codepoint == '\n' && multiline)
continue;
// Replace codepoints with their visual symbols, which are at the same
// offset from kSymbolsCodepoint.
(*text)[offset] = kSymbolsCodepoint + control_codepoint;
} else if (control_codepoint == 0x7F) {
// Replace the 'del' codepoint by its symbol (u2421).
(*text)[offset] = kSymbolsCodepoint + 0x21;
}
}
}
} // namespace } // namespace
namespace internal { namespace internal {
...@@ -507,14 +530,6 @@ void RenderText::SetWordWrapBehavior(WordWrapBehavior behavior) { ...@@ -507,14 +530,6 @@ void RenderText::SetWordWrapBehavior(WordWrapBehavior behavior) {
} }
} }
void RenderText::SetReplaceNewlineCharsWithSymbols(bool replace) {
if (replace_newline_chars_with_symbols_ == replace)
return;
replace_newline_chars_with_symbols_ = replace;
cached_bounds_and_offset_valid_ = false;
OnTextAttributeChanged();
}
void RenderText::SetMinLineHeight(int line_height) { void RenderText::SetMinLineHeight(int line_height) {
if (min_line_height_ == line_height) if (min_line_height_ == line_height)
return; return;
...@@ -1137,7 +1152,6 @@ RenderText::RenderText() ...@@ -1137,7 +1152,6 @@ RenderText::RenderText()
multiline_(false), multiline_(false),
max_lines_(0), max_lines_(0),
word_wrap_behavior_(IGNORE_LONG_WORDS), word_wrap_behavior_(IGNORE_LONG_WORDS),
replace_newline_chars_with_symbols_(true),
subpixel_rendering_suppressed_(false), subpixel_rendering_suppressed_(false),
clip_to_display_rect_(true), clip_to_display_rect_(true),
baseline_(kInvalidBaseline), baseline_(kInvalidBaseline),
...@@ -1661,10 +1675,10 @@ void RenderText::OnTextAttributeChanged() { ...@@ -1661,10 +1675,10 @@ void RenderText::OnTextAttributeChanged() {
layout_text_.assign(text.substr(0, iter.getIndex()) + kEllipsisUTF16); layout_text_.assign(text.substr(0, iter.getIndex()) + kEllipsisUTF16);
} }
} }
static const base::char16 kNewline[] = { '\n', 0 };
static const base::char16 kNewlineSymbol[] = { 0x2424, 0 }; // Handle unicode control characters ISO 6429 (block C0). Range from 0 to 0x1F
if (!multiline_ && replace_newline_chars_with_symbols_) // and 0x7F.
base::ReplaceChars(layout_text_, kNewline, kNewlineSymbol, &layout_text_); ReplaceControlCharactersWithSymbols(multiline_, &layout_text_);
OnLayoutTextAttributeChanged(true); OnLayoutTextAttributeChanged(true);
} }
......
...@@ -292,9 +292,6 @@ class GFX_EXPORT RenderText { ...@@ -292,9 +292,6 @@ class GFX_EXPORT RenderText {
WordWrapBehavior word_wrap_behavior() const { return word_wrap_behavior_; } WordWrapBehavior word_wrap_behavior() const { return word_wrap_behavior_; }
void SetWordWrapBehavior(WordWrapBehavior behavior); void SetWordWrapBehavior(WordWrapBehavior behavior);
// Set whether newline characters should be replaced with newline symbols.
void SetReplaceNewlineCharsWithSymbols(bool replace);
// Returns true if this instance supports multiline rendering. // Returns true if this instance supports multiline rendering.
virtual bool MultilineSupported() const = 0; virtual bool MultilineSupported() const = 0;
...@@ -931,9 +928,6 @@ class GFX_EXPORT RenderText { ...@@ -931,9 +928,6 @@ class GFX_EXPORT RenderText {
// |multiline_| is set. The default value is IGNORE_LONG_WORDS. // |multiline_| is set. The default value is IGNORE_LONG_WORDS.
WordWrapBehavior word_wrap_behavior_; WordWrapBehavior word_wrap_behavior_;
// Whether newline characters should be replaced with newline symbols.
bool replace_newline_chars_with_symbols_;
// Set to true to suppress subpixel rendering due to non-font reasons (eg. // Set to true to suppress subpixel rendering due to non-font reasons (eg.
// if the background is transparent). The default value is false. // if the background is transparent). The default value is false.
bool subpixel_rendering_suppressed_; bool subpixel_rendering_suppressed_;
......
...@@ -4290,6 +4290,20 @@ TEST_F(RenderTextTest, NewlineWithoutMultilineFlag) { ...@@ -4290,6 +4290,20 @@ TEST_F(RenderTextTest, NewlineWithoutMultilineFlag) {
} }
} }
TEST_F(RenderTextTest, ControlCharacterReplacement) {
static const char kTextWithControlCharacters[] = "\b\r\a\t\n\v\f";
RenderText* render_text = GetRenderText();
render_text->SetText(UTF8ToUTF16(kTextWithControlCharacters));
// The control characters should have been replaced by their symbols.
EXPECT_EQ(WideToUTF16(L"␈␍␇␉␊␋␌"), render_text->GetDisplayText());
// Setting multiline, the newline character will be back to the original text.
render_text->SetMultiline(true);
EXPECT_EQ(WideToUTF16(L"␈␍␇␉\n␋␌"), render_text->GetDisplayText());
}
// Make sure the horizontal positions of runs in a line (left-to-right for // Make sure the horizontal positions of runs in a line (left-to-right for
// LTR languages and right-to-left for RTL languages). // LTR languages and right-to-left for RTL languages).
TEST_F(RenderTextTest, HarfBuzz_HorizontalPositions) { TEST_F(RenderTextTest, HarfBuzz_HorizontalPositions) {
......
...@@ -239,7 +239,6 @@ void Label::SetMultiLine(bool multi_line) { ...@@ -239,7 +239,6 @@ void Label::SetMultiLine(bool multi_line) {
return; return;
multi_line_ = multi_line; multi_line_ = multi_line;
full_text_->SetMultiline(multi_line); full_text_->SetMultiline(multi_line);
full_text_->SetReplaceNewlineCharsWithSymbols(!multi_line);
OnPropertyChanged(&multi_line_, kPropertyEffectsLayout); OnPropertyChanged(&multi_line_, kPropertyEffectsLayout);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment