diff options
-rw-r--r-- | chrome/browser/chromeos/status/status_area_button.cc | 3 | ||||
-rw-r--r-- | gfx/canvas_skia.h | 12 | ||||
-rw-r--r-- | gfx/canvas_skia_linux.cc | 237 | ||||
-rw-r--r-- | views/controls/button/text_button.cc | 19 | ||||
-rw-r--r-- | views/controls/button/text_button.h | 5 |
5 files changed, 207 insertions, 69 deletions
diff --git a/chrome/browser/chromeos/status/status_area_button.cc b/chrome/browser/chromeos/status/status_area_button.cc index 2ddaa20..14d197d 100644 --- a/chrome/browser/chromeos/status/status_area_button.cc +++ b/chrome/browser/chromeos/status/status_area_button.cc @@ -22,6 +22,9 @@ StatusAreaButton::StatusAreaButton(views::ViewMenuDelegate* menu_delegate) // Use an offset that is top aligned with toolbar. set_menu_offset(0, 2); + + // Use a black halo for status text. + SetTextHaloColor(SK_ColorBLACK); } void StatusAreaButton::Paint(gfx::Canvas* canvas, bool for_drag) { diff --git a/gfx/canvas_skia.h b/gfx/canvas_skia.h index 27781ff..d309784 100644 --- a/gfx/canvas_skia.h +++ b/gfx/canvas_skia.h @@ -67,11 +67,13 @@ class CanvasSkia : public skia::PlatformCanvas, void DrawGdkPixbuf(GdkPixbuf* pixbuf, int x, int y); #endif -#ifdef OS_WIN // Only implemented on Windows for now. - // Draws text with a 1-pixel halo around it of the given color. It allows - // ClearType to be drawn to an otherwise transparenct bitmap for drag images. - // Drag images have only 1-bit of transparency, so we don't do any fancy - // blurring. +#if defined(OS_WIN) || (defined(OS_POSIX) && !defined(OS_MACOSX)) + // Draws text with a 1-pixel halo around it of the given color. + // On Windows, it allows ClearType to be drawn to an otherwise transparenct + // bitmap for drag images. Drag images have only 1-bit of transparency, so + // we don't do any fancy blurring. + // On Linux, text with halo is created by stroking it with 2px |halo_color| + // then filling it with |text_color|. void DrawStringWithHalo(const std::wstring& text, const gfx::Font& font, const SkColor& text_color, diff --git a/gfx/canvas_skia_linux.cc b/gfx/canvas_skia_linux.cc index 57705a6..02a2dfab 100644 --- a/gfx/canvas_skia_linux.cc +++ b/gfx/canvas_skia_linux.cc @@ -88,20 +88,6 @@ static void UpdateCairoFontOptions() { g_free(rgba_style); } -} // namespace - -namespace gfx { - -CanvasSkia::CanvasSkia(int width, int height, bool is_opaque) - : skia::PlatformCanvas(width, height, is_opaque) { -} - -CanvasSkia::CanvasSkia() : skia::PlatformCanvas() { -} - -CanvasSkia::~CanvasSkia() { -} - // Pass a width > 0 to force wrapping and elliding. static void SetupPangoLayout(PangoLayout* layout, const std::wstring& text, @@ -122,21 +108,21 @@ static void SetupPangoLayout(PangoLayout* layout, if (width > 0) pango_layout_set_width(layout, width * PANGO_SCALE); - if (flags & Canvas::NO_ELLIPSIS) { + if (flags & gfx::Canvas::NO_ELLIPSIS) { pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE); } else { pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END); } - if (flags & Canvas::TEXT_ALIGN_CENTER) { + if (flags & gfx::Canvas::TEXT_ALIGN_CENTER) { pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER); - } else if (flags & Canvas::TEXT_ALIGN_RIGHT) { + } else if (flags & gfx::Canvas::TEXT_ALIGN_RIGHT) { pango_layout_set_alignment(layout, PANGO_ALIGN_RIGHT); } - if (flags & Canvas::MULTI_LINE) { + if (flags & gfx::Canvas::MULTI_LINE) { pango_layout_set_wrap(layout, - (flags & Canvas::CHARACTER_BREAK) ? + (flags & gfx::Canvas::CHARACTER_BREAK) ? PANGO_WRAP_WORD_CHAR : PANGO_WRAP_WORD); } @@ -172,6 +158,156 @@ static void SetupPangoLayout(PangoLayout* layout, } } +// A class to encapsulate string drawing params and operations. +class DrawStringContext { + public: + DrawStringContext(gfx::CanvasSkia* canvas, + const std::wstring& text, + const gfx::Font& font, + const gfx::Rect& bounds, + const gfx::Rect& clip, + int flags); + ~DrawStringContext(); + + void Draw(const SkColor& text_color); + void DrawWithHalo(const SkColor& text_color, + const SkColor& halo_color); + + private: + const gfx::Rect& bounds_; + int flags_; + const gfx::Font& font_; + + gfx::CanvasSkia* canvas_; + cairo_t* cr_; + PangoLayout* layout_; + + int text_x_; + int text_y_; + int text_width_; + int text_height_; + + DISALLOW_COPY_AND_ASSIGN(DrawStringContext); +}; + +DrawStringContext::DrawStringContext(gfx::CanvasSkia* canvas, + const std::wstring& text, + const gfx::Font& font, + const gfx::Rect& bounds, + const gfx::Rect& clip, + int flags) + : bounds_(bounds), + flags_(flags), + font_(font), + canvas_(canvas), + cr_(NULL), + layout_(NULL), + text_x_(bounds.x()), + text_y_(bounds.y()), + text_width_(0), + text_height_(0) { + DCHECK(!bounds_.IsEmpty()); + + cr_ = canvas_->beginPlatformPaint(); + layout_ = pango_cairo_create_layout(cr_); + + SetupPangoLayout(layout_, text, font, bounds_.width(), flags_); + + pango_layout_set_height(layout_, bounds_.height() * PANGO_SCALE); + + cairo_save(cr_); + + cairo_rectangle(cr_, clip.x(), clip.y(), clip.width(), clip.height()); + cairo_clip(cr_); + + pango_layout_get_pixel_size(layout_, &text_width_, &text_height_); + + if (flags_ & gfx::Canvas::TEXT_VALIGN_TOP) { + // Cairo should draw from the top left corner already. + } else if (flags_ & gfx::Canvas::TEXT_VALIGN_BOTTOM) { + text_y_ += (bounds.height() - text_height_); + } else { + // Vertically centered. + text_y_ += ((bounds.height() - text_height_) / 2); + } +} + +DrawStringContext::~DrawStringContext() { + if (font_.GetStyle() & gfx::Font::UNDERLINED) { + gfx::PlatformFontGtk* platform_font = + static_cast<gfx::PlatformFontGtk*>(font_.platform_font()); + double underline_y = + static_cast<double>(text_y_) + text_height_ + + platform_font->underline_position(); + cairo_set_line_width(cr_, platform_font->underline_thickness()); + cairo_move_to(cr_, text_x_, underline_y); + cairo_line_to(cr_, text_x_ + text_width_, underline_y); + cairo_stroke(cr_); + } + cairo_restore(cr_); + + g_object_unref(layout_); + // NOTE: beginPlatformPaint returned its surface, we shouldn't destroy it. +} + +void DrawStringContext::Draw(const SkColor& text_color) { + cairo_set_source_rgba(cr_, + SkColorGetR(text_color) / 255.0, + SkColorGetG(text_color) / 255.0, + SkColorGetB(text_color) / 255.0, + SkColorGetA(text_color) / 255.0); + cairo_move_to(cr_, text_x_, text_y_); + pango_cairo_show_layout(cr_, layout_); +} + +void DrawStringContext::DrawWithHalo(const SkColor& text_color, + const SkColor& halo_color) { + gfx::CanvasSkia text_canvas(bounds_.width() + 2, bounds_.height() + 2, false); + text_canvas.FillRectInt(static_cast<SkColor>(0), + 0, 0, bounds_.width() + 2, bounds_.height() + 2); + + cairo_t* text_cr = text_canvas.beginPlatformPaint(); + + cairo_move_to(text_cr, 1, 1); + pango_cairo_layout_path(text_cr, layout_); + + cairo_set_source_rgba(text_cr, + SkColorGetR(halo_color) / 255.0, + SkColorGetG(halo_color) / 255.0, + SkColorGetB(halo_color) / 255.0, + SkColorGetA(halo_color) / 255.0); + cairo_set_line_width(text_cr, 2.0); + cairo_stroke_preserve(text_cr); + + cairo_set_operator(text_cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba(text_cr, + SkColorGetR(text_color) / 255.0, + SkColorGetG(text_color) / 255.0, + SkColorGetB(text_color) / 255.0, + SkColorGetA(text_color) / 255.0); + cairo_fill(text_cr); + + text_canvas.endPlatformPaint(); + + const SkBitmap& text_bitmap = const_cast<SkBitmap&>( + text_canvas.getTopPlatformDevice().accessBitmap(false)); + canvas_->DrawBitmapInt(text_bitmap, text_x_ - 1, text_y_ - 1); +} + +} // namespace + +namespace gfx { + +CanvasSkia::CanvasSkia(int width, int height, bool is_opaque) + : skia::PlatformCanvas(width, height, is_opaque) { +} + +CanvasSkia::CanvasSkia() : skia::PlatformCanvas() { +} + +CanvasSkia::~CanvasSkia() { +} + // static void CanvasSkia::SizeStringInt(const std::wstring& text, const gfx::Font& font, @@ -208,6 +344,21 @@ void CanvasSkia::SizeStringInt(const std::wstring& text, cairo_surface_destroy(surface); } +void CanvasSkia::DrawStringWithHalo(const std::wstring& text, + const gfx::Font& font, + const SkColor& text_color, + const SkColor& halo_color, + int x, int y, int w, int h, + int flags) { + if (w <= 0 || h <= 0) + return; + + gfx::Rect bounds(x, y, w, h); + gfx::Rect clip(x - 1, y - 1, w + 2, h + 2); // Bigger clip for halo + DrawStringContext context(this, text, font, bounds, clip,flags); + context.DrawWithHalo(text_color, halo_color); +} + void CanvasSkia::DrawStringInt(const std::wstring& text, const gfx::Font& font, const SkColor& color, @@ -216,51 +367,9 @@ void CanvasSkia::DrawStringInt(const std::wstring& text, if (w <= 0 || h <= 0) return; - cairo_t* cr = beginPlatformPaint(); - PangoLayout* layout = pango_cairo_create_layout(cr); - - SetupPangoLayout(layout, text, font, w, flags); - - pango_layout_set_height(layout, h * PANGO_SCALE); - - cairo_save(cr); - cairo_set_source_rgba(cr, - SkColorGetR(color) / 255.0, - SkColorGetG(color) / 255.0, - SkColorGetB(color) / 255.0, - SkColorGetA(color) / 255.0); - - int width, height; - pango_layout_get_pixel_size(layout, &width, &height); - - cairo_rectangle(cr, x, y, w, h); - cairo_clip(cr); - - if (flags & Canvas::TEXT_VALIGN_TOP) { - // Cairo should draw from the top left corner already. - } else if (flags & Canvas::TEXT_VALIGN_BOTTOM) { - y += (h - height); - } else { - // Vertically centered. - y += ((h - height) / 2); - } - - cairo_move_to(cr, x, y); - pango_cairo_show_layout(cr, layout); - if (font.GetStyle() & gfx::Font::UNDERLINED) { - gfx::PlatformFontGtk* platform_font = - static_cast<gfx::PlatformFontGtk*>(font.platform_font()); - double underline_y = - static_cast<double>(y) + height + platform_font->underline_position(); - cairo_set_line_width(cr, platform_font->underline_thickness()); - cairo_move_to(cr, x, underline_y); - cairo_line_to(cr, x + width, underline_y); - cairo_stroke(cr); - } - cairo_restore(cr); - - g_object_unref(layout); - // NOTE: beginPlatformPaint returned its surface, we shouldn't destroy it. + gfx::Rect bounds(x, y, w, h); + DrawStringContext context(this, text, font, bounds, bounds, flags); + context.Draw(color); } void CanvasSkia::DrawGdkPixbuf(GdkPixbuf* pixbuf, int x, int y) { diff --git a/views/controls/button/text_button.cc b/views/controls/button/text_button.cc index e64d3dc..f758910 100644 --- a/views/controls/button/text_button.cc +++ b/views/controls/button/text_button.cc @@ -190,6 +190,8 @@ TextButton::TextButton(ButtonListener* listener, const std::wstring& text) color_disabled_(kDisabledColor), color_highlight_(kHighlightColor), color_hover_(kHoverColor), + text_halo_color_(0), + has_text_halo_(false), has_hover_icon_(false), has_pushed_icon_(false), max_width_(0), @@ -248,6 +250,11 @@ void TextButton::SetHoverColor(SkColor color) { color_hover_ = color; } +void TextButton::SetTextHaloColor(SkColor color) { + text_halo_color_ = color; + has_text_halo_ = true; +} + void TextButton::ClearMaxTextSize() { max_text_size_ = text_size_; } @@ -360,6 +367,11 @@ void TextButton::Paint(gfx::Canvas* canvas, bool for_drag) { text_bounds.height(), draw_string_flags); #endif + } else if (has_text_halo_) { + canvas->AsCanvasSkia()->DrawStringWithHalo( + text_, font_, text_color, text_halo_color_, text_bounds.x(), + text_bounds.y(), text_bounds.width(), text_bounds.height(), + draw_string_flags); } else { canvas->DrawStringInt(text_, font_, @@ -391,6 +403,13 @@ void TextButton::UpdateTextSize() { gfx::CanvasSkia::SizeStringInt( text_, font_, &width, &height, gfx::Canvas::NO_ELLIPSIS | PrefixTypeToCanvasType(prefix_type_)); + + // Add 2 extra pixels to width and height when text halo is used. + if (has_text_halo_) { + width += 2; + height += 2; + } + text_size_.SetSize(width, font_.GetHeight()); max_text_size_.SetSize(std::max(max_text_size_.width(), text_size_.width()), std::max(max_text_size_.height(), diff --git a/views/controls/button/text_button.h b/views/controls/button/text_button.h index 7e204d4..fc821f4 100644 --- a/views/controls/button/text_button.h +++ b/views/controls/button/text_button.h @@ -142,6 +142,7 @@ class TextButton : public CustomButton { void SetDisabledColor(SkColor color); void SetHighlightColor(SkColor color); void SetHoverColor(SkColor color); + void SetTextHaloColor(SkColor color); void SetNormalHasBorder(bool normal_has_border); // Sets whether or not to show the hot and pushed states for the button icon // (if present) in addition to the normal state. Defaults to true. @@ -207,6 +208,10 @@ class TextButton : public CustomButton { SkColor color_highlight_; SkColor color_hover_; + // An optional halo around text. + SkColor text_halo_color_; + bool has_text_halo_; + // An icon displayed with the text. SkBitmap icon_; |