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
3 // found in the LICENSE file.
4
5 #include "chrome/common/badge_util.h"
6
7 #include "base/logging.h"
8 #include "base/utf_string_conversions.h"
9 #include "third_party/skia/include/core/SkPaint.h"
10 #include "third_party/skia/include/core/SkTypeface.h"
11 #include "ui/base/resource/resource_bundle.h"
12 #include "ui/gfx/canvas_skia.h"
13 #include "ui/gfx/font.h"
14
15 namespace badge_util {
16
GetBadgeTextPaintSingleton()17 SkPaint* GetBadgeTextPaintSingleton() {
18 #if defined(OS_MACOSX)
19 const char kPreferredTypeface[] = "Helvetica Bold";
20 #else
21 const char kPreferredTypeface[] = "Arial";
22 #endif
23
24 static SkPaint* text_paint = NULL;
25 if (!text_paint) {
26 text_paint = new SkPaint;
27 text_paint->setAntiAlias(true);
28 text_paint->setTextAlign(SkPaint::kLeft_Align);
29
30 SkTypeface* typeface = SkTypeface::CreateFromName(
31 kPreferredTypeface, SkTypeface::kBold);
32 // Skia doesn't do any font fallback---if the user is missing the font then
33 // typeface will be NULL. If we don't do manual fallback then we'll crash.
34 if (typeface) {
35 text_paint->setFakeBoldText(true);
36 } else {
37 // Fall back to the system font. We don't bold it because we aren't sure
38 // how it will look.
39 // For the most part this code path will only be hit on Linux systems
40 // that don't have Arial.
41 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
42 const gfx::Font& base_font = rb.GetFont(ResourceBundle::BaseFont);
43 typeface = SkTypeface::CreateFromName(
44 UTF16ToUTF8(base_font.GetFontName()).c_str(), SkTypeface::kNormal);
45 DCHECK(typeface);
46 }
47
48 text_paint->setTypeface(typeface);
49 // |text_paint| adds its own ref. Release the ref from CreateFontName.
50 typeface->unref();
51 }
52 return text_paint;
53 }
54
DrawBadgeIconOverlay(const SkBitmap & icon,float font_size,const string16 & text,const string16 & fallback)55 SkBitmap DrawBadgeIconOverlay(const SkBitmap& icon,
56 float font_size,
57 const string16& text,
58 const string16& fallback) {
59 const int kMinPadding = 1;
60
61 // Calculate the proper style/text overlay to render on the badge.
62 SkPaint* paint = badge_util::GetBadgeTextPaintSingleton();
63 paint->setTextSize(SkFloatToScalar(font_size));
64 paint->setColor(SK_ColorWHITE);
65
66 std::string badge_text = UTF16ToUTF8(text);
67
68 // See if the text will fit - otherwise use a default.
69 SkScalar text_width = paint->measureText(badge_text.c_str(),
70 badge_text.size());
71
72 if (SkScalarRound(text_width) > (icon.width() - kMinPadding * 2)) {
73 // String is too large - use the alternate text.
74 badge_text = UTF16ToUTF8(fallback);
75 text_width = paint->measureText(badge_text.c_str(), badge_text.size());
76 }
77
78 // When centering the text, we need to make sure there are an equal number
79 // of pixels on each side as otherwise the text looks off-center. So if the
80 // padding would be uneven, clip one pixel off the right side.
81 int badge_width = icon.width();
82 if ((SkScalarRound(text_width) % 1) != (badge_width % 1))
83 badge_width--;
84
85 // Render the badge bitmap and overlay into a canvas.
86 scoped_ptr<gfx::CanvasSkia> canvas(
87 new gfx::CanvasSkia(badge_width, icon.height(), false));
88 canvas->DrawBitmapInt(icon, 0, 0);
89
90 // Draw the text overlay centered horizontally and vertically. Skia expects
91 // us to specify the lower left coordinate of the text box, which is why we
92 // add 'font_size - 1' to the height.
93 SkScalar x = (badge_width - text_width)/2;
94 SkScalar y = (icon.height() - font_size)/2 + font_size - 1;
95 canvas->drawText(badge_text.c_str(), badge_text.size(), x, y, *paint);
96
97 // Return the generated image.
98 return canvas->ExtractBitmap();
99 }
100
101 } // namespace badge_util
102