Add line height setting to views::Label & use it for notifications.

This fixes the line spacing of notification so it's 18px on all
platforms (instead of the previous 17px on Chrome OS and 15px on
Windows).

To do this, support for a line height property was added to the
BoundedLabel that NotificationView uses, to the Label that BoundedLabel
uses, and to the Canvas that Label uses.

BUG=225871
R=mukai@chromium.org,msw@chromium.org

Review URL: https://chromiumcodereview.appspot.com/14322007

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@195076 0039d316-1c4b-4281-b951-d872f2087c98
parent a1c0601d
......@@ -89,7 +89,7 @@ void Canvas::RecreateBackingCanvas(const gfx::Size& size,
// static
int Canvas::GetStringWidth(const string16& text, const gfx::Font& font) {
int width = 0, height = 0;
Canvas::SizeStringInt(text, font, &width, &height, NO_ELLIPSIS);
Canvas::SizeStringInt(text, font, &width, &height, 0, NO_ELLIPSIS);
return width;
}
......@@ -433,6 +433,7 @@ void Canvas::DrawStringInt(const string16& text,
font,
color,
gfx::Rect(x, y, w, h),
0,
flags,
ShadowValues());
}
......
......@@ -124,10 +124,12 @@ class UI_EXPORT Canvas {
// Compute the size required to draw some text with the provided font.
// Attempts to fit the text with the provided width and height. Increases
// height and then width as needed to make the text fit. This method
// supports multiple lines.
// supports multiple lines. On Skia only a line_height can be specified and
// specifying a 0 value for it will cause the default height to be used.
static void SizeStringInt(const string16& text,
const gfx::Font& font,
int* width, int* height,
int line_height,
int flags);
// Returns the number of horizontal pixels needed to display the specified
......@@ -322,11 +324,13 @@ class UI_EXPORT Canvas {
int flags);
// Similar to above DrawStringInt method but with text shadows support.
// Currently it's only implemented for canvas skia.
// Currently it's only implemented for canvas skia. Specifying a 0 line_height
// will cause the default height to be used.
void DrawStringWithShadows(const string16& text,
const gfx::Font& font,
SkColor color,
const gfx::Rect& text_bounds,
int line_height,
int flags,
const ShadowValues& shadows);
......
......@@ -12,7 +12,10 @@ namespace gfx {
// static
void Canvas::SizeStringInt(const string16& text,
const gfx::Font& font,
int* width, int* height, int flags) {
int* width,
int* height,
int line_height,
int flags) {
NOTIMPLEMENTED();
}
......@@ -20,6 +23,7 @@ void Canvas::DrawStringWithShadows(const string16& text,
const gfx::Font& font,
SkColor color,
const gfx::Rect& text_bounds,
int line_height,
int flags,
const ShadowValues& shadows) {
NOTIMPLEMENTED();
......
......@@ -13,11 +13,10 @@
#include "ui/gfx/rect.h"
// Note: This is a temporary Skia-based implementation of the ui/gfx text
// rendering routines for views/aura. It replaces the stale Cocoa-based
// implementation. A future |canvas_skia.cc| implementation will supersede
// this and the other platform-specific implmenentations.
// Most drawing options, such as alignment and multi-line, are not implemented
// here.
// rendering routines for views/aura. It replaces the stale Cocoa-based
// implementation. A future |canvas_skia.cc| implementation will supersede
// this and the other platform-specific implmenentations. Most drawing options,
// such as alignment, multi-line, and line heights are not implemented here.
namespace {
......@@ -40,7 +39,11 @@ void Canvas::SizeStringInt(const string16& text,
const gfx::Font& font,
int* width,
int* height,
int line_height,
int flags) {
DLOG_IF(WARNING, line_height != 0) << "Line heights not implemented.";
DLOG_IF(WARNING, flags & Canvas::MULTI_LINE) << "Multi-line not implemented.";
NSFont* native_font = font.GetNativeFont();
NSString* ns_string = base::SysUTF16ToNSString(text);
NSDictionary* attributes =
......@@ -55,9 +58,12 @@ void Canvas::DrawStringWithShadows(const string16& text,
const gfx::Font& font,
SkColor color,
const gfx::Rect& text_bounds,
int line_height,
int flags,
const ShadowValues& shadows) {
DLOG_IF(WARNING, !shadows.empty()) << "Text shadow not implemented.";
DLOG_IF(WARNING, line_height != 0) << "Line heights not implemented.";
DLOG_IF(WARNING, flags & Canvas::MULTI_LINE) << "Multi-line not implemented.";
DLOG_IF(WARNING, !shadows.empty()) << "Text shadows not implemented.";
skia::RefPtr<SkTypeface> typeface = skia::AdoptRef(
SkTypeface::CreateFromName(
......
......@@ -169,6 +169,7 @@ int AdjustPlatformSpecificFlags(const string16& text, int flags) {
void Canvas::SizeStringInt(const string16& text,
const Font& font,
int* width, int* height,
int line_height,
int flags) {
DCHECK_GE(*width, 0);
DCHECK_GE(*height, 0);
......@@ -201,7 +202,7 @@ void Canvas::SizeStringInt(const string16& text,
render_text->SetText(strings[i]);
const Size string_size = render_text->GetStringSize();
w = std::max(w, string_size.width());
h += string_size.height();
h += (i > 0 && line_height > 0) ? line_height : string_size.height();
}
*width = w;
*height = h;
......@@ -228,6 +229,7 @@ void Canvas::DrawStringWithShadows(const string16& text,
const Font& font,
SkColor color,
const Rect& text_bounds,
int line_height,
int flags,
const ShadowValues& shadows) {
if (!IntersectsClipRect(text_bounds))
......@@ -268,18 +270,22 @@ void Canvas::DrawStringWithShadows(const string16& text,
for (size_t i = 0; i < strings.size(); i++) {
ui::Range range = StripAcceleratorChars(flags, &strings[i]);
UpdateRenderText(rect, strings[i], font, flags, color, render_text.get());
const int line_height = render_text->GetStringSize().height();
int line_padding = 0;
if (line_height > 0)
line_padding = line_height - render_text->GetStringSize().height();
else
line_height = render_text->GetStringSize().height();
// TODO(msw|asvitkine): Center Windows multi-line text: crbug.com/107357
#if !defined(OS_WIN)
if (i == 0) {
// TODO(msw|asvitkine): Support multi-line text with varied heights.
const int aggregate_height = strings.size() * line_height;
rect += Vector2d(0, (text_bounds.height() - aggregate_height) / 2);
const int text_height = strings.size() * line_height - line_padding;
rect += Vector2d(0, (text_bounds.height() - text_height) / 2);
}
#endif
rect.set_height(line_height);
rect.set_height(line_height - line_padding);
if (range.IsValid())
render_text->ApplyStyle(UNDERLINE, true, range);
......@@ -313,10 +319,10 @@ void Canvas::DrawStringWithShadows(const string16& text,
UpdateRenderText(rect, adjusted_text, font, flags, color,
render_text.get());
const int line_height = render_text->GetStringSize().height();
const int text_height = render_text->GetStringSize().height();
// Center the text vertically.
rect += Vector2d(0, (text_bounds.height() - line_height) / 2);
rect.set_height(line_height);
rect += Vector2d(0, (text_bounds.height() - text_height) / 2);
rect.set_height(text_height);
render_text->SetDisplayRect(rect);
if (range.IsValid())
render_text->ApplyStyle(UNDERLINE, true, range);
......
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <limits>
#include "base/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/canvas.h"
......@@ -9,29 +11,50 @@
namespace gfx {
TEST(CanvasTest, StringWidth) {
const string16 text = UTF8ToUTF16("Test");
const int width = Canvas::GetStringWidth(text, Font());
EXPECT_GT(width, 0);
class CanvasTest : public testing::Test {
protected:
int GetStringWidth(const char *text) {
return Canvas::GetStringWidth(UTF8ToUTF16(text), font_);
}
gfx::Size SizeStringInt(const char *text, int width, int line_height) {
string16 text16 = UTF8ToUTF16(text);
int height = 0;
int flags = (text16.find('\n') != string16::npos) ? Canvas::MULTI_LINE : 0;
Canvas::SizeStringInt(text16, font_, &width, &height, line_height, flags);
return gfx::Size(width, height);
}
private:
gfx::Font font_;
};
TEST_F(CanvasTest, StringWidth) {
EXPECT_GT(GetStringWidth("Test"), 0);
}
TEST(CanvasTest, StringWidthEmptyString) {
const string16 text = UTF8ToUTF16("");
const int width = Canvas::GetStringWidth(text, Font());
EXPECT_EQ(0, width);
TEST_F(CanvasTest, StringWidthEmptyString) {
EXPECT_EQ(0, GetStringWidth(""));
}
TEST(CanvasTest, StringSizeEmptyString) {
const Font font;
const string16 text = UTF8ToUTF16("");
int width = 0;
int height = 0;
Canvas::SizeStringInt(text, font, &width, &height, 0);
TEST_F(CanvasTest, StringSizeEmptyString) {
gfx::Size size = SizeStringInt("", 0, 0);
EXPECT_EQ(0, size.width());
EXPECT_GT(size.height(), 0);
}
EXPECT_EQ(0, width);
EXPECT_GT(height, 0);
// Line height is only supported on Skia.
#if defined(OS_MACOSX) || defined(OS_ANDROID)
#define MAYBE_StringSizeWithLineHeight DISABLED_StringSizeWithLineHeight
#else
#define MAYBE_StringSizeWithLineHeight StringSizeWithLineHeight
#endif
TEST_F(CanvasTest, MAYBE_StringSizeWithLineHeight) {
gfx::Size one_line_size = SizeStringInt("Q", 0, 0);
gfx::Size four_line_size = SizeStringInt("Q\nQ\nQ\nQ", 1000000, 1000);
EXPECT_EQ(one_line_size.width(), four_line_size.width());
EXPECT_EQ(3 * 1000 + one_line_size.height(), four_line_size.height());
}
} // namespace gfx
......@@ -25,6 +25,7 @@ const int kTextTopPadding = 12;
// Text sizes.
const int kTitleFontSize = 14;
const int kMessageFontSize = 12;
const int kMessageLineHeight = 18;
// Colors.
const SkColor kNotificationBackgroundColor = SkColorSetRGB(255, 255, 255);
......
......@@ -28,8 +28,9 @@ extern const int kIconToTextPadding; // H space between icon & title/message.
extern const int kTextTopPadding; // V space between text elements.
// Text sizes.
extern const int kTitleFontSize; // For title only.
extern const int kMessageFontSize; // For everything but title.
extern const int kTitleFontSize; // For title only.
extern const int kMessageFontSize; // For everything but title.
extern const int kMessageLineHeight; // In pixels.
// Colors.
extern const SkColor kNotificationBackgroundColor; // Background of the card.
......
......@@ -113,7 +113,9 @@ gfx::Size InnerBoundedLabel::GetSizeForWidthAndLines(int width, int lines) {
int text_height = std::numeric_limits<int>::max();
std::vector<string16> wrapped = GetWrappedText(text_width, lines);
gfx::Canvas::SizeStringInt(JoinString(wrapped, '\n'), font(),
&text_width, &text_height, GetTextFlags());
&text_width, &text_height,
owner_->GetLineHeight(),
GetTextFlags());
size.set_width(text_width + insets.width());
size.set_height(text_height + insets.height());
SetCachedSize(key, size);
......@@ -167,7 +169,7 @@ void InnerBoundedLabel::OnPaint(gfx::Canvas* canvas) {
views::Label::OnPaintBackground(canvas);
views::Label::OnPaintFocusBorder(canvas);
views::Label::OnPaintBorder(canvas);
int lines = owner_->line_limit();
int lines = owner_->GetLineLimit();
int height = GetSizeForWidthAndLines(width(), lines).height();
if (height > 0) {
gfx::Rect bounds(width(), height);
......@@ -275,10 +277,22 @@ void BoundedLabel::SetColors(SkColor textColor, SkColor backgroundColor) {
label_->SetBackgroundColor(backgroundColor);
}
void BoundedLabel::SetLineHeight(int height) {
label_->SetLineHeight(height);
}
void BoundedLabel::SetLineLimit(int lines) {
line_limit_ = std::max(lines, -1);
}
int BoundedLabel::GetLineHeight() const {
return label_->line_height();
}
int BoundedLabel::GetLineLimit() const {
return line_limit_;
}
int BoundedLabel::GetLinesForWidthAndLimit(int width, int limit) {
return visible() ? label_->GetLinesForWidthAndLimit(width, limit) : 0;
}
......
......@@ -38,9 +38,11 @@ class MESSAGE_CENTER_EXPORT BoundedLabel : public views::View {
virtual ~BoundedLabel();
void SetColors(SkColor textColor, SkColor backgroundColor);
void SetLineHeight(int height); // Pass in 0 for default height.
void SetLineLimit(int lines); // Pass in -1 for no limit.
int line_limit() const { return line_limit_; }
int GetLineHeight() const;
int GetLineLimit() const;
// Pass in a -1 width to use the preferred width, a -1 limit to skip limits.
int GetLinesForWidthAndLimit(int width, int limit);
......
......@@ -412,6 +412,7 @@ NotificationView::NotificationView(const Notification& notification,
if (!notification.message().empty()) {
message_view_ = new BoundedLabel(
ui::TruncateString(notification.message(), kMessageCharacterLimit));
message_view_->SetLineHeight(kMessageLineHeight);
message_view_->SetVisible(!is_expanded() || !notification.items().size());
message_view_->SetColors(kDimTextColor, kDimTextBackgroundColor);
message_view_->set_border(MakeTextBorder(4, 1));
......@@ -507,7 +508,7 @@ int NotificationView::GetHeightForWidth(int width) {
// line limit would be different for the specified width than it currently is.
// TODO(dharcourt): Avoid BoxLayout and directly compute the correct height.
if (message_view_ && title_view_) {
int used_limit = message_view_->line_limit();
int used_limit = message_view_->GetLineLimit();
int correct_limit = GetMessageLineLimit(width);
if (used_limit != correct_limit) {
total_height -= GetMessageHeight(content_width, used_limit);
......
......@@ -376,7 +376,7 @@ void TextButtonBase::CalculateTextSize(gfx::Size* text_size, int max_width) {
if (!multi_line_)
flags |= gfx::Canvas::NO_ELLIPSIS;
gfx::Canvas::SizeStringInt(text_, font_, &w, &h, flags);
gfx::Canvas::SizeStringInt(text_, font_, &w, &h, 0, flags);
text_size->SetSize(w, h);
}
......@@ -498,7 +498,7 @@ void TextButtonBase::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
shadows.push_back(gfx::ShadowValue(text_shadow_offset_, 0, color));
}
canvas->DrawStringWithShadows(text_, font_, text_color, text_bounds,
draw_string_flags, shadows);
0, draw_string_flags, shadows);
}
}
}
......
......@@ -121,6 +121,15 @@ void Label::SetHorizontalAlignment(gfx::HorizontalAlignment alignment) {
}
}
void Label::SetLineHeight(int height) {
if (height != line_height_) {
line_height_ = height;
ResetCachedSize();
PreferredSizeChanged();
SchedulePaint();
}
}
void Label::SetMultiLine(bool multi_line) {
DCHECK(!multi_line || elide_behavior_ != ELIDE_IN_MIDDLE);
if (multi_line != is_multi_line_) {
......@@ -226,7 +235,8 @@ int Label::GetHeightForWidth(int w) {
int cache_width = w;
int h = font_.GetHeight();
gfx::Canvas::SizeStringInt(text_, font_, &w, &h, ComputeDrawStringFlags());
const int flags = ComputeDrawStringFlags();
gfx::Canvas::SizeStringInt(text_, font_, &w, &h, line_height_, flags);
cached_heights_[cached_heights_cursor_] = gfx::Size(cache_width, h);
cached_heights_cursor_ = (cached_heights_cursor_ + 1) % kCachedSizeLimit;
return h + GetInsets().height();
......@@ -274,7 +284,7 @@ void Label::PaintText(gfx::Canvas* canvas,
enabled() ? enabled_shadow_color_ : disabled_shadow_color_));
canvas->DrawStringWithShadows(text, font_,
enabled() ? actual_enabled_color_ : actual_disabled_color_,
text_bounds, flags, shadows);
text_bounds, line_height_, flags, shadows);
if (HasFocus()) {
gfx::Rect focus_bounds = text_bounds;
......@@ -297,7 +307,7 @@ gfx::Size Label::GetTextSize() const {
int flags = ComputeDrawStringFlags();
if (!is_multi_line_)
flags |= gfx::Canvas::NO_ELLIPSIS;
gfx::Canvas::SizeStringInt(text_, font_, &w, &h, flags);
gfx::Canvas::SizeStringInt(text_, font_, &w, &h, line_height_, flags);
text_size_.SetSize(w, h);
text_size_valid_ = true;
}
......@@ -338,6 +348,7 @@ void Label::Init(const string16& text, const gfx::Font& font) {
auto_color_readability_ = true;
UpdateColorsFromTheme(ui::NativeTheme::instance());
horizontal_alignment_ = gfx::ALIGN_CENTER;
line_height_ = 0;
is_multi_line_ = false;
allow_character_break_ = false;
elide_behavior_ = NO_ELIDE;
......
......@@ -117,6 +117,12 @@ class VIEWS_EXPORT Label : public View {
return directionality_mode_;
}
// Get or set the distance in pixels between baselines of multi-line text.
// Default is 0, indicating the distance between lines should be the standard
// one for the label's text, font, and platform.
int line_height() const { return line_height_; }
void SetLineHeight(int height);
// Get or set if the label text can wrap on multiple lines; default is false.
bool is_multi_line() const { return is_multi_line_; }
void SetMultiLine(bool multi_line);
......@@ -242,6 +248,7 @@ class VIEWS_EXPORT Label : public View {
bool auto_color_readability_;
mutable gfx::Size text_size_;
mutable bool text_size_valid_;
int line_height_;
bool is_multi_line_;
bool allow_character_break_;
ElideBehavior elide_behavior_;
......
......@@ -659,8 +659,8 @@ void TreeView::ConfigureInternalNode(TreeModelNode* model_node,
void TreeView::UpdateNodeTextWidth(InternalNode* node) {
int width = 0, height = 0;
gfx::Canvas::SizeStringInt(node->model_node()->GetTitle(),
font_, &width, &height, gfx::Canvas::NO_ELLIPSIS);
gfx::Canvas::SizeStringInt(node->model_node()->GetTitle(), font_,
&width, &height, 0, gfx::Canvas::NO_ELLIPSIS);
node->set_text_width(width);
}
......
......@@ -111,7 +111,7 @@ void DrawTextStartingFrom(gfx::Canvas* canvas,
word = text; // Draw the whole text at once.
int w = 0, h = 0;
gfx::Canvas::SizeStringInt(word, font, &w, &h, flags);
gfx::Canvas::SizeStringInt(word, font, &w, &h, 0, flags);
// If we exceed the boundaries, we need to wrap.
WrapIfWordDoesntFit(w, font.GetHeight(), position, bounds);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment