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