summaryrefslogtreecommitdiffstats
path: root/chromium/ui/views/controls/styled_label.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/ui/views/controls/styled_label.cc')
-rw-r--r--chromium/ui/views/controls/styled_label.cc147
1 files changed, 95 insertions, 52 deletions
diff --git a/chromium/ui/views/controls/styled_label.cc b/chromium/ui/views/controls/styled_label.cc
index 96cc275c2d1..e7ee56c0b44 100644
--- a/chromium/ui/views/controls/styled_label.cc
+++ b/chromium/ui/views/controls/styled_label.cc
@@ -7,6 +7,7 @@
#include <vector>
#include "base/strings/string_util.h"
+#include "ui/gfx/font_list.h"
#include "ui/gfx/text_elider.h"
#include "ui/native_theme/native_theme.h"
#include "ui/views/controls/label.h"
@@ -15,17 +16,22 @@
namespace views {
+
+// Helpers --------------------------------------------------------------------
+
namespace {
// Calculates the height of a line of text. Currently returns the height of
// a label.
-int CalculateLineHeight() {
+int CalculateLineHeight(const gfx::FontList& font_list) {
Label label;
+ label.SetFontList(font_list);
return label.GetPreferredSize().height();
}
scoped_ptr<Label> CreateLabelRange(
- const string16& text,
+ const base::string16& text,
+ const gfx::FontList& font_list,
const StyledLabel::RangeStyleInfo& style_info,
views::LinkListener* link_listener) {
scoped_ptr<Label> result;
@@ -36,26 +42,27 @@ scoped_ptr<Label> CreateLabelRange(
link->SetUnderline((style_info.font_style & gfx::Font::UNDERLINE) != 0);
result.reset(link);
} else {
- Label* label = new Label(text);
- // Give the label a focus border so that its preferred size matches
- // links' preferred sizes
- label->SetHasFocusBorder(true);
-
- result.reset(label);
+ result.reset(new Label(text));
}
result->SetEnabledColor(style_info.color);
+ result->SetFontList(font_list);
if (!style_info.tooltip.empty())
result->SetTooltipText(style_info.tooltip);
- if (style_info.font_style != gfx::Font::NORMAL)
- result->SetFont(result->font().DeriveFont(0, style_info.font_style));
+ if (style_info.font_style != gfx::Font::NORMAL) {
+ result->SetFontList(
+ result->font_list().DeriveWithStyle(style_info.font_style));
+ }
- return scoped_ptr<Label>(result.release());
+ return result.Pass();
}
} // namespace
+
+// StyledLabel::RangeStyleInfo ------------------------------------------------
+
StyledLabel::RangeStyleInfo::RangeStyleInfo()
: font_style(gfx::Font::NORMAL),
color(ui::NativeTheme::instance()->GetSystemColor(
@@ -74,35 +81,49 @@ StyledLabel::RangeStyleInfo StyledLabel::RangeStyleInfo::CreateForLink() {
return result;
}
+
+// StyledLabel::StyleRange ----------------------------------------------------
+
bool StyledLabel::StyleRange::operator<(
const StyledLabel::StyleRange& other) const {
- // Intentionally reversed so the priority queue is sorted by smallest first.
- return range.start() > other.range.start();
+ return range.start() < other.range.start();
}
-StyledLabel::StyledLabel(const string16& text, StyledLabelListener* listener)
+
+// StyledLabel ----------------------------------------------------------------
+
+StyledLabel::StyledLabel(const base::string16& text,
+ StyledLabelListener* listener)
: listener_(listener),
displayed_on_background_color_set_(false),
auto_color_readability_enabled_(true) {
- TrimWhitespace(text, TRIM_TRAILING, &text_);
+ base::TrimWhitespace(text, base::TRIM_TRAILING, &text_);
}
StyledLabel::~StyledLabel() {}
-void StyledLabel::SetText(const string16& text) {
+void StyledLabel::SetText(const base::string16& text) {
text_ = text;
- style_ranges_ = std::priority_queue<StyleRange>();
+ style_ranges_.clear();
RemoveAllChildViews(true);
PreferredSizeChanged();
}
+void StyledLabel::SetBaseFontList(const gfx::FontList& font_list) {
+ font_list_ = font_list;
+ PreferredSizeChanged();
+}
+
void StyledLabel::AddStyleRange(const gfx::Range& range,
const RangeStyleInfo& style_info) {
DCHECK(!range.is_reversed());
DCHECK(!range.is_empty());
DCHECK(gfx::Range(0, text_.size()).Contains(range));
- style_ranges_.push(StyleRange(range, style_info));
+ // Insert the new range in sorted order.
+ StyleRanges new_range;
+ new_range.push_front(StyleRange(range, style_info));
+ style_ranges_.merge(new_range);
PreferredSizeChanged();
}
@@ -119,20 +140,37 @@ void StyledLabel::SetDisplayedOnBackgroundColor(SkColor color) {
gfx::Insets StyledLabel::GetInsets() const {
gfx::Insets insets = View::GetInsets();
- const gfx::Insets focus_border_padding(1, 1, 1, 1);
- insets += focus_border_padding;
+
+ // We need a focus border iff we contain a link that will have a focus border.
+ // That in turn will be true only if the link is non-empty.
+ for (StyleRanges::const_iterator i(style_ranges_.begin());
+ i != style_ranges_.end(); ++i) {
+ if (i->style_info.is_link && !i->range.is_empty()) {
+ const gfx::Insets focus_border_padding(
+ Label::kFocusBorderPadding, Label::kFocusBorderPadding,
+ Label::kFocusBorderPadding, Label::kFocusBorderPadding);
+ insets += focus_border_padding;
+ break;
+ }
+ }
+
return insets;
}
-int StyledLabel::GetHeightForWidth(int w) {
- if (w != calculated_size_.width())
- calculated_size_ = gfx::Size(w, CalculateAndDoLayout(w, true));
-
+int StyledLabel::GetHeightForWidth(int w) const {
+ if (w != calculated_size_.width()) {
+ // TODO(erg): Munge the const-ness of the style label. CalculateAndDoLayout
+ // doesn't actually make any changes to member variables when |dry_run| is
+ // set to true. In general, the mutating and non-mutating parts shouldn't
+ // be in the same codepath.
+ calculated_size_ =
+ const_cast<StyledLabel*>(this)->CalculateAndDoLayout(w, true);
+ }
return calculated_size_.height();
}
void StyledLabel::Layout() {
- CalculateAndDoLayout(GetLocalBounds().width(), false);
+ calculated_size_ = CalculateAndDoLayout(GetLocalBounds().width(), false);
}
void StyledLabel::PreferredSizeChanged() {
@@ -145,7 +183,7 @@ void StyledLabel::LinkClicked(Link* source, int event_flags) {
listener_->StyledLabelLinkClicked(link_targets_[source], event_flags);
}
-int StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
+gfx::Size StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
if (!dry_run) {
RemoveAllChildViews(true);
link_targets_.clear();
@@ -153,41 +191,43 @@ int StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
width -= GetInsets().width();
if (width <= 0 || text_.empty())
- return 0;
+ return gfx::Size();
- const int line_height = CalculateLineHeight();
+ const int line_height = CalculateLineHeight(font_list_);
// The index of the line we're on.
int line = 0;
// The x position (in pixels) of the line we're on, relative to content
// bounds.
int x = 0;
- string16 remaining_string = text_;
- std::priority_queue<StyleRange> style_ranges = style_ranges_;
+ base::string16 remaining_string = text_;
+ StyleRanges::const_iterator current_range = style_ranges_.begin();
// Iterate over the text, creating a bunch of labels and links and laying them
// out in the appropriate positions.
while (!remaining_string.empty()) {
// Don't put whitespace at beginning of a line with an exception for the
// first line (so the text's leading whitespace is respected).
- if (x == 0 && line > 0)
- TrimWhitespace(remaining_string, TRIM_LEADING, &remaining_string);
+ if (x == 0 && line > 0) {
+ base::TrimWhitespace(remaining_string, base::TRIM_LEADING,
+ &remaining_string);
+ }
gfx::Range range(gfx::Range::InvalidRange());
- if (!style_ranges.empty())
- range = style_ranges.top().range;
+ if (current_range != style_ranges_.end())
+ range = current_range->range;
const size_t position = text_.size() - remaining_string.size();
const gfx::Rect chunk_bounds(x, 0, width - x, 2 * line_height);
- std::vector<string16> substrings;
- gfx::FontList text_font_list;
+ std::vector<base::string16> substrings;
+ gfx::FontList text_font_list = font_list_;
// If the start of the remaining text is inside a styled range, the font
// style may differ from the base font. The font specified by the range
// should be used when eliding text.
if (position >= range.start()) {
- text_font_list = text_font_list.DeriveFontListWithSizeDeltaAndStyle(
- 0, style_ranges.top().style_info.font_style);
+ text_font_list = text_font_list.DeriveWithStyle(
+ current_range->style_info.font_style);
}
gfx::ElideRectangleText(remaining_string,
text_font_list,
@@ -197,7 +237,7 @@ int StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
&substrings);
DCHECK(!substrings.empty());
- string16 chunk = substrings[0];
+ base::string16 chunk = substrings[0];
if (chunk.empty()) {
// Nothing fits on this line. Start a new line.
// If x is 0, first line may have leading whitespace that doesn't fit in a
@@ -205,7 +245,8 @@ int StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
// anything; abort.
if (x == 0) {
if (line == 0) {
- TrimWhitespace(remaining_string, TRIM_LEADING, &remaining_string);
+ base::TrimWhitespace(remaining_string, base::TRIM_LEADING,
+ &remaining_string);
continue;
}
break;
@@ -218,7 +259,7 @@ int StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
scoped_ptr<Label> label;
if (position >= range.start()) {
- const RangeStyleInfo& style_info = style_ranges.top().style_info;
+ const RangeStyleInfo& style_info = current_range->style_info;
if (style_info.disable_line_wrapping && chunk.size() < range.length() &&
position == range.start() && x != 0) {
@@ -231,42 +272,44 @@ int StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
chunk = chunk.substr(0, std::min(chunk.size(), range.end() - position));
- label = CreateLabelRange(chunk, style_info, this);
+ label = CreateLabelRange(chunk, font_list_, style_info, this);
if (style_info.is_link && !dry_run)
link_targets_[label.get()] = range;
if (position + chunk.size() >= range.end())
- style_ranges.pop();
+ ++current_range;
} else {
// This chunk is normal text.
if (position + chunk.size() > range.start())
chunk = chunk.substr(0, range.start() - position);
- label = CreateLabelRange(chunk, default_style_info_, this);
+ label = CreateLabelRange(chunk, font_list_, default_style_info_, this);
}
if (displayed_on_background_color_set_)
label->SetBackgroundColor(displayed_on_background_color_);
label->SetAutoColorReadabilityEnabled(auto_color_readability_enabled_);
- // Lay out the views to overlap by 1 pixel to compensate for their border
- // spacing. Otherwise, "<a>link</a>," will render as "link ,".
- const int overlap = 1;
+ // Calculate the size of the optional focus border, and overlap by that
+ // amount. Otherwise, "<a>link</a>," will render as "link ,".
+ gfx::Insets focus_border_insets(label->GetInsets());
+ focus_border_insets += -label->View::GetInsets();
const gfx::Size view_size = label->GetPreferredSize();
- DCHECK_EQ(line_height, view_size.height() - 2 * overlap);
+ DCHECK_EQ(line_height, view_size.height() - focus_border_insets.height());
if (!dry_run) {
label->SetBoundsRect(gfx::Rect(
- gfx::Point(GetInsets().left() + x - overlap,
- GetInsets().top() + line * line_height - overlap),
+ gfx::Point(GetInsets().left() + x - focus_border_insets.left(),
+ GetInsets().top() + line * line_height -
+ focus_border_insets.top()),
view_size));
AddChildView(label.release());
}
- x += view_size.width() - 2 * overlap;
+ x += view_size.width() - focus_border_insets.width();
remaining_string = remaining_string.substr(chunk.size());
}
- return (line + 1) * line_height + GetInsets().height();
+ return gfx::Size(width, (line + 1) * line_height + GetInsets().height());
}
} // namespace views