| Index: ui/views/controls/styled_label.cc
|
| diff --git a/ui/views/controls/styled_label.cc b/ui/views/controls/styled_label.cc
|
| index 9c8f720cee179ae03412fa863f526a9638f9f4d1..8bf6706b3238289c4ac0a7fe7212e8a7cdae6f06 100644
|
| --- a/ui/views/controls/styled_label.cc
|
| +++ b/ui/views/controls/styled_label.cc
|
| @@ -132,7 +132,26 @@ void StyledLabel::AddStyleRange(const gfx::Range& range,
|
|
|
| // Insert the new range in sorted order.
|
| StyleRanges new_range;
|
| - new_range.push_front(StyleRange(range, style_info));
|
| + new_range.push_front(StyleRange(range, style_info, nullptr));
|
| + style_ranges_.merge(new_range);
|
| +
|
| + PreferredSizeChanged();
|
| +}
|
| +
|
| +void StyledLabel::AddEmbeddedView(uint32_t position, scoped_ptr<View> view) {
|
| + DCHECK_LE(position, text_.size());
|
| + DCHECK(!view->parent());
|
| +
|
| + // Set the view as owned by the StyledLabel so the Views hierarchy doesn't
|
| + // clean it up.
|
| + view->set_owned_by_client();
|
| +
|
| + // Insert the new range in sorted order.
|
| + StyleRanges new_range;
|
| + embedded_views_.push_back(std::move(view));
|
| + new_range.push_front(StyleRange(gfx::Range(position, position),
|
| + RangeStyleInfo(),
|
| + embedded_views_.back().get()));
|
| style_ranges_.merge(new_range);
|
|
|
| PreferredSizeChanged();
|
| @@ -240,15 +259,19 @@ gfx::Size StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
|
| if (width <= 0 || text_.empty())
|
| return gfx::Size();
|
|
|
| - const int line_height = specified_line_height_ > 0 ? specified_line_height_
|
| - : CalculateLineHeight(font_list_);
|
| + const int usual_line_height = specified_line_height_ > 0
|
| + ? specified_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
|
| + // The x, y position (in pixels) of the line we're on, relative to content
|
| // bounds.
|
| - int x = 0;
|
| + int x = 0, y = 0;
|
| // The width that was actually used. Guaranteed to be no larger than |width|.
|
| int used_width = 0;
|
| + // The height of the actual current line. Guaranteed to be no smaller than
|
| + // |usual_line_height|.
|
| + int line_height = usual_line_height;
|
|
|
| base::string16 remaining_string = text_;
|
| StyleRanges::const_iterator current_range = style_ranges_.begin();
|
| @@ -269,7 +292,7 @@ gfx::Size StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
|
|
|
| const size_t position = text_.size() - remaining_string.size();
|
|
|
| - const gfx::Rect chunk_bounds(x, 0, width - x, 2 * line_height);
|
| + const gfx::Rect chunk_bounds(x, 0, width - x, 2 * usual_line_height);
|
| 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
|
| @@ -301,14 +324,20 @@ gfx::Size StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
|
| }
|
|
|
| x = 0;
|
| + y += line_height;
|
| + line_height = usual_line_height;
|
| line++;
|
| continue;
|
| }
|
|
|
| base::string16 chunk = substrings[0];
|
|
|
| + View* view = current_range->embedded_view;
|
| scoped_ptr<Label> label;
|
| if (position >= range.start()) {
|
| + if (view)
|
| + line_height = std::max(line_height, view->GetPreferredSize().height());
|
| +
|
| const RangeStyleInfo& style_info = current_range->style_info;
|
|
|
| if (style_info.disable_line_wrapping && chunk.size() < range.length() &&
|
| @@ -316,6 +345,8 @@ gfx::Size StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
|
| // If the chunk should not be wrapped, try to fit it entirely on the
|
| // next line.
|
| x = 0;
|
| + y += line_height;
|
| + line_height = usual_line_height;
|
| line++;
|
| continue;
|
| }
|
| @@ -323,10 +354,12 @@ gfx::Size StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
|
| if (chunk.size() > range.end() - position)
|
| chunk = chunk.substr(0, range.end() - position);
|
|
|
| - label = CreateLabelRange(chunk, font_list_, style_info, this);
|
| + if (!view) {
|
| + label = CreateLabelRange(chunk, font_list_, style_info, this);
|
|
|
| - if (style_info.is_link && !dry_run)
|
| - link_targets_[label.get()] = range;
|
| + if (style_info.is_link && !dry_run)
|
| + link_targets_[label.get()] = range;
|
| + }
|
|
|
| if (position + chunk.size() >= range.end())
|
| ++current_range;
|
| @@ -337,22 +370,32 @@ gfx::Size StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
|
| 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_);
|
| + if (label) {
|
| + if (displayed_on_background_color_set_)
|
| + label->SetBackgroundColor(displayed_on_background_color_);
|
| + label->SetAutoColorReadabilityEnabled(auto_color_readability_enabled_);
|
| +
|
| + // |view| temporarily owns the pointer to the Label. This will be owned by
|
| + // the views hierarchy.
|
| + view = label.release();
|
| + }
|
|
|
| // 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();
|
| + gfx::Insets focus_border_insets(view->GetInsets());
|
| + focus_border_insets += -view->View::GetInsets();
|
| + const gfx::Size view_size = view->GetPreferredSize();
|
| if (!dry_run) {
|
| - label->SetBoundsRect(gfx::Rect(
|
| + view->SetBoundsRect(gfx::Rect(
|
| gfx::Point(GetInsets().left() + x - focus_border_insets.left(),
|
| - GetInsets().top() + line * line_height -
|
| - focus_border_insets.top()),
|
| + GetInsets().top() + y - focus_border_insets.top()),
|
| view_size));
|
| - AddChildView(label.release());
|
| +
|
| + // Ownership: If |view| came from a Label created above, it will be owned
|
| + // by the views hierarchy from now on. If |view| came from an externally
|
| + // supplied embedded view, it will continue to be owned by the
|
| + // |embedded_views_| vector.
|
| + AddChildView(view);
|
| }
|
| x += view_size.width() - focus_border_insets.width();
|
| used_width = std::max(used_width, x);
|
| @@ -364,6 +407,8 @@ gfx::Size StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
|
| // substring has different style), proceed to the next line.
|
| if (substrings.size() > 1 && chunk.size() == substrings[0].size()) {
|
| x = 0;
|
| + y += line_height;
|
| + line_height = usual_line_height;
|
| ++line;
|
| }
|
|
|
| @@ -373,8 +418,8 @@ gfx::Size StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
|
| DCHECK_LE(used_width, width);
|
| // The user-specified line height only applies to interline spacing, so the
|
| // final line's height is unaffected.
|
| - int total_height = line * line_height +
|
| - CalculateLineHeight(font_list_) + GetInsets().height();
|
| + // TODO(mgiuca): I think this makes a bad assumption about the final line.
|
| + int total_height = y + CalculateLineHeight(font_list_) + GetInsets().height();
|
| calculated_size_ = gfx::Size(used_width + GetInsets().width(), total_height);
|
| return calculated_size_;
|
| }
|
|
|