OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |