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