| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/gfx/canvas_skia.h" | 5 #include "ui/gfx/canvas_skia.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include <cairo/cairo.h> | 9 #include <cairo/cairo.h> |
| 10 #include <pango/pango.h> | 10 #include <pango/pango.h> |
| 11 #include <pango/pangocairo.h> | 11 #include <pango/pangocairo.h> |
| 12 | 12 |
| 13 #include "base/i18n/rtl.h" | 13 #include "base/i18n/rtl.h" |
| 14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "ui/gfx/font.h" | 15 #include "ui/gfx/font.h" |
| 16 #include "ui/gfx/pango_util.h" | 16 #include "ui/gfx/pango_util.h" |
| 17 #include "ui/gfx/platform_font_pango.h" | 17 #include "ui/gfx/platform_font_pango.h" |
| 18 #include "ui/gfx/rect.h" | 18 #include "ui/gfx/rect.h" |
| 19 #include "ui/gfx/skia_util.h" | 19 #include "ui/gfx/skia_util.h" |
| 20 | 20 |
| 21 #if defined(TOOLKIT_USES_GTK) | 21 #if defined(TOOLKIT_USES_GTK) |
| 22 #include <gdk/gdk.h> | 22 #include <gdk/gdk.h> |
| 23 #endif | 23 #endif |
| 24 | 24 |
| 25 using std::max; | 25 using std::max; |
| 26 | 26 |
| 27 namespace { | 27 namespace { |
| 28 | 28 |
| 29 // Multiply by the text height to determine how much text should be faded | |
| 30 // when elliding. | |
| 31 const double kFadeWidthFactor = 1.5; | |
| 32 | |
| 33 // End state of the elliding fade. | |
| 34 const double kFadeFinalAlpha = 0.15; | |
| 35 | |
| 36 // Width of the border drawn around haloed text. | 29 // Width of the border drawn around haloed text. |
| 37 const double kTextHaloWidth = 1.0; | 30 const double kTextHaloWidth = 1.0; |
| 38 | 31 |
| 39 // A class to encapsulate string drawing params and operations. | 32 // A class to encapsulate string drawing params and operations. |
| 40 class DrawStringContext { | 33 class DrawStringContext : public gfx::PangoDrawString { |
| 41 public: | 34 public: |
| 42 DrawStringContext(gfx::CanvasSkia* canvas, | 35 DrawStringContext(gfx::CanvasSkia* canvas, |
| 43 const string16& text, | 36 const string16& text, |
| 44 const gfx::Font& font, | 37 const gfx::Font& font, |
| 45 const gfx::Rect& bounds, | 38 const gfx::Rect& bounds, |
| 46 const gfx::Rect& clip, | 39 const gfx::Rect& clip, |
| 47 int flags); | 40 int flags); |
| 48 ~DrawStringContext(); | 41 ~DrawStringContext(); |
| 49 | 42 |
| 50 void Draw(const SkColor& text_color); | |
| 51 void DrawWithHalo(const SkColor& text_color, const SkColor& halo_color); | 43 void DrawWithHalo(const SkColor& text_color, const SkColor& halo_color); |
| 52 | 44 |
| 53 private: | 45 private: |
| 54 // Draw an underline under the text using |cr|, which must already be | |
| 55 // initialized with the correct source. |extra_edge_width| is added to the | |
| 56 // outer edge of the line. Helper method for Draw() and DrawWithHalo(). | |
| 57 void DrawUnderline(cairo_t* cr, double extra_edge_width); | |
| 58 | |
| 59 const gfx::Rect& bounds_; | |
| 60 int flags_; | |
| 61 const gfx::Font& font_; | |
| 62 | |
| 63 gfx::CanvasSkia* canvas_; | 46 gfx::CanvasSkia* canvas_; |
| 64 cairo_t* cr_; | |
| 65 PangoLayout* layout_; | |
| 66 | |
| 67 int text_x_; | |
| 68 int text_y_; | |
| 69 int text_width_; | |
| 70 int text_height_; | |
| 71 | |
| 72 base::i18n::TextDirection text_direction_; | |
| 73 | 47 |
| 74 DISALLOW_COPY_AND_ASSIGN(DrawStringContext); | 48 DISALLOW_COPY_AND_ASSIGN(DrawStringContext); |
| 75 }; | 49 }; |
| 76 | 50 |
| 77 DrawStringContext::DrawStringContext(gfx::CanvasSkia* canvas, | 51 DrawStringContext::DrawStringContext(gfx::CanvasSkia* canvas, |
| 78 const string16& text, | 52 const string16& text, |
| 79 const gfx::Font& font, | 53 const gfx::Font& font, |
| 80 const gfx::Rect& bounds, | 54 const gfx::Rect& bounds, |
| 81 const gfx::Rect& clip, | 55 const gfx::Rect& clip, |
| 82 int flags) | 56 int flags) |
| 83 : bounds_(bounds), | 57 : PangoDrawString(skia::BeginPlatformPaint(canvas->sk_canvas()), |
| 84 flags_(flags), | 58 text, |
| 85 font_(font), | 59 font, |
| 86 canvas_(canvas), | 60 bounds, |
| 87 cr_(NULL), | 61 clip, |
| 88 layout_(NULL), | 62 flags), |
| 89 text_x_(bounds.x()), | 63 canvas_(canvas) { |
| 90 text_y_(bounds.y()), | |
| 91 text_width_(0), | |
| 92 text_height_(0), | |
| 93 text_direction_(base::i18n::GetFirstStrongCharacterDirection(text)) { | |
| 94 DCHECK(!bounds_.IsEmpty()); | |
| 95 | |
| 96 cr_ = skia::BeginPlatformPaint(canvas_->sk_canvas()); | |
| 97 layout_ = pango_cairo_create_layout(cr_); | |
| 98 | |
| 99 gfx::SetupPangoLayout( | |
| 100 layout_, text, font, bounds_.width(), text_direction_, flags_); | |
| 101 | |
| 102 pango_layout_set_height(layout_, bounds_.height() * PANGO_SCALE); | |
| 103 | |
| 104 cairo_save(cr_); | |
| 105 | |
| 106 cairo_rectangle(cr_, clip.x(), clip.y(), clip.width(), clip.height()); | |
| 107 cairo_clip(cr_); | |
| 108 | |
| 109 pango_layout_get_pixel_size(layout_, &text_width_, &text_height_); | |
| 110 | |
| 111 if (flags_ & gfx::Canvas::TEXT_VALIGN_TOP) { | |
| 112 // Cairo should draw from the top left corner already. | |
| 113 } else if (flags_ & gfx::Canvas::TEXT_VALIGN_BOTTOM) { | |
| 114 text_y_ += (bounds.height() - text_height_); | |
| 115 } else { | |
| 116 // Vertically centered. | |
| 117 text_y_ += ((bounds.height() - text_height_) / 2); | |
| 118 } | |
| 119 } | 64 } |
| 120 | 65 |
| 121 DrawStringContext::~DrawStringContext() { | 66 DrawStringContext::~DrawStringContext() { |
| 122 cairo_restore(cr_); | |
| 123 skia::EndPlatformPaint(canvas_->sk_canvas()); | 67 skia::EndPlatformPaint(canvas_->sk_canvas()); |
| 124 g_object_unref(layout_); | |
| 125 // NOTE: BeginPlatformPaint returned its surface, we shouldn't destroy it. | |
| 126 } | |
| 127 | |
| 128 void DrawStringContext::Draw(const SkColor& text_color) { | |
| 129 double r = SkColorGetR(text_color) / 255.0, | |
| 130 g = SkColorGetG(text_color) / 255.0, | |
| 131 b = SkColorGetB(text_color) / 255.0, | |
| 132 a = SkColorGetA(text_color) / 255.0; | |
| 133 | |
| 134 cairo_pattern_t* pattern = NULL; | |
| 135 | |
| 136 cairo_save(cr_); | |
| 137 | |
| 138 // If we're not eliding, use a fixed color. | |
| 139 // Otherwise, create a gradient pattern to use as the source. | |
| 140 if (text_direction_ == base::i18n::RIGHT_TO_LEFT || | |
| 141 (flags_ & gfx::Canvas::NO_ELLIPSIS) || | |
| 142 text_width_ <= bounds_.width()) { | |
| 143 cairo_set_source_rgba(cr_, r, g, b, a); | |
| 144 } else { | |
| 145 // Fade to semi-transparent to elide. | |
| 146 int fade_width = static_cast<double>(text_height_) * kFadeWidthFactor; | |
| 147 if (fade_width > (bounds_.width() / 2)) { | |
| 148 // Don't fade more than half the text. | |
| 149 fade_width = bounds_.width() / 2; | |
| 150 } | |
| 151 int fade_x = bounds_.x() + bounds_.width() - fade_width; | |
| 152 | |
| 153 pattern = cairo_pattern_create_linear( | |
| 154 fade_x, bounds_.y(), bounds_.x() + bounds_.width(), bounds_.y()); | |
| 155 cairo_pattern_add_color_stop_rgba(pattern, 0, r, g, b, a); | |
| 156 cairo_pattern_add_color_stop_rgba(pattern, 1, r, g, b, kFadeFinalAlpha); | |
| 157 cairo_set_source(cr_, pattern); | |
| 158 } | |
| 159 | |
| 160 cairo_move_to(cr_, text_x_, text_y_); | |
| 161 pango_cairo_show_layout(cr_, layout_); | |
| 162 | |
| 163 if (font_.GetStyle() & gfx::Font::UNDERLINED) | |
| 164 DrawUnderline(cr_, 0.0); | |
| 165 | |
| 166 if (pattern) | |
| 167 cairo_pattern_destroy(pattern); | |
| 168 | |
| 169 cairo_restore(cr_); | |
| 170 } | 68 } |
| 171 | 69 |
| 172 void DrawStringContext::DrawWithHalo(const SkColor& text_color, | 70 void DrawStringContext::DrawWithHalo(const SkColor& text_color, |
| 173 const SkColor& halo_color) { | 71 const SkColor& halo_color) { |
| 174 gfx::CanvasSkia text_canvas(bounds_.width() + 2, bounds_.height() + 2, false); | 72 gfx::CanvasSkia text_canvas(bounds_.width() + 2, bounds_.height() + 2, false); |
| 175 text_canvas.FillRectInt(static_cast<SkColor>(0), | 73 text_canvas.FillRectInt(static_cast<SkColor>(0), |
| 176 0, 0, bounds_.width() + 2, bounds_.height() + 2); | 74 0, 0, bounds_.width() + 2, bounds_.height() + 2); |
| 177 | 75 |
| 178 { | 76 { |
| 179 skia::ScopedPlatformPaint scoped_platform_paint(text_canvas.sk_canvas()); | 77 skia::ScopedPlatformPaint scoped_platform_paint(text_canvas.sk_canvas()); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 213 | 111 |
| 214 if (font_.GetStyle() & gfx::Font::UNDERLINED) | 112 if (font_.GetStyle() & gfx::Font::UNDERLINED) |
| 215 DrawUnderline(text_cr, 0.0); | 113 DrawUnderline(text_cr, 0.0); |
| 216 } | 114 } |
| 217 | 115 |
| 218 const SkBitmap& text_bitmap = const_cast<SkBitmap&>( | 116 const SkBitmap& text_bitmap = const_cast<SkBitmap&>( |
| 219 skia::GetTopDevice(*text_canvas.sk_canvas())->accessBitmap(false)); | 117 skia::GetTopDevice(*text_canvas.sk_canvas())->accessBitmap(false)); |
| 220 canvas_->DrawBitmapInt(text_bitmap, text_x_ - 1, text_y_ - 1); | 118 canvas_->DrawBitmapInt(text_bitmap, text_x_ - 1, text_y_ - 1); |
| 221 } | 119 } |
| 222 | 120 |
| 223 void DrawStringContext::DrawUnderline(cairo_t* cr, double extra_edge_width) { | |
| 224 gfx::PlatformFontPango* platform_font = | |
| 225 static_cast<gfx::PlatformFontPango*>(font_.platform_font()); | |
| 226 const double underline_y = | |
| 227 static_cast<double>(text_y_) + text_height_ + | |
| 228 platform_font->underline_position(); | |
| 229 cairo_set_line_width( | |
| 230 cr, platform_font->underline_thickness() + 2 * extra_edge_width); | |
| 231 cairo_move_to(cr, text_x_ - extra_edge_width, underline_y); | |
| 232 cairo_line_to(cr, text_x_ + text_width_ + extra_edge_width, underline_y); | |
| 233 cairo_stroke(cr); | |
| 234 } | |
| 235 | |
| 236 } // namespace | 121 } // namespace |
| 237 | 122 |
| 238 namespace gfx { | 123 namespace gfx { |
| 239 | 124 |
| 240 // static | 125 // static |
| 241 void CanvasSkia::SizeStringInt(const string16& text, | 126 void CanvasSkia::SizeStringInt(const string16& text, |
| 242 const gfx::Font& font, | 127 const gfx::Font& font, |
| 243 int* width, int* height, | 128 int* width, int* height, |
| 244 int flags) { | 129 int flags) { |
| 245 int org_width = *width; | 130 int org_width = *width; |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 334 cairo_paint(cr); | 219 cairo_paint(cr); |
| 335 } | 220 } |
| 336 #endif // defined(TOOLKIT_USES_GTK) | 221 #endif // defined(TOOLKIT_USES_GTK) |
| 337 | 222 |
| 338 ui::TextureID CanvasSkia::GetTextureID() { | 223 ui::TextureID CanvasSkia::GetTextureID() { |
| 339 // TODO(wjmaclean) | 224 // TODO(wjmaclean) |
| 340 return 0; | 225 return 0; |
| 341 } | 226 } |
| 342 | 227 |
| 343 } // namespace gfx | 228 } // namespace gfx |
| OLD | NEW |