OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/views/controls/styled_label.h" | 5 #include "ui/views/controls/styled_label.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/strings/string_util.h" | 9 #include "base/strings/string_util.h" |
10 #include "ui/gfx/font_list.h" | 10 #include "ui/gfx/font_list.h" |
11 #include "ui/gfx/text_elider.h" | 11 #include "ui/gfx/text_elider.h" |
12 #include "ui/native_theme/native_theme.h" | 12 #include "ui/native_theme/native_theme.h" |
13 #include "ui/views/controls/label.h" | 13 #include "ui/views/controls/label.h" |
14 #include "ui/views/controls/link.h" | 14 #include "ui/views/controls/link.h" |
15 #include "ui/views/controls/styled_label_listener.h" | 15 #include "ui/views/controls/styled_label_listener.h" |
16 | 16 |
17 namespace views { | 17 namespace views { |
18 | 18 |
19 | 19 |
20 // Helpers -------------------------------------------------------------------- | 20 // Helpers -------------------------------------------------------------------- |
21 | 21 |
22 namespace { | 22 namespace { |
23 | 23 |
24 // Calculates the height of a line of text. Currently returns the height of | 24 // Calculates the height of a line of text. Currently returns the height of |
25 // a label. | 25 // a label. |
26 int CalculateLineHeight() { | 26 int CalculateLineHeight(const gfx::FontList& font_list) { |
27 Label label; | 27 Label label; |
| 28 label.SetFontList(font_list); |
28 return label.GetPreferredSize().height(); | 29 return label.GetPreferredSize().height(); |
29 } | 30 } |
30 | 31 |
31 scoped_ptr<Label> CreateLabelRange( | 32 scoped_ptr<Label> CreateLabelRange( |
32 const base::string16& text, | 33 const base::string16& text, |
| 34 const gfx::FontList& font_list, |
33 const StyledLabel::RangeStyleInfo& style_info, | 35 const StyledLabel::RangeStyleInfo& style_info, |
34 views::LinkListener* link_listener) { | 36 views::LinkListener* link_listener) { |
35 scoped_ptr<Label> result; | 37 scoped_ptr<Label> result; |
36 | 38 |
37 if (style_info.is_link) { | 39 if (style_info.is_link) { |
38 Link* link = new Link(text); | 40 Link* link = new Link(text); |
39 link->set_listener(link_listener); | 41 link->set_listener(link_listener); |
40 link->SetUnderline((style_info.font_style & gfx::Font::UNDERLINE) != 0); | 42 link->SetUnderline((style_info.font_style & gfx::Font::UNDERLINE) != 0); |
41 result.reset(link); | 43 result.reset(link); |
42 } else { | 44 } else { |
43 result.reset(new Label(text)); | 45 result.reset(new Label(text)); |
44 } | 46 } |
45 | 47 |
46 result->SetEnabledColor(style_info.color); | 48 result->SetEnabledColor(style_info.color); |
| 49 result->SetFontList(font_list); |
47 | 50 |
48 if (!style_info.tooltip.empty()) | 51 if (!style_info.tooltip.empty()) |
49 result->SetTooltipText(style_info.tooltip); | 52 result->SetTooltipText(style_info.tooltip); |
50 if (style_info.font_style != gfx::Font::NORMAL) { | 53 if (style_info.font_style != gfx::Font::NORMAL) { |
51 result->SetFontList( | 54 result->SetFontList( |
52 result->font_list().DeriveWithStyle(style_info.font_style)); | 55 result->font_list().DeriveWithStyle(style_info.font_style)); |
53 } | 56 } |
54 | 57 |
55 return result.Pass(); | 58 return result.Pass(); |
56 } | 59 } |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
99 | 102 |
100 StyledLabel::~StyledLabel() {} | 103 StyledLabel::~StyledLabel() {} |
101 | 104 |
102 void StyledLabel::SetText(const base::string16& text) { | 105 void StyledLabel::SetText(const base::string16& text) { |
103 text_ = text; | 106 text_ = text; |
104 style_ranges_.clear(); | 107 style_ranges_.clear(); |
105 RemoveAllChildViews(true); | 108 RemoveAllChildViews(true); |
106 PreferredSizeChanged(); | 109 PreferredSizeChanged(); |
107 } | 110 } |
108 | 111 |
| 112 void StyledLabel::SetBaseFontList(const gfx::FontList& font_list) { |
| 113 font_list_ = font_list; |
| 114 PreferredSizeChanged(); |
| 115 } |
| 116 |
109 void StyledLabel::AddStyleRange(const gfx::Range& range, | 117 void StyledLabel::AddStyleRange(const gfx::Range& range, |
110 const RangeStyleInfo& style_info) { | 118 const RangeStyleInfo& style_info) { |
111 DCHECK(!range.is_reversed()); | 119 DCHECK(!range.is_reversed()); |
112 DCHECK(!range.is_empty()); | 120 DCHECK(!range.is_empty()); |
113 DCHECK(gfx::Range(0, text_.size()).Contains(range)); | 121 DCHECK(gfx::Range(0, text_.size()).Contains(range)); |
114 | 122 |
115 // Insert the new range in sorted order. | 123 // Insert the new range in sorted order. |
116 StyleRanges new_range; | 124 StyleRanges new_range; |
117 new_range.push_front(StyleRange(range, style_info)); | 125 new_range.push_front(StyleRange(range, style_info)); |
118 style_ranges_.merge(new_range); | 126 style_ranges_.merge(new_range); |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
172 gfx::Size StyledLabel::CalculateAndDoLayout(int width, bool dry_run) { | 180 gfx::Size StyledLabel::CalculateAndDoLayout(int width, bool dry_run) { |
173 if (!dry_run) { | 181 if (!dry_run) { |
174 RemoveAllChildViews(true); | 182 RemoveAllChildViews(true); |
175 link_targets_.clear(); | 183 link_targets_.clear(); |
176 } | 184 } |
177 | 185 |
178 width -= GetInsets().width(); | 186 width -= GetInsets().width(); |
179 if (width <= 0 || text_.empty()) | 187 if (width <= 0 || text_.empty()) |
180 return gfx::Size(); | 188 return gfx::Size(); |
181 | 189 |
182 const int line_height = CalculateLineHeight(); | 190 const int line_height = CalculateLineHeight(font_list_); |
183 // The index of the line we're on. | 191 // The index of the line we're on. |
184 int line = 0; | 192 int line = 0; |
185 // The x position (in pixels) of the line we're on, relative to content | 193 // The x position (in pixels) of the line we're on, relative to content |
186 // bounds. | 194 // bounds. |
187 int x = 0; | 195 int x = 0; |
188 | 196 |
189 base::string16 remaining_string = text_; | 197 base::string16 remaining_string = text_; |
190 StyleRanges::const_iterator current_range = style_ranges_.begin(); | 198 StyleRanges::const_iterator current_range = style_ranges_.begin(); |
191 | 199 |
192 // Iterate over the text, creating a bunch of labels and links and laying them | 200 // Iterate over the text, creating a bunch of labels and links and laying them |
193 // out in the appropriate positions. | 201 // out in the appropriate positions. |
194 while (!remaining_string.empty()) { | 202 while (!remaining_string.empty()) { |
195 // Don't put whitespace at beginning of a line with an exception for the | 203 // Don't put whitespace at beginning of a line with an exception for the |
196 // first line (so the text's leading whitespace is respected). | 204 // first line (so the text's leading whitespace is respected). |
197 if (x == 0 && line > 0) | 205 if (x == 0 && line > 0) |
198 TrimWhitespace(remaining_string, TRIM_LEADING, &remaining_string); | 206 TrimWhitespace(remaining_string, TRIM_LEADING, &remaining_string); |
199 | 207 |
200 gfx::Range range(gfx::Range::InvalidRange()); | 208 gfx::Range range(gfx::Range::InvalidRange()); |
201 if (current_range != style_ranges_.end()) | 209 if (current_range != style_ranges_.end()) |
202 range = current_range->range; | 210 range = current_range->range; |
203 | 211 |
204 const size_t position = text_.size() - remaining_string.size(); | 212 const size_t position = text_.size() - remaining_string.size(); |
205 | 213 |
206 const gfx::Rect chunk_bounds(x, 0, width - x, 2 * line_height); | 214 const gfx::Rect chunk_bounds(x, 0, width - x, 2 * line_height); |
207 std::vector<base::string16> substrings; | 215 std::vector<base::string16> substrings; |
208 gfx::FontList text_font_list; | 216 gfx::FontList text_font_list = font_list_; |
209 // If the start of the remaining text is inside a styled range, the font | 217 // If the start of the remaining text is inside a styled range, the font |
210 // style may differ from the base font. The font specified by the range | 218 // style may differ from the base font. The font specified by the range |
211 // should be used when eliding text. | 219 // should be used when eliding text. |
212 if (position >= range.start()) { | 220 if (position >= range.start()) { |
213 text_font_list = text_font_list.DeriveWithStyle( | 221 text_font_list = text_font_list.DeriveWithStyle( |
214 current_range->style_info.font_style); | 222 current_range->style_info.font_style); |
215 } | 223 } |
216 gfx::ElideRectangleText(remaining_string, | 224 gfx::ElideRectangleText(remaining_string, |
217 text_font_list, | 225 text_font_list, |
218 chunk_bounds.width(), | 226 chunk_bounds.width(), |
(...skipping 29 matching lines...) Expand all Loading... |
248 position == range.start() && x != 0) { | 256 position == range.start() && x != 0) { |
249 // If the chunk should not be wrapped, try to fit it entirely on the | 257 // If the chunk should not be wrapped, try to fit it entirely on the |
250 // next line. | 258 // next line. |
251 x = 0; | 259 x = 0; |
252 line++; | 260 line++; |
253 continue; | 261 continue; |
254 } | 262 } |
255 | 263 |
256 chunk = chunk.substr(0, std::min(chunk.size(), range.end() - position)); | 264 chunk = chunk.substr(0, std::min(chunk.size(), range.end() - position)); |
257 | 265 |
258 label = CreateLabelRange(chunk, style_info, this); | 266 label = CreateLabelRange(chunk, font_list_, style_info, this); |
259 | 267 |
260 if (style_info.is_link && !dry_run) | 268 if (style_info.is_link && !dry_run) |
261 link_targets_[label.get()] = range; | 269 link_targets_[label.get()] = range; |
262 | 270 |
263 if (position + chunk.size() >= range.end()) | 271 if (position + chunk.size() >= range.end()) |
264 ++current_range; | 272 ++current_range; |
265 } else { | 273 } else { |
266 // This chunk is normal text. | 274 // This chunk is normal text. |
267 if (position + chunk.size() > range.start()) | 275 if (position + chunk.size() > range.start()) |
268 chunk = chunk.substr(0, range.start() - position); | 276 chunk = chunk.substr(0, range.start() - position); |
269 label = CreateLabelRange(chunk, default_style_info_, this); | 277 label = CreateLabelRange(chunk, font_list_, default_style_info_, this); |
270 } | 278 } |
271 | 279 |
272 if (displayed_on_background_color_set_) | 280 if (displayed_on_background_color_set_) |
273 label->SetBackgroundColor(displayed_on_background_color_); | 281 label->SetBackgroundColor(displayed_on_background_color_); |
274 label->SetAutoColorReadabilityEnabled(auto_color_readability_enabled_); | 282 label->SetAutoColorReadabilityEnabled(auto_color_readability_enabled_); |
275 | 283 |
276 // Calculate the size of the optional focus border, and overlap by that | 284 // Calculate the size of the optional focus border, and overlap by that |
277 // amount. Otherwise, "<a>link</a>," will render as "link ,". | 285 // amount. Otherwise, "<a>link</a>," will render as "link ,". |
278 gfx::Insets focus_border_insets(label->GetInsets()); | 286 gfx::Insets focus_border_insets(label->GetInsets()); |
279 focus_border_insets += -label->View::GetInsets(); | 287 focus_border_insets += -label->View::GetInsets(); |
280 const gfx::Size view_size = label->GetPreferredSize(); | 288 const gfx::Size view_size = label->GetPreferredSize(); |
281 DCHECK_EQ(line_height, view_size.height() - focus_border_insets.height()); | 289 DCHECK_EQ(line_height, view_size.height() - focus_border_insets.height()); |
282 if (!dry_run) { | 290 if (!dry_run) { |
283 label->SetBoundsRect(gfx::Rect( | 291 label->SetBoundsRect(gfx::Rect( |
284 gfx::Point(GetInsets().left() + x - focus_border_insets.left(), | 292 gfx::Point(GetInsets().left() + x - focus_border_insets.left(), |
285 GetInsets().top() + line * line_height - | 293 GetInsets().top() + line * line_height - |
286 focus_border_insets.top()), | 294 focus_border_insets.top()), |
287 view_size)); | 295 view_size)); |
288 AddChildView(label.release()); | 296 AddChildView(label.release()); |
289 } | 297 } |
290 x += view_size.width() - focus_border_insets.width(); | 298 x += view_size.width() - focus_border_insets.width(); |
291 | 299 |
292 remaining_string = remaining_string.substr(chunk.size()); | 300 remaining_string = remaining_string.substr(chunk.size()); |
293 } | 301 } |
294 | 302 |
295 return gfx::Size(width, (line + 1) * line_height + GetInsets().height()); | 303 return gfx::Size(width, (line + 1) * line_height + GetInsets().height()); |
296 } | 304 } |
297 | 305 |
298 } // namespace views | 306 } // namespace views |
OLD | NEW |