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

Side by Side Diff: ui/gfx/render_text.cc

Issue 312233003: Add fade eliding for Views Labels; related cleanup. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Refine alignment check; minor additional cleanup. Created 6 years, 6 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 | Annotate | Revision Log
« no previous file with comments | « ui/gfx/render_text.h ('k') | ui/gfx/render_text_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "ui/gfx/render_text.h" 5 #include "ui/gfx/render_text.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <climits> 8 #include <climits>
9 9
10 #include "base/command_line.h" 10 #include "base/command_line.h"
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
71 // Some platforms don't support getting the cap height, and simply return 71 // Some platforms don't support getting the cap height, and simply return
72 // the entire font ascent from GetCapHeight(). Centering the ascent makes 72 // the entire font ascent from GetCapHeight(). Centering the ascent makes
73 // the font look too low, so if GetCapHeight() returns the ascent, center 73 // the font look too low, so if GetCapHeight() returns the ascent, center
74 // the entire font height instead. 74 // the entire font height instead.
75 const int space = 75 const int space =
76 display_height - ((internal_leading != 0) ? cap_height : font_height); 76 display_height - ((internal_leading != 0) ? cap_height : font_height);
77 const int baseline_shift = space / 2 - internal_leading; 77 const int baseline_shift = space / 2 - internal_leading;
78 return baseline + std::max(min_shift, std::min(max_shift, baseline_shift)); 78 return baseline + std::max(min_shift, std::min(max_shift, baseline_shift));
79 } 79 }
80 80
81 // Converts |gfx::Font::FontStyle| flags to |SkTypeface::Style| flags. 81 // Converts |Font::FontStyle| flags to |SkTypeface::Style| flags.
82 SkTypeface::Style ConvertFontStyleToSkiaTypefaceStyle(int font_style) { 82 SkTypeface::Style ConvertFontStyleToSkiaTypefaceStyle(int font_style) {
83 int skia_style = SkTypeface::kNormal; 83 int skia_style = SkTypeface::kNormal;
84 skia_style |= (font_style & gfx::Font::BOLD) ? SkTypeface::kBold : 0; 84 skia_style |= (font_style & Font::BOLD) ? SkTypeface::kBold : 0;
85 skia_style |= (font_style & gfx::Font::ITALIC) ? SkTypeface::kItalic : 0; 85 skia_style |= (font_style & Font::ITALIC) ? SkTypeface::kItalic : 0;
86 return static_cast<SkTypeface::Style>(skia_style); 86 return static_cast<SkTypeface::Style>(skia_style);
87 } 87 }
88 88
89 // Given |font| and |display_width|, returns the width of the fade gradient. 89 // Given |font| and |display_width|, returns the width of the fade gradient.
90 int CalculateFadeGradientWidth(const FontList& font_list, int display_width) { 90 int CalculateFadeGradientWidth(const FontList& font_list, int display_width) {
91 // Fade in/out about 2.5 characters of the beginning/end of the string. 91 // Fade in/out about 2.5 characters of the beginning/end of the string.
92 // The .5 here is helpful if one of the characters is a space. 92 // The .5 here is helpful if one of the characters is a space.
93 // Use a quarter of the display width if the display width is very short. 93 // Use a quarter of the display width if the display width is very short.
94 const int average_character_width = font_list.GetExpectedTextWidth(1); 94 const int average_character_width = font_list.GetExpectedTextWidth(1);
95 const double gradient_width = std::min(average_character_width * 2.5, 95 const double gradient_width = std::min(average_character_width * 2.5,
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
222 int style) { 222 int style) {
223 DCHECK(!family.empty()); 223 DCHECK(!family.empty());
224 224
225 skia::RefPtr<SkTypeface> typeface = CreateSkiaTypeface(family.c_str(), style); 225 skia::RefPtr<SkTypeface> typeface = CreateSkiaTypeface(family.c_str(), style);
226 if (typeface) { 226 if (typeface) {
227 // |paint_| adds its own ref. So don't |release()| it from the ref ptr here. 227 // |paint_| adds its own ref. So don't |release()| it from the ref ptr here.
228 SetTypeface(typeface.get()); 228 SetTypeface(typeface.get());
229 229
230 // Enable fake bold text if bold style is needed but new typeface does not 230 // Enable fake bold text if bold style is needed but new typeface does not
231 // have it. 231 // have it.
232 paint_.setFakeBoldText((style & gfx::Font::BOLD) && !typeface->isBold()); 232 paint_.setFakeBoldText((style & Font::BOLD) && !typeface->isBold());
233 } 233 }
234 } 234 }
235 235
236 void SkiaTextRenderer::SetForegroundColor(SkColor foreground) { 236 void SkiaTextRenderer::SetForegroundColor(SkColor foreground) {
237 paint_.setColor(foreground); 237 paint_.setColor(foreground);
238 } 238 }
239 239
240 void SkiaTextRenderer::SetShader(SkShader* shader, const Rect& bounds) { 240 void SkiaTextRenderer::SetShader(SkShader* shader, const Rect& bounds) {
241 bounds_ = RectToSkRect(bounds); 241 bounds_ = RectToSkRect(bounds);
242 paint_.setShader(shader); 242 paint_.setShader(shader);
(...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after
502 UpdateLayoutText(); 502 UpdateLayoutText();
503 } 503 }
504 } 504 }
505 505
506 void RenderText::SetDisplayRect(const Rect& r) { 506 void RenderText::SetDisplayRect(const Rect& r) {
507 if (r != display_rect_) { 507 if (r != display_rect_) {
508 display_rect_ = r; 508 display_rect_ = r;
509 baseline_ = kInvalidBaseline; 509 baseline_ = kInvalidBaseline;
510 cached_bounds_and_offset_valid_ = false; 510 cached_bounds_and_offset_valid_ = false;
511 lines_.clear(); 511 lines_.clear();
512 if (elide_behavior_ != gfx::NO_ELIDE) 512 if (elide_behavior_ != TRUNCATE)
513 UpdateLayoutText(); 513 UpdateLayoutText();
514 } 514 }
515 } 515 }
516 516
517 void RenderText::SetCursorPosition(size_t position) { 517 void RenderText::SetCursorPosition(size_t position) {
518 MoveCursorTo(position, false); 518 MoveCursorTo(position, false);
519 } 519 }
520 520
521 void RenderText::MoveCursor(BreakType break_type, 521 void RenderText::MoveCursor(BreakType break_type,
522 VisualCursorDirection direction, 522 VisualCursorDirection direction,
(...skipping 360 matching lines...) Expand 10 before | Expand all | Expand 10 after
883 selection_color_(kDefaultColor), 883 selection_color_(kDefaultColor),
884 selection_background_focused_color_(kDefaultSelectionBackgroundColor), 884 selection_background_focused_color_(kDefaultSelectionBackgroundColor),
885 focused_(false), 885 focused_(false),
886 composition_range_(Range::InvalidRange()), 886 composition_range_(Range::InvalidRange()),
887 colors_(kDefaultColor), 887 colors_(kDefaultColor),
888 styles_(NUM_TEXT_STYLES), 888 styles_(NUM_TEXT_STYLES),
889 composition_and_selection_styles_applied_(false), 889 composition_and_selection_styles_applied_(false),
890 obscured_(false), 890 obscured_(false),
891 obscured_reveal_index_(-1), 891 obscured_reveal_index_(-1),
892 truncate_length_(0), 892 truncate_length_(0),
893 elide_behavior_(NO_ELIDE), 893 elide_behavior_(TRUNCATE),
894 multiline_(false), 894 multiline_(false),
895 fade_head_(false),
896 fade_tail_(false),
897 background_is_transparent_(false), 895 background_is_transparent_(false),
898 clip_to_display_rect_(true), 896 clip_to_display_rect_(true),
899 baseline_(kInvalidBaseline), 897 baseline_(kInvalidBaseline),
900 cached_bounds_and_offset_valid_(false) { 898 cached_bounds_and_offset_valid_(false) {
901 } 899 }
902 900
903 const Vector2d& RenderText::GetUpdatedDisplayOffset() { 901 const Vector2d& RenderText::GetUpdatedDisplayOffset() {
904 UpdateCachedBoundsAndOffset(); 902 UpdateCachedBoundsAndOffset();
905 return display_offset_; 903 return display_offset_;
906 } 904 }
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
1067 lines_.back().size.height(); 1065 lines_.back().size.height();
1068 offset.set_y((display_rect_.height() - text_height) / 2); 1066 offset.set_y((display_rect_.height() - text_height) / 2);
1069 } else { 1067 } else {
1070 offset.set_y(GetBaseline() - GetLayoutTextBaseline()); 1068 offset.set_y(GetBaseline() - GetLayoutTextBaseline());
1071 } 1069 }
1072 1070
1073 return offset; 1071 return offset;
1074 } 1072 }
1075 1073
1076 void RenderText::ApplyFadeEffects(internal::SkiaTextRenderer* renderer) { 1074 void RenderText::ApplyFadeEffects(internal::SkiaTextRenderer* renderer) {
1077 if (multiline() || (!fade_head() && !fade_tail())) 1075 const int width = display_rect().width();
1076 if (multiline() || elide_behavior_ != FADE_TAIL || GetContentWidth() <= width)
1078 return; 1077 return;
1079 1078
1080 const int display_width = display_rect().width(); 1079 const int gradient_width = CalculateFadeGradientWidth(font_list(), width);
1081
1082 // If the text fits as-is, no need to fade.
1083 if (GetStringSize().width() <= display_width)
1084 return;
1085
1086 int gradient_width = CalculateFadeGradientWidth(font_list(), display_width);
1087 if (gradient_width == 0) 1080 if (gradient_width == 0)
1088 return; 1081 return;
1089 1082
1090 bool fade_left = fade_head();
1091 bool fade_right = fade_tail();
1092 // Under RTL, |fade_right| == |fade_head|.
1093 // TODO(asvitkine): This is currently not based on GetTextDirection() because
1094 // RenderTextWin does not return a direction that's based on
1095 // the text content.
1096 if (horizontal_alignment_ == ALIGN_RIGHT)
1097 std::swap(fade_left, fade_right);
1098
1099 Rect solid_part = display_rect(); 1083 Rect solid_part = display_rect();
1100 Rect left_part; 1084 Rect left_part;
1101 Rect right_part; 1085 Rect right_part;
1102 if (fade_left) { 1086 if (horizontal_alignment_ != ALIGN_LEFT) {
1103 left_part = solid_part; 1087 left_part = solid_part;
1104 left_part.Inset(0, 0, solid_part.width() - gradient_width, 0); 1088 left_part.Inset(0, 0, solid_part.width() - gradient_width, 0);
1105 solid_part.Inset(gradient_width, 0, 0, 0); 1089 solid_part.Inset(gradient_width, 0, 0, 0);
1106 } 1090 }
1107 if (fade_right) { 1091 if (horizontal_alignment_ != ALIGN_RIGHT) {
1108 right_part = solid_part; 1092 right_part = solid_part;
1109 right_part.Inset(solid_part.width() - gradient_width, 0, 0, 0); 1093 right_part.Inset(solid_part.width() - gradient_width, 0, 0, 0);
1110 solid_part.Inset(0, 0, gradient_width, 0); 1094 solid_part.Inset(0, 0, gradient_width, 0);
1111 } 1095 }
1112 1096
1113 Rect text_rect = display_rect(); 1097 Rect text_rect = display_rect();
1114 text_rect.Inset(GetAlignmentOffset(0).x(), 0, 0, 0); 1098 text_rect.Inset(GetAlignmentOffset(0).x(), 0, 0, 0);
1115 1099
1116 // TODO(msw): Use the actual text colors corresponding to each faded part. 1100 // TODO(msw): Use the actual text colors corresponding to each faded part.
1117 skia::RefPtr<SkShader> shader = CreateFadeShader( 1101 skia::RefPtr<SkShader> shader = CreateFadeShader(
(...skipping 24 matching lines...) Expand all
1142 Range(select ? selection().start() : cursor, cursor), 1126 Range(select ? selection().start() : cursor, cursor),
1143 (cursor == 0) ? CURSOR_FORWARD : CURSOR_BACKWARD)); 1127 (cursor == 0) ? CURSOR_FORWARD : CURSOR_BACKWARD));
1144 } 1128 }
1145 1129
1146 void RenderText::UpdateLayoutText() { 1130 void RenderText::UpdateLayoutText() {
1147 layout_text_.clear(); 1131 layout_text_.clear();
1148 line_breaks_.SetMax(0); 1132 line_breaks_.SetMax(0);
1149 1133
1150 if (obscured_) { 1134 if (obscured_) {
1151 size_t obscured_text_length = 1135 size_t obscured_text_length =
1152 static_cast<size_t>(gfx::UTF16IndexToOffset(text_, 0, text_.length())); 1136 static_cast<size_t>(UTF16IndexToOffset(text_, 0, text_.length()));
1153 layout_text_.assign(obscured_text_length, kPasswordReplacementChar); 1137 layout_text_.assign(obscured_text_length, kPasswordReplacementChar);
1154 1138
1155 if (obscured_reveal_index_ >= 0 && 1139 if (obscured_reveal_index_ >= 0 &&
1156 obscured_reveal_index_ < static_cast<int>(text_.length())) { 1140 obscured_reveal_index_ < static_cast<int>(text_.length())) {
1157 // Gets the index range in |text_| to be revealed. 1141 // Gets the index range in |text_| to be revealed.
1158 size_t start = obscured_reveal_index_; 1142 size_t start = obscured_reveal_index_;
1159 U16_SET_CP_START(text_.data(), 0, start); 1143 U16_SET_CP_START(text_.data(), 0, start);
1160 size_t end = start; 1144 size_t end = start;
1161 UChar32 unused_char; 1145 UChar32 unused_char;
1162 U16_NEXT(text_.data(), end, text_.length(), unused_char); 1146 U16_NEXT(text_.data(), end, text_.length(), unused_char);
1163 1147
1164 // Gets the index in |layout_text_| to be replaced. 1148 // Gets the index in |layout_text_| to be replaced.
1165 const size_t cp_start = 1149 const size_t cp_start =
1166 static_cast<size_t>(gfx::UTF16IndexToOffset(text_, 0, start)); 1150 static_cast<size_t>(UTF16IndexToOffset(text_, 0, start));
1167 if (layout_text_.length() > cp_start) 1151 if (layout_text_.length() > cp_start)
1168 layout_text_.replace(cp_start, 1, text_.substr(start, end - start)); 1152 layout_text_.replace(cp_start, 1, text_.substr(start, end - start));
1169 } 1153 }
1170 } else { 1154 } else {
1171 layout_text_ = text_; 1155 layout_text_ = text_;
1172 } 1156 }
1173 1157
1174 const base::string16& text = layout_text_; 1158 const base::string16& text = layout_text_;
1175 if (truncate_length_ > 0 && truncate_length_ < text.length()) { 1159 if (truncate_length_ > 0 && truncate_length_ < text.length()) {
1176 // Truncate the text at a valid character break and append an ellipsis. 1160 // Truncate the text at a valid character break and append an ellipsis.
1177 icu::StringCharacterIterator iter(text.c_str()); 1161 icu::StringCharacterIterator iter(text.c_str());
1178 iter.setIndex32(truncate_length_ - 1); 1162 iter.setIndex32(truncate_length_ - 1);
1179 layout_text_.assign(text.substr(0, iter.getIndex()) + gfx::kEllipsisUTF16); 1163 layout_text_.assign(text.substr(0, iter.getIndex()) + kEllipsisUTF16);
1180 } 1164 }
1181 1165
1182 if (elide_behavior_ != NO_ELIDE && display_rect_.width() > 0 && 1166 if (elide_behavior_ != TRUNCATE && elide_behavior_ != FADE_TAIL &&
1183 !layout_text_.empty() && GetContentWidth() > display_rect_.width()) { 1167 display_rect_.width() > 0 && !layout_text_.empty() &&
1168 GetContentWidth() > display_rect_.width()) {
1184 // This doesn't trim styles so ellipsis may get rendered as a different 1169 // This doesn't trim styles so ellipsis may get rendered as a different
1185 // style than the preceding text. See crbug.com/327850. 1170 // style than the preceding text. See crbug.com/327850.
1186 layout_text_.assign(ElideText(layout_text_)); 1171 layout_text_.assign(ElideText(layout_text_));
1187 } 1172 }
1188 1173
1189 ResetLayout(); 1174 ResetLayout();
1190 } 1175 }
1191 1176
1192 // TODO(skanuj): Fix code duplication with ElideText in ui/gfx/text_elider.cc 1177 // TODO(skanuj): Fix code duplication with ElideText in ui/gfx/text_elider.cc
1193 // See crbug.com/327846 1178 // See crbug.com/327846
1194 base::string16 RenderText::ElideText(const base::string16& text) { 1179 base::string16 RenderText::ElideText(const base::string16& text) {
1195 const bool insert_ellipsis = (elide_behavior_ != TRUNCATE_AT_END); 1180 const bool insert_ellipsis = (elide_behavior_ != TRUNCATE);
1196 // Create a RenderText copy with attributes that affect the rendering width. 1181 // Create a RenderText copy with attributes that affect the rendering width.
1197 scoped_ptr<RenderText> render_text(CreateInstance()); 1182 scoped_ptr<RenderText> render_text(CreateInstance());
1198 render_text->SetFontList(font_list_); 1183 render_text->SetFontList(font_list_);
1199 render_text->SetDirectionalityMode(directionality_mode_); 1184 render_text->SetDirectionalityMode(directionality_mode_);
1200 render_text->SetCursorEnabled(cursor_enabled_); 1185 render_text->SetCursorEnabled(cursor_enabled_);
1201 1186
1202 render_text->styles_ = styles_; 1187 render_text->styles_ = styles_;
1203 render_text->colors_ = colors_; 1188 render_text->colors_ = colors_;
1204 render_text->SetText(text); 1189 render_text->SetText(text);
1205 const int current_text_pixel_width = render_text->GetContentWidth(); 1190 const int current_text_pixel_width = render_text->GetContentWidth();
1206 1191
1207 const base::string16 ellipsis = base::string16(gfx::kEllipsisUTF16); 1192 const base::string16 ellipsis = base::string16(kEllipsisUTF16);
1208 const bool elide_in_middle = false; 1193 const bool elide_in_middle = false;
1209 const bool elide_at_beginning = false; 1194 const bool elide_at_beginning = false;
1210 StringSlicer slicer(text, ellipsis, elide_in_middle, elide_at_beginning); 1195 StringSlicer slicer(text, ellipsis, elide_in_middle, elide_at_beginning);
1211 1196
1212 // Pango will return 0 width for absurdly long strings. Cut the string in 1197 // Pango will return 0 width for absurdly long strings. Cut the string in
1213 // half and try again. 1198 // half and try again.
1214 // This is caused by an int overflow in Pango (specifically, in 1199 // This is caused by an int overflow in Pango (specifically, in
1215 // pango_glyph_string_extents_range). It's actually more subtle than just 1200 // pango_glyph_string_extents_range). It's actually more subtle than just
1216 // returning 0, since on super absurdly long strings, the int can wrap and 1201 // returning 0, since on super absurdly long strings, the int can wrap and
1217 // return positive numbers again. Detecting that is probably not worth it 1202 // return positive numbers again. Detecting that is probably not worth it
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
1330 cursor_bounds_ += delta_offset; 1315 cursor_bounds_ += delta_offset;
1331 } 1316 }
1332 1317
1333 void RenderText::DrawSelection(Canvas* canvas) { 1318 void RenderText::DrawSelection(Canvas* canvas) {
1334 const std::vector<Rect> sel = GetSubstringBounds(selection()); 1319 const std::vector<Rect> sel = GetSubstringBounds(selection());
1335 for (std::vector<Rect>::const_iterator i = sel.begin(); i < sel.end(); ++i) 1320 for (std::vector<Rect>::const_iterator i = sel.begin(); i < sel.end(); ++i)
1336 canvas->FillRect(*i, selection_background_focused_color_); 1321 canvas->FillRect(*i, selection_background_focused_color_);
1337 } 1322 }
1338 1323
1339 } // namespace gfx 1324 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/render_text.h ('k') | ui/gfx/render_text_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698