12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/controls/styled_label.h" 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <vector> 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 95e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h" 105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/gfx/font_list.h" 1158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "ui/gfx/text_elider.h" 127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "ui/native_theme/native_theme.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/controls/label.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/controls/link.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/controls/styled_label_listener.h" 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace views { 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Helpers -------------------------------------------------------------------- 215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace { 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Calculates the height of a line of text. Currently returns the height of 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// a label. 265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)int CalculateLineHeight(const gfx::FontList& font_list) { 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Label label; 285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) label.SetFontList(font_list); 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return label.GetPreferredSize().height(); 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochscoped_ptr<Label> CreateLabelRange( 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::string16& text, 345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const gfx::FontList& font_list, 357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch const StyledLabel::RangeStyleInfo& style_info, 367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch views::LinkListener* link_listener) { 37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) scoped_ptr<Label> result; 38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (style_info.is_link) { 40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) Link* link = new Link(text); 41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) link->set_listener(link_listener); 42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) link->SetUnderline((style_info.font_style & gfx::Font::UNDERLINE) != 0); 43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) result.reset(link); 44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else { 455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) result.reset(new Label(text)); 46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch result->SetEnabledColor(style_info.color); 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) result->SetFontList(font_list); 507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!style_info.tooltip.empty()) 52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) result->SetTooltipText(style_info.tooltip); 535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (style_info.font_style != gfx::Font::NORMAL) { 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) result->SetFontList( 555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) result->font_list().DeriveWithStyle(style_info.font_style)); 565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return result.Pass(); 59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// StyledLabel::RangeStyleInfo ------------------------------------------------ 655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)StyledLabel::RangeStyleInfo::RangeStyleInfo() 67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) : font_style(gfx::Font::NORMAL), 687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch color(ui::NativeTheme::instance()->GetSystemColor( 697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch ui::NativeTheme::kColorId_LabelEnabledColor)), 70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) disable_line_wrapping(false), 71ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch is_link(false) {} 72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)StyledLabel::RangeStyleInfo::~RangeStyleInfo() {} 74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// static 76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)StyledLabel::RangeStyleInfo StyledLabel::RangeStyleInfo::CreateForLink() { 77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) RangeStyleInfo result; 78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) result.disable_line_wrapping = true; 79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) result.is_link = true; 807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch result.color = Link::GetDefaultEnabledColor(); 81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return result; 82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// StyledLabel::StyleRange ---------------------------------------------------- 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool StyledLabel::StyleRange::operator<( 88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const StyledLabel::StyleRange& other) const { 895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return range.start() < other.range.start(); 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// StyledLabel ---------------------------------------------------------------- 945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)StyledLabel::StyledLabel(const base::string16& text, 965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) StyledLabelListener* listener) 97116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch : specified_line_height_(0), 98116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch listener_(listener), 9958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) displayed_on_background_color_set_(false), 10058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) auto_color_readability_enabled_(true) { 101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::TrimWhitespace(text, base::TRIM_TRAILING, &text_); 102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)StyledLabel::~StyledLabel() {} 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void StyledLabel::SetText(const base::string16& text) { 107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) text_ = text; 1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) style_ranges_.clear(); 109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) RemoveAllChildViews(true); 110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) PreferredSizeChanged(); 111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void StyledLabel::SetBaseFontList(const gfx::FontList& font_list) { 1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) font_list_ = font_list; 1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) PreferredSizeChanged(); 1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 11858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void StyledLabel::AddStyleRange(const gfx::Range& range, 119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const RangeStyleInfo& style_info) { 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(!range.is_reversed()); 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(!range.is_empty()); 12258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(gfx::Range(0, text_.size()).Contains(range)); 123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Insert the new range in sorted order. 1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) StyleRanges new_range; 1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) new_range.push_front(StyleRange(range, style_info)); 1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) style_ranges_.merge(new_range); 128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 129ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch PreferredSizeChanged(); 130ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch} 131ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 132ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid StyledLabel::SetDefaultStyle(const RangeStyleInfo& style_info) { 133ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch default_style_info_ = style_info; 134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) PreferredSizeChanged(); 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 137116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid StyledLabel::SetLineHeight(int line_height) { 138116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch specified_line_height_ = line_height; 139116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch PreferredSizeChanged(); 140116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 141116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 1427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid StyledLabel::SetDisplayedOnBackgroundColor(SkColor color) { 1437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch displayed_on_background_color_ = color; 1447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch displayed_on_background_color_set_ = true; 1457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch} 1467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gfx::Insets StyledLabel::GetInsets() const { 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Insets insets = View::GetInsets(); 1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // We need a focus border iff we contain a link that will have a focus border. 1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // That in turn will be true only if the link is non-empty. 1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (StyleRanges::const_iterator i(style_ranges_.begin()); 1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) i != style_ranges_.end(); ++i) { 1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (i->style_info.is_link && !i->range.is_empty()) { 1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const gfx::Insets focus_border_padding( 1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Label::kFocusBorderPadding, Label::kFocusBorderPadding, 1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Label::kFocusBorderPadding, Label::kFocusBorderPadding); 1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) insets += focus_border_padding; 1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return insets; 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)int StyledLabel::GetHeightForWidth(int w) const { 167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (w != calculated_size_.width()) { 168cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // TODO(erg): Munge the const-ness of the style label. CalculateAndDoLayout 169cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // doesn't actually make any changes to member variables when |dry_run| is 170cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // set to true. In general, the mutating and non-mutating parts shouldn't 171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // be in the same codepath. 172cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) calculated_size_ = 173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const_cast<StyledLabel*>(this)->CalculateAndDoLayout(w, true); 174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return calculated_size_.height(); 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StyledLabel::Layout() { 1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) calculated_size_ = CalculateAndDoLayout(GetLocalBounds().width(), false); 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 182ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid StyledLabel::PreferredSizeChanged() { 183ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch calculated_size_ = gfx::Size(); 184ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch View::PreferredSizeChanged(); 185ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch} 186ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StyledLabel::LinkClicked(Link* source, int event_flags) { 1887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (listener_) 1897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch listener_->StyledLabelLinkClicked(link_targets_[source], event_flags); 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)gfx::Size StyledLabel::CalculateAndDoLayout(int width, bool dry_run) { 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!dry_run) { 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RemoveAllChildViews(true); 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) link_targets_.clear(); 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) width -= GetInsets().width(); 199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (width <= 0 || text_.empty()) 2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return gfx::Size(); 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 202116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const int line_height = specified_line_height_ > 0 ? specified_line_height_ 203116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch : CalculateLineHeight(font_list_); 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The index of the line we're on. 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int line = 0; 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The x position (in pixels) of the line we're on, relative to content 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // bounds. 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int x = 0; 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16 remaining_string = text_; 2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) StyleRanges::const_iterator current_range = style_ranges_.begin(); 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Iterate over the text, creating a bunch of labels and links and laying them 2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // out in the appropriate positions. 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) while (!remaining_string.empty()) { 216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Don't put whitespace at beginning of a line with an exception for the 217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // first line (so the text's leading whitespace is respected). 218a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (x == 0 && line > 0) { 219a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::TrimWhitespace(remaining_string, base::TRIM_LEADING, 220a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) &remaining_string); 221a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 22358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) gfx::Range range(gfx::Range::InvalidRange()); 2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (current_range != style_ranges_.end()) 2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) range = current_range->range; 226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const size_t position = text_.size() - remaining_string.size(); 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const gfx::Rect chunk_bounds(x, 0, width - x, 2 * line_height); 2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::vector<base::string16> substrings; 2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) gfx::FontList text_font_list = font_list_; 232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // If the start of the remaining text is inside a styled range, the font 233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // style may differ from the base font. The font specified by the range 234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // should be used when eliding text. 235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (position >= range.start()) { 2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) text_font_list = text_font_list.DeriveWithStyle( 2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) current_range->style_info.font_style); 238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 23958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) gfx::ElideRectangleText(remaining_string, 240f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) text_font_list, 241f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) chunk_bounds.width(), 242f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) chunk_bounds.height(), 243f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) gfx::IGNORE_LONG_WORDS, 244f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) &substrings); 2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(!substrings.empty()); 2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16 chunk = substrings[0]; 2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (chunk.empty()) { 249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Nothing fits on this line. Start a new line. 250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // If x is 0, first line may have leading whitespace that doesn't fit in a 251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // single line, so try trimming those. Otherwise there is no room for 252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // anything; abort. 253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (x == 0) { 254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (line == 0) { 255a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::TrimWhitespace(remaining_string, base::TRIM_LEADING, 256a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) &remaining_string); 257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) continue; 258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) x = 0; 2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) line++; 2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch scoped_ptr<Label> label; 2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (position >= range.start()) { 2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const RangeStyleInfo& style_info = current_range->style_info; 270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (style_info.disable_line_wrapping && chunk.size() < range.length() && 272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) position == range.start() && x != 0) { 273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // If the chunk should not be wrapped, try to fit it entirely on the 274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // next line. 2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) x = 0; 2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) line++; 2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) chunk = chunk.substr(0, std::min(chunk.size(), range.end() - position)); 281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) label = CreateLabelRange(chunk, font_list_, style_info, this); 283c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 284c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (style_info.is_link && !dry_run) 2857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch link_targets_[label.get()] = range; 286c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 287c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (position + chunk.size() >= range.end()) 2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ++current_range; 2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // This chunk is normal text. 2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (position + chunk.size() > range.start()) 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) chunk = chunk.substr(0, range.start() - position); 2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) label = CreateLabelRange(chunk, font_list_, default_style_info_, this); 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (displayed_on_background_color_set_) 2977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch label->SetBackgroundColor(displayed_on_background_color_); 29858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) label->SetAutoColorReadabilityEnabled(auto_color_readability_enabled_); 2997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Calculate the size of the optional focus border, and overlap by that 3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // amount. Otherwise, "<a>link</a>," will render as "link ,". 3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) gfx::Insets focus_border_insets(label->GetInsets()); 3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) focus_border_insets += -label->View::GetInsets(); 3047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch const gfx::Size view_size = label->GetPreferredSize(); 3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!dry_run) { 3067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch label->SetBoundsRect(gfx::Rect( 3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) gfx::Point(GetInsets().left() + x - focus_border_insets.left(), 3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) GetInsets().top() + line * line_height - 3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) focus_border_insets.top()), 3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) view_size)); 3117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch AddChildView(label.release()); 3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) x += view_size.width() - focus_border_insets.width(); 3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) remaining_string = remaining_string.substr(chunk.size()); 3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 318116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // The user-specified line height only applies to interline spacing, so the 319116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // final line's height is unaffected. 320116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch int total_height = line * line_height + 321116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch CalculateLineHeight(font_list_) + GetInsets().height(); 322116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return gfx::Size(width, total_height); 3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace views 326