diff options
-rw-r--r-- | ash/app_list/app_list_item_view.cc | 10 | ||||
-rw-r--r-- | ash/app_list/drop_shadow_label.cc | 107 | ||||
-rw-r--r-- | ash/app_list/drop_shadow_label.h | 28 | ||||
-rw-r--r-- | ui/gfx/canvas.cc | 19 | ||||
-rw-r--r-- | ui/gfx/canvas.h | 15 | ||||
-rw-r--r-- | ui/gfx/canvas_android.cc | 11 | ||||
-rw-r--r-- | ui/gfx/canvas_linux.cc | 18 | ||||
-rw-r--r-- | ui/gfx/canvas_mac.mm | 18 | ||||
-rw-r--r-- | ui/gfx/canvas_skia.cc | 45 | ||||
-rw-r--r-- | ui/gfx/canvas_win.cc | 23 | ||||
-rw-r--r-- | ui/gfx/render_text.cc | 58 | ||||
-rw-r--r-- | ui/gfx/render_text.h | 13 | ||||
-rw-r--r-- | ui/gfx/render_text_linux.cc | 1 | ||||
-rw-r--r-- | ui/gfx/render_text_win.cc | 1 | ||||
-rw-r--r-- | ui/gfx/shadow_value.cc | 61 | ||||
-rw-r--r-- | ui/gfx/shadow_value.h | 58 | ||||
-rw-r--r-- | ui/gfx/shadow_value_unittest.cc | 65 | ||||
-rw-r--r-- | ui/ui.gyp | 2 | ||||
-rw-r--r-- | ui/ui_unittests.gypi | 1 |
19 files changed, 408 insertions, 146 deletions
diff --git a/ash/app_list/app_list_item_view.cc b/ash/app_list/app_list_item_view.cc index 5addda1..c9e7492 100644 --- a/ash/app_list/app_list_item_view.cc +++ b/ash/app_list/app_list_item_view.cc @@ -17,6 +17,7 @@ #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/canvas.h" #include "ui/gfx/font.h" +#include "ui/gfx/shadow_value.h" #include "ui/gfx/skbitmap_operations.h" #include "ui/views/controls/image_view.h" #include "ui/views/controls/menu/menu_item_view.h" @@ -184,7 +185,14 @@ AppListItemView::AppListItemView(AppListModelView* list_model_view, ALLOW_THIS_IN_INITIALIZER_LIST(apply_shadow_factory_(this)) { title_->SetBackgroundColor(0); title_->SetEnabledColor(kTitleColor); - title_->SetDropShadowSize(3); + + const gfx::ShadowValue kTitleShadows[] = { + gfx::ShadowValue(gfx::Point(0, 0), 1, SkColorSetARGB(0x66, 0, 0, 0)), + gfx::ShadowValue(gfx::Point(0, 0), 10, SkColorSetARGB(0x66, 0, 0, 0)), + gfx::ShadowValue(gfx::Point(0, 2), 2, SkColorSetARGB(0x66, 0, 0, 0)), + gfx::ShadowValue(gfx::Point(0, 2), 4, SkColorSetARGB(0x66, 0, 0, 0)), + }; + title_->SetTextShadows(arraysize(kTitleShadows), kTitleShadows); AddChildView(icon_); AddChildView(title_); diff --git a/ash/app_list/drop_shadow_label.cc b/ash/app_list/drop_shadow_label.cc index de1c90f..c897e2a 100644 --- a/ash/app_list/drop_shadow_label.cc +++ b/ash/app_list/drop_shadow_label.cc @@ -8,97 +8,49 @@ #include "third_party/skia/include/effects/SkGradientShader.h" #include "ui/gfx/canvas.h" #include "ui/gfx/color_utils.h" +#include "ui/gfx/insets.h" #include "ui/gfx/skbitmap_operations.h" using views::Label; namespace ash { -static const int kDefaultDropShadowSize = 2; +DropShadowLabel::DropShadowLabel() { +} -DropShadowLabel::DropShadowLabel() : drop_shadow_size_(kDefaultDropShadowSize) { +DropShadowLabel::~DropShadowLabel() { } -void DropShadowLabel::SetDropShadowSize(int drop_shadow_size) { - if (drop_shadow_size != drop_shadow_size_) { - drop_shadow_size_ = drop_shadow_size; - invalidate_text_size(); - SchedulePaint(); +void DropShadowLabel::SetTextShadows(int shadow_count, + const gfx::ShadowValue* shadows) { + text_shadows_.clear(); + + if (shadow_count && shadows) { + for (int i = 0; i < shadow_count; ++i) + text_shadows_.push_back(shadows[i]); } } +gfx::Insets DropShadowLabel::GetInsets() const { + gfx::Insets insets = views::Label::GetInsets(); + gfx::Insets shadow_margin = gfx::ShadowValue::GetMargin(text_shadows_); + // Negate |shadow_margin| to convert it to a padding insets needed inside + // the bounds and combine with label's insets. + insets += -shadow_margin; + return insets; +} + void DropShadowLabel::PaintText(gfx::Canvas* canvas, const string16& text, const gfx::Rect& text_bounds, int flags) { SkColor text_color = enabled() ? enabled_color() : disabled_color(); - if (drop_shadow_size_ > 0) { - // To properly render shadow with elliding fade effect, text and shadow - // is rendered to this canvas first with elliding disable so that underlying - // code would not mix shadow color into text area because of elliding fade. - // When that is done and if we need elliding fade, an alpha mask is applied - // when transfering contents on this canvas to target canvas. - gfx::Size canvas_size(text_bounds.width() + drop_shadow_size_, - text_bounds.height() + drop_shadow_size_); - gfx::Canvas text_canvas(canvas_size, false); - - const double kShadowOpacity = 0.2; - const SkColor shadow_color = - SkColorSetA(SK_ColorBLACK, kShadowOpacity * SkColorGetA(text_color)); - gfx::Size text_size = GetTextSize(); - for (int i = 0; i < drop_shadow_size_; i++) { - text_canvas.DrawStringInt(text, font(), shadow_color, i, 0, - text_size.width(), text_size.height(), - flags | gfx::Canvas::NO_ELLIPSIS); - text_canvas.DrawStringInt(text, font(), shadow_color, i, i, - text_size.width(), text_size.height(), - flags | gfx::Canvas::NO_ELLIPSIS); - text_canvas.DrawStringInt(text, font(), shadow_color, 0, i, - text_size.width(), text_size.height(), - flags | gfx::Canvas::NO_ELLIPSIS); - } - text_canvas.DrawStringInt(text, font(), text_color, 0, 0, - text_size.width(), text_size.height(), - flags | gfx::Canvas::NO_ELLIPSIS); - - const SkBitmap& text_bitmap = const_cast<SkBitmap&>( - skia::GetTopDevice(*text_canvas.sk_canvas())->accessBitmap(false)); - - if (text_size.width() > text_bounds.width() && - !(flags & gfx::Canvas::NO_ELLIPSIS)) { - // Apply an gradient alpha mask for elliding fade effect. - const double kFadeWidthFactor = 1.5; - int fade_width = std::min(text_size.width() / 2, - static_cast<int>(text_size.height() * kFadeWidthFactor)); - - const SkColor kColors[] = { SK_ColorWHITE, 0 }; - const SkScalar kPoints[] = { SkIntToScalar(0), SkIntToScalar(1) }; - SkPoint p[2]; - p[0].set(SkIntToScalar(text_bounds.width() - fade_width), - SkIntToScalar(0)); - p[1].set(SkIntToScalar(text_bounds.width()), - SkIntToScalar(0)); - SkShader* s = SkGradientShader::CreateLinear( - p, kColors, kPoints, 2, SkShader::kClamp_TileMode, NULL); - - SkPaint paint; - paint.setShader(s)->unref(); - - gfx::Canvas alpha_canvas(canvas_size, false); - alpha_canvas.DrawRect(gfx::Rect(canvas_size), paint); - - const SkBitmap& alpha_bitmap = const_cast<SkBitmap&>( - skia::GetTopDevice(*alpha_canvas.sk_canvas())->accessBitmap(false)); - SkBitmap blended = SkBitmapOperations::CreateMaskedBitmap(text_bitmap, - alpha_bitmap); - canvas->DrawBitmapInt(blended, text_bounds.x(), text_bounds.y()); - } else { - canvas->DrawBitmapInt(text_bitmap, text_bounds.x(), text_bounds.y()); - } - } else { - canvas->DrawStringInt(text, font(), text_color, text_bounds.x(), - text_bounds.y(), text_bounds.width(), text_bounds.height(), flags); - } + canvas->DrawStringWithShadows(text, + font(), + text_color, + text_bounds, + flags, + text_shadows_); if (HasFocus() || paint_as_focused()) { gfx::Rect focus_bounds = text_bounds; @@ -108,11 +60,4 @@ void DropShadowLabel::PaintText(gfx::Canvas* canvas, } } -gfx::Size DropShadowLabel::GetTextSize() const { - gfx::Size text_size = Label::GetTextSize(); - text_size.SetSize(text_size.width() + drop_shadow_size_, - text_size.height() + drop_shadow_size_); - return text_size; -} - } // namespace ash diff --git a/ash/app_list/drop_shadow_label.h b/ash/app_list/drop_shadow_label.h index 2a7ce5d..25a24e1 100644 --- a/ash/app_list/drop_shadow_label.h +++ b/ash/app_list/drop_shadow_label.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #define ASH_APP_LIST_DROP_SHADOW_LABEL_H_ #pragma once -#include "ui/gfx/font.h" +#include <vector> + +#include "ui/gfx/shadow_value.h" #include "ui/views/controls/label.h" namespace ash { @@ -22,29 +24,19 @@ namespace ash { class DropShadowLabel : public views::Label { public: DropShadowLabel(); + virtual ~DropShadowLabel(); - // Sets the size of the drop shadow drawn under the text. - // Defaults to two. Note that this is a really simplistic drop - // shadow -- it gets more expensive to draw the larger it gets, - // since it simply draws more copies of the string. For instance, - // for a value of two, the string is draw seven times. In general, - // it is drawn three extra times for each increment of |size|. - void SetDropShadowSize(int size); - - // Return the size of the drop shadow in pixels. - int drop_shadow_size() const { return drop_shadow_size_; } + void SetTextShadows(int shadow_count, const gfx::ShadowValue* shadows); - // Overridden to paint the text differently from the base class. + private: + // Overridden from views::Label: + virtual gfx::Insets GetInsets() const OVERRIDE; virtual void PaintText(gfx::Canvas* canvas, const string16& text, const gfx::Rect& text_bounds, int flags) OVERRIDE; - protected: - virtual gfx::Size GetTextSize() const OVERRIDE; - - private: - int drop_shadow_size_; + std::vector<gfx::ShadowValue> text_shadows_; DISALLOW_COPY_AND_ASSIGN(DropShadowLabel); }; diff --git a/ui/gfx/canvas.cc b/ui/gfx/canvas.cc index ded3e2f7..883a7ce 100644 --- a/ui/gfx/canvas.cc +++ b/ui/gfx/canvas.cc @@ -13,6 +13,7 @@ #include "ui/gfx/canvas.h" #include "ui/gfx/font.h" #include "ui/gfx/rect.h" +#include "ui/gfx/shadow_value.h" #include "ui/gfx/skia_util.h" #include "ui/gfx/transform.h" @@ -340,6 +341,19 @@ void Canvas::DrawStringInt(const string16& text, display_rect.width(), display_rect.height()); } +void Canvas::DrawStringInt(const string16& text, + const gfx::Font& font, + SkColor color, + int x, int y, int w, int h, + int flags) { + DrawStringWithShadows(text, + font, + color, + gfx::Rect(x, y, w, h), + flags, + std::vector<ShadowValue>()); +} + void Canvas::TileImageInt(const SkBitmap& bitmap, int x, int y, int w, int h) { TileImageInt(bitmap, 0, 0, x, y, w, h); @@ -389,4 +403,9 @@ bool Canvas::IntersectsClipRectInt(int x, int y, int w, int h) { SkIntToScalar(y + h)); } +bool Canvas::IntersectsClipRect(const gfx::Rect& rect) { + return IntersectsClipRectInt(rect.x(), rect.y(), + rect.width(), rect.height()); +} + } // namespace gfx diff --git a/ui/gfx/canvas.h b/ui/gfx/canvas.h index 7bb83b7..dd2e764 100644 --- a/ui/gfx/canvas.h +++ b/ui/gfx/canvas.h @@ -6,6 +6,8 @@ #define UI_GFX_CANVAS_H_ #pragma once +#include <vector> + #include "base/basictypes.h" #include "base/memory/scoped_ptr.h" #include "base/string16.h" @@ -24,6 +26,7 @@ class Brush; class Rect; class Font; class Point; +class ShadowValue; class Size; // Canvas is a SkCanvas wrapper that provides a number of methods for @@ -291,6 +294,15 @@ class UI_EXPORT Canvas { int x, int y, int w, int h, int flags); + // Similar to above DrawStringInt method but with text shadows support. + // Currently it's only implemented for canvas skia. + void DrawStringWithShadows(const string16& text, + const gfx::Font& font, + SkColor color, + const gfx::Rect& text_bounds, + int flags, + const std::vector<ShadowValue>& shadows); + // Draws a dotted gray rectangle used for focus purposes. void DrawFocusRect(const gfx::Rect& rect); @@ -332,6 +344,7 @@ class UI_EXPORT Canvas { private: // Test whether the provided rectangle intersects the current clip rect. bool IntersectsClipRectInt(int x, int y, int w, int h); + bool IntersectsClipRect(const gfx::Rect& rect); #if defined(OS_WIN) // Draws text with the specified color, font and location. The text is @@ -340,7 +353,7 @@ class UI_EXPORT Canvas { void DrawStringInt(const string16& text, HFONT font, SkColor color, - int x, int y, int w, int h, + const gfx::Rect& text_bounds, int flags); #endif diff --git a/ui/gfx/canvas_android.cc b/ui/gfx/canvas_android.cc index 8d24d3a..3d8a823 100644 --- a/ui/gfx/canvas_android.cc +++ b/ui/gfx/canvas_android.cc @@ -16,11 +16,12 @@ void Canvas::SizeStringInt(const string16& text, NOTIMPLEMENTED(); } -void Canvas::DrawStringInt(const string16& text, - const gfx::Font& font, - SkColor color, - int x, int y, int w, int h, - int flags) { +void Canvas::DrawStringWithShadows(const string16& text, + const gfx::Font& font, + SkColor color, + const gfx::Rect& text_bounds, + int flags, + const std::vector<ShadowValue>& shadows) { NOTIMPLEMENTED(); } diff --git a/ui/gfx/canvas_linux.cc b/ui/gfx/canvas_linux.cc index a47cb51..18ce2a4 100644 --- a/ui/gfx/canvas_linux.cc +++ b/ui/gfx/canvas_linux.cc @@ -244,16 +244,18 @@ void Canvas::DrawStringWithHalo(const string16& text, context.DrawWithHalo(text_color, halo_color); } -void Canvas::DrawStringInt(const string16& text, - const gfx::Font& font, - SkColor color, - int x, int y, int w, int h, - int flags) { - if (!IntersectsClipRectInt(x, y, w, h)) +void Canvas::DrawStringWithShadows(const string16& text, + const gfx::Font& font, + SkColor color, + const gfx::Rect& text_bounds, + int flags, + const std::vector<ShadowValue>& shadows) { + DLOG_IF(WARNING, !shadows.empty()) << "Text shadow not implemented."; + + if (!IntersectsClipRect(text_bounds)) return; - gfx::Rect bounds(x, y, w, h); - DrawStringContext context(this, text, font, bounds, bounds, flags); + DrawStringContext context(this, text, font, text_bounds, text_bounds, flags); context.Draw(color); } diff --git a/ui/gfx/canvas_mac.mm b/ui/gfx/canvas_mac.mm index 76e61e2..23025e9 100644 --- a/ui/gfx/canvas_mac.mm +++ b/ui/gfx/canvas_mac.mm @@ -10,6 +10,7 @@ #include "base/sys_string_conversions.h" #include "third_party/skia/include/core/SkTypeface.h" #include "ui/gfx/font.h" +#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 @@ -50,11 +51,14 @@ void Canvas::SizeStringInt(const string16& text, *height = font.GetHeight(); } -void Canvas::DrawStringInt(const string16& text, - const gfx::Font& font, - SkColor color, - int x, int y, int w, int h, - int flags) { +void Canvas::DrawStringWithShadows(const string16& text, + const gfx::Font& font, + SkColor color, + const gfx::Rect& text_bounds, + int flags, + const std::vector<ShadowValue>& shadows) { + DLOG_IF(WARNING, !shadows.empty()) << "Text shadow not implemented."; + SkTypeface* typeface = SkTypeface::CreateFromName(font.GetFontName().c_str(), FontTypefaceStyle(font)); SkPaint paint; @@ -63,8 +67,8 @@ void Canvas::DrawStringInt(const string16& text, paint.setColor(color); canvas_->drawText(text.c_str(), text.size() * sizeof(string16::value_type), - x, - y + h, + text_bounds.x(), + text_bounds.bottom(), paint); } diff --git a/ui/gfx/canvas_skia.cc b/ui/gfx/canvas_skia.cc index b790076..cdd4ec5 100644 --- a/ui/gfx/canvas_skia.cc +++ b/ui/gfx/canvas_skia.cc @@ -11,8 +11,10 @@ #include "ui/base/text/text_elider.h" #include "ui/gfx/font.h" #include "ui/gfx/font_list.h" +#include "ui/gfx/insets.h" #include "ui/gfx/rect.h" #include "ui/gfx/render_text.h" +#include "ui/gfx/shadow_value.h" #include "ui/gfx/skia_util.h" namespace { @@ -218,12 +220,13 @@ void Canvas::SizeStringInt(const string16& text, } } -void Canvas::DrawStringInt(const string16& text, - const gfx::Font& font, - SkColor color, - int x, int y, int w, int h, - int flags) { - if (!IntersectsClipRectInt(x, y, w, h)) +void Canvas::DrawStringWithShadows(const string16& text, + const gfx::Font& font, + SkColor color, + const gfx::Rect& text_bounds, + int flags, + const std::vector<ShadowValue>& shadows) { + if (!IntersectsClipRect(text_bounds)) return; flags = AdjustPlatformSpecificFlags(text, flags); @@ -237,10 +240,13 @@ void Canvas::DrawStringInt(const string16& text, } #endif - gfx::Rect rect(x, y, w, h); + gfx::Rect clip_rect(text_bounds); + clip_rect.Inset(ShadowValue::GetMargin(shadows)); + canvas_->save(SkCanvas::kClip_SaveFlag); - ClipRect(rect); + ClipRect(clip_rect); + gfx::Rect rect(text_bounds); string16 adjusted_text = text; #if defined(OS_WIN) @@ -249,6 +255,7 @@ void Canvas::DrawStringInt(const string16& text, #endif scoped_ptr<RenderText> render_text(RenderText::CreateRenderText()); + render_text->SetTextShadows(shadows); if (flags & MULTI_LINE) { ui::WordWrapBehavior wrap_behavior = ui::IGNORE_LONG_WORDS; @@ -258,7 +265,10 @@ void Canvas::DrawStringInt(const string16& text, wrap_behavior = ui::ELIDE_LONG_WORDS; std::vector<string16> strings; - ui::ElideRectangleText(adjusted_text, font, w, h, wrap_behavior, + ui::ElideRectangleText(adjusted_text, + font, + text_bounds.width(), text_bounds.height(), + wrap_behavior, &strings); for (size_t i = 0; i < strings.size(); i++) { @@ -269,8 +279,11 @@ void Canvas::DrawStringInt(const string16& text, // first line. This may not be correct if different lines in the text have // different heights, but avoids needing to do two passes. const int line_height = render_text->GetStringSize().height(); - if (i == 0) - rect.Offset(0, VAlignText(strings.size() * line_height, flags, h)); + if (i == 0) { + rect.Offset(0, VAlignText(strings.size() * line_height, + flags, + text_bounds.height())); + } rect.set_height(line_height); ApplyUnderlineStyle(range, render_text.get()); @@ -293,14 +306,18 @@ void Canvas::DrawStringInt(const string16& text, } #endif - if (elide_text) - ElideTextAndAdjustRange(font, w, &adjusted_text, &range); + if (elide_text) { + ElideTextAndAdjustRange(font, + text_bounds.width(), + &adjusted_text, + &range); + } UpdateRenderText(rect, adjusted_text, font, flags, color, render_text.get()); const int line_height = render_text->GetStringSize().height(); - rect.Offset(0, VAlignText(line_height, flags, h)); + rect.Offset(0, VAlignText(line_height, flags, text_bounds.height())); rect.set_height(line_height); render_text->SetDisplayRect(rect); diff --git a/ui/gfx/canvas_win.cc b/ui/gfx/canvas_win.cc index 54ba117..0d3ca63 100644 --- a/ui/gfx/canvas_win.cc +++ b/ui/gfx/canvas_win.cc @@ -325,15 +325,15 @@ void Canvas::SizeStringInt(const string16& text, void Canvas::DrawStringInt(const string16& text, HFONT font, SkColor color, - int x, int y, int w, int h, + const gfx::Rect& text_bounds, int flags) { SkRect fclip; if (!canvas_->getClipBounds(&fclip)) return; - RECT text_bounds = { x, y, x + w, y + h }; + RECT text_rect = text_bounds.ToRECT(); SkIRect clip; fclip.round(&clip); - if (!clip.intersect(skia::RECTToSkIRect(text_bounds))) + if (!clip.intersect(skia::RECTToSkIRect(text_rect))) return; // Clamp the max amount of text we'll draw to 32K. There seem to be bugs in @@ -355,7 +355,7 @@ void Canvas::DrawStringInt(const string16& text, SetTextColor(dc, brush_color); int f = ComputeFormatFlags(flags, clamped_string); - DoDrawText(dc, clamped_string, &text_bounds, f); + DoDrawText(dc, clamped_string, &text_rect, f); } // Restore the old font. This way we don't have to worry if the caller @@ -369,12 +369,15 @@ void Canvas::DrawStringInt(const string16& text, clip.height()); } -void Canvas::DrawStringInt(const string16& text, - const gfx::Font& font, - SkColor color, - int x, int y, int w, int h, - int flags) { - DrawStringInt(text, font.GetNativeFont(), color, x, y, w, h, flags); +void Canvas::DrawStringWithShadows(const string16& text, + const gfx::Font& font, + SkColor color, + const gfx::Rect& text_bounds, + int flags, + const std::vector<ShadowValue>& shadows) { + DLOG_IF(WARNING, !shadows.empty()) << "Text shadow not implemented."; + + DrawStringInt(text, font.GetNativeFont(), color, text_bounds, flags); } // Checks each pixel immediately adjacent to the given pixel in the bitmap. If diff --git a/ui/gfx/render_text.cc b/ui/gfx/render_text.cc index d7fa03c..6fff6f7 100644 --- a/ui/gfx/render_text.cc +++ b/ui/gfx/render_text.cc @@ -10,11 +10,16 @@ #include "base/i18n/break_iterator.h" #include "base/logging.h" #include "base/stl_util.h" +#include "third_party/skia/include/core/SkColorFilter.h" #include "third_party/skia/include/core/SkTypeface.h" +#include "third_party/skia/include/effects/SkBlurMaskFilter.h" #include "third_party/skia/include/effects/SkGradientShader.h" +#include "third_party/skia/include/effects/SkLayerDrawLooper.h" #include "ui/base/text/utf16_indexing.h" #include "ui/gfx/canvas.h" +#include "ui/gfx/insets.h" #include "ui/gfx/native_theme.h" +#include "ui/gfx/shadow_value.h" namespace { @@ -183,6 +188,10 @@ SkiaTextRenderer::SkiaTextRenderer(Canvas* canvas) SkiaTextRenderer::~SkiaTextRenderer() { } +void SkiaTextRenderer::SetDrawLooper(SkDrawLooper* draw_looper) { + paint_.setLooper(draw_looper); +} + void SkiaTextRenderer::SetFontSmoothingSettings(bool enable_smoothing, bool enable_lcd_text) { paint_.setAntiAlias(enable_smoothing); @@ -546,8 +555,11 @@ void RenderText::Draw(Canvas* canvas) { EnsureLayout(); } + gfx::Rect clip_rect(display_rect()); + clip_rect.Inset(ShadowValue::GetMargin(text_shadows_)); + canvas->Save(); - canvas->ClipRect(display_rect()); + canvas->ClipRect(clip_rect); if (!text().empty()) DrawSelection(canvas); @@ -608,6 +620,10 @@ SelectionModel RenderText::GetSelectionModelForSelectionStart() { sel.is_reversed() ? CURSOR_BACKWARD : CURSOR_FORWARD); } +void RenderText::SetTextShadows(const std::vector<ShadowValue>& shadows) { + text_shadows_ = shadows; +} + RenderText::RenderText() : horizontal_alignment_(base::i18n::IsRTL() ? ALIGN_RIGHT : ALIGN_LEFT), cursor_enabled_(true), @@ -788,6 +804,46 @@ void RenderText::ApplyFadeEffects(internal::SkiaTextRenderer* renderer) { } } +void RenderText::ApplyTextShadows(internal::SkiaTextRenderer* renderer) { + if (text_shadows_.empty()) { + renderer->SetDrawLooper(NULL); + return; + } + + SkLayerDrawLooper* looper = new SkLayerDrawLooper; + SkAutoUnref auto_unref(looper); + + looper->addLayer(); // top layer of the original. + + SkLayerDrawLooper::LayerInfo layer_info; + layer_info.fPaintBits |= SkLayerDrawLooper::kMaskFilter_Bit; + layer_info.fPaintBits |= SkLayerDrawLooper::kColorFilter_Bit; + layer_info.fColorMode = SkXfermode::kSrc_Mode; + + for (size_t i = 0; i < text_shadows_.size(); ++i) { + const ShadowValue& shadow = text_shadows_[i]; + + layer_info.fOffset.set(SkIntToScalar(shadow.x()), + SkIntToScalar(shadow.y())); + + // SkBlurMaskFilter's blur radius defines the range to extend the blur from + // original mask, which is half of blur amount as defined in ShadowValue. + SkMaskFilter* blur_mask = SkBlurMaskFilter::Create( + SkDoubleToScalar(shadow.blur() / 2), + SkBlurMaskFilter::kNormal_BlurStyle, + SkBlurMaskFilter::kHighQuality_BlurFlag); + SkColorFilter* color_filter = SkColorFilter::CreateModeFilter( + shadow.color(), + SkXfermode::kSrcIn_Mode); + + SkPaint* paint = looper->addLayer(layer_info); + SkSafeUnref(paint->setMaskFilter(blur_mask)); + SkSafeUnref(paint->setColorFilter(color_filter)); + } + + renderer->SetDrawLooper(looper); +} + // static bool RenderText::RangeContainsCaret(const ui::Range& range, size_t caret_pos, diff --git a/ui/gfx/render_text.h b/ui/gfx/render_text.h index 1e32489..8077828 100644 --- a/ui/gfx/render_text.h +++ b/ui/gfx/render_text.h @@ -28,6 +28,7 @@ namespace gfx { class Canvas; class RenderTextTest; +class ShadowValue; struct StyleRange; namespace internal { @@ -38,6 +39,7 @@ class SkiaTextRenderer { explicit SkiaTextRenderer(Canvas* canvas); ~SkiaTextRenderer(); + void SetDrawLooper(SkDrawLooper* draw_looper); void SetFontSmoothingSettings(bool enable_smoothing, bool enable_lcd_text); void SetTypeface(SkTypeface* typeface); void SetTextSize(int size); @@ -214,6 +216,8 @@ class UI_EXPORT RenderText { // Get the size in pixels of the entire string. For the height, this will // return the maximum height among the different fonts in the text runs. + // Note that this returns the raw size of the string, which does not include + // the margin area of text shadows. virtual Size GetStringSize() = 0; void Draw(Canvas* canvas); @@ -246,6 +250,9 @@ class UI_EXPORT RenderText { // The returned value represents a cursor/caret position without a selection. SelectionModel GetSelectionModelForSelectionStart(); + // Sets shadows to drawn with text. + void SetTextShadows(const std::vector<ShadowValue>& shadows); + protected: RenderText(); @@ -339,6 +346,9 @@ class UI_EXPORT RenderText { // Applies fade effects to |renderer|. void ApplyFadeEffects(internal::SkiaTextRenderer* renderer); + // Applies text shadows to |renderer|. + void ApplyTextShadows(internal::SkiaTextRenderer* renderer); + // A convenience function to check whether the glyph attached to the caret // is within the given range. static bool RangeContainsCaret(const ui::Range& range, @@ -430,6 +440,9 @@ class UI_EXPORT RenderText { // selection, font, and other operations that adjust the visible text bounds. bool cached_bounds_and_offset_valid_; + // Text shadows to be drawn. + std::vector<ShadowValue> text_shadows_; + DISALLOW_COPY_AND_ASSIGN(RenderText); }; diff --git a/ui/gfx/render_text_linux.cc b/ui/gfx/render_text_linux.cc index e411cd9..6333bba 100644 --- a/ui/gfx/render_text_linux.cc +++ b/ui/gfx/render_text_linux.cc @@ -385,6 +385,7 @@ void RenderTextLinux::DrawVisualText(Canvas* canvas) { internal::SkiaTextRenderer renderer(canvas); ApplyFadeEffects(&renderer); + ApplyTextShadows(&renderer); renderer.SetFontSmoothingSettings( true /* enable_smoothing */, IsSubpixelRenderingEnabledInFontConfig() && !background_is_transparent()); diff --git a/ui/gfx/render_text_win.cc b/ui/gfx/render_text_win.cc index cee9738..470a499 100644 --- a/ui/gfx/render_text_win.cc +++ b/ui/gfx/render_text_win.cc @@ -476,6 +476,7 @@ void RenderTextWin::DrawVisualText(Canvas* canvas) { internal::SkiaTextRenderer renderer(canvas); ApplyFadeEffects(&renderer); + ApplyTextShadows(&renderer); bool smoothing_enabled; bool cleartype_enabled; diff --git a/ui/gfx/shadow_value.cc b/ui/gfx/shadow_value.cc new file mode 100644 index 0000000..4df5013 --- /dev/null +++ b/ui/gfx/shadow_value.cc @@ -0,0 +1,61 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/gfx/shadow_value.h" + +#include "base/stringprintf.h" +#include "ui/gfx/insets.h" + +namespace gfx { + +ShadowValue::ShadowValue() + : blur_(0), + color_(0) { +} + +ShadowValue::ShadowValue(const gfx::Point& offset, + double blur, + SkColor color) + : offset_(offset), + blur_(blur), + color_(color) { +} + +ShadowValue::~ShadowValue() { +} + +std::string ShadowValue::ToString() const { + return base::StringPrintf( + "(%d,%d),%.2f,rgba(%d,%d,%d,%d)", + offset_.x(), offset_.y(), + blur_, + SkColorGetR(color_), + SkColorGetG(color_), + SkColorGetB(color_), + SkColorGetA(color_)); +} + +// static +Insets ShadowValue::GetMargin(const std::vector<ShadowValue>& shadows) { + int left = 0; + int top = 0; + int right = 0; + int bottom = 0; + + for (size_t i = 0; i < shadows.size(); ++i) { + const ShadowValue& shadow = shadows[i]; + + // Add 0.5 to round up to the next integer. + int blur = static_cast<int>(shadow.blur() / 2 + 0.5); + + left = std::max(left, blur - shadow.x()); + top = std::max(top, blur - shadow.y()); + right = std::max(right, blur + shadow.x()); + bottom = std::max(bottom, blur + shadow.y()); + } + + return Insets(-top, -left, -bottom, -right); +} + +} // namespace gfx diff --git a/ui/gfx/shadow_value.h b/ui/gfx/shadow_value.h new file mode 100644 index 0000000..8ca9196 --- /dev/null +++ b/ui/gfx/shadow_value.h @@ -0,0 +1,58 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_GFX_SHADOW_VALUE_ +#define UI_GFX_SHADOW_VALUE_ +#pragma once + +#include <string> +#include <vector> + +#include "third_party/skia/include/core/SkColor.h" +#include "ui/base/ui_export.h" +#include "ui/gfx/point.h" + +namespace gfx { + +class Insets; + +// ShadowValue encapsulates parameters needed to define a shadow, including the +// shadow's offset, blur amount and color. +class UI_EXPORT ShadowValue { + public: + ShadowValue(); + ShadowValue(const gfx::Point& offset, double blur, SkColor color); + ~ShadowValue(); + + int x() const { return offset_.x(); } + int y() const { return offset_.y(); } + const gfx::Point& offset() const { return offset_; } + double blur() const { return blur_; } + SkColor color() const { return color_; } + + std::string ToString() const; + + // Gets margin space needed for shadows. Note that values in returned Insets + // are negative because shadow margins are outside a boundary. + static Insets GetMargin(const std::vector<ShadowValue>& shadows); + + private: + gfx::Point offset_; + + // Blur amount of the shadow in pixels. If underlying implementation supports + // (e.g. Skia), it can have fraction part such as 0.5 pixel. The value + // defines a range from full shadow color at the start point inside the + // shadow to fully transparent at the end point outside it. The range is + // perpendicular to and centered on the shadow edge. For example, a blur + // amount of 4.0 means to have a blurry shadow edge of 4 pixels that + // transitions from full shadow color to fully transparent and with 2 pixels + // inside the shadow and 2 pixels goes beyond the edge. + double blur_; + + SkColor color_; +}; + +} // namespace gfx + +#endif // UI_GFX_SHADOW_VALUE_ diff --git a/ui/gfx/shadow_value_unittest.cc b/ui/gfx/shadow_value_unittest.cc new file mode 100644 index 0000000..8c30b2b --- /dev/null +++ b/ui/gfx/shadow_value_unittest.cc @@ -0,0 +1,65 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/basictypes.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/insets.h" +#include "ui/gfx/shadow_value.h" + +namespace gfx { + +TEST(ShadowValueTest, GetMargin) { + const struct TestCase { + Insets expected_margin; + size_t shadow_count; + ShadowValue shadows[2]; + } kTestCases[] = { + { + Insets(), 0, {}, + }, + { + Insets(-2, -2, -2, -2), + 1, + { ShadowValue(gfx::Point(0, 0), 4, 0), }, + }, + { + Insets(0, -1, -4, -3), + 1, + { ShadowValue(gfx::Point(1, 2), 4, 0), }, + }, + { + Insets(-4, -3, 0, -1), + 1, + { ShadowValue(gfx::Point(-1, -2), 4, 0), }, + }, + { + Insets(0, -1, -5, -4), + 2, + { + ShadowValue(gfx::Point(1, 2), 4, 0), + ShadowValue(gfx::Point(2, 3), 4, 0), + }, + }, + { + Insets(-4, -3, -5, -4), + 2, + { + ShadowValue(gfx::Point(-1, -2), 4, 0), + ShadowValue(gfx::Point(2, 3), 4, 0), + }, + }, + }; + + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) { + std::vector<ShadowValue> shadows( + &kTestCases[i].shadows[0], + &kTestCases[i].shadows[kTestCases[i].shadow_count]); + + Insets margin = ShadowValue::GetMargin(shadows); + + EXPECT_EQ(kTestCases[i].expected_margin, margin) << " i=" << i; + } +} + +} // namespace gfx @@ -368,6 +368,8 @@ 'gfx/scrollbar_size.h', 'gfx/selection_model.cc', 'gfx/selection_model.h', + 'gfx/shadow_value.cc', + 'gfx/shadow_value.h', 'gfx/size.cc', 'gfx/size.h', 'gfx/skbitmap_operations.cc', diff --git a/ui/ui_unittests.gypi b/ui/ui_unittests.gypi index afafb6e..d68c9c7 100644 --- a/ui/ui_unittests.gypi +++ b/ui/ui_unittests.gypi @@ -91,6 +91,7 @@ 'gfx/insets_unittest.cc', 'gfx/rect_unittest.cc', 'gfx/screen_unittest.cc', + 'gfx/shadow_value_unittest.cc', 'gfx/skbitmap_operations_unittest.cc', 'gfx/skia_util_unittest.cc', 'gfx/transform_util_unittest.cc', |