summaryrefslogtreecommitdiffstats
path: root/app/gfx
diff options
context:
space:
mode:
authorben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-06 01:13:41 +0000
committerben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-06 01:13:41 +0000
commitc601cd327760f385f03d228967d8aa7445712dd6 (patch)
tree3849dc1f70c468d26dc2543db85979eb8a5b8c1d /app/gfx
parent24e5219bf22811b32ca821c35c85f31e2697160a (diff)
downloadchromium_src-c601cd327760f385f03d228967d8aa7445712dd6.zip
chromium_src-c601cd327760f385f03d228967d8aa7445712dd6.tar.gz
chromium_src-c601cd327760f385f03d228967d8aa7445712dd6.tar.bz2
move chrome_font to app/gfx
http://crbug.com/11387 Review URL: http://codereview.chromium.org/115010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15367 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'app/gfx')
-rw-r--r--app/gfx/chrome_canvas.cc2
-rw-r--r--app/gfx/chrome_canvas_linux.cc2
-rw-r--r--app/gfx/chrome_canvas_win.cc2
-rw-r--r--app/gfx/chrome_font.h237
-rw-r--r--app/gfx/chrome_font_gtk.cc85
-rw-r--r--app/gfx/chrome_font_mac.mm87
-rw-r--r--app/gfx/chrome_font_skia.cc163
-rw-r--r--app/gfx/chrome_font_unittest.cc57
-rw-r--r--app/gfx/chrome_font_win.cc211
9 files changed, 843 insertions, 3 deletions
diff --git a/app/gfx/chrome_canvas.cc b/app/gfx/chrome_canvas.cc
index 886a170..dfb1936 100644
--- a/app/gfx/chrome_canvas.cc
+++ b/app/gfx/chrome_canvas.cc
@@ -6,11 +6,11 @@
#include <limits>
+#include "app/gfx/chrome_font.h"
#include "app/l10n_util.h"
#include "base/gfx/rect.h"
#include "base/logging.h"
#include "skia/include/SkShader.h"
-#include "chrome/common/gfx/chrome_font.h"
bool ChromeCanvas::GetClipRect(gfx::Rect* r) {
SkRect clip;
diff --git a/app/gfx/chrome_canvas_linux.cc b/app/gfx/chrome_canvas_linux.cc
index 262c9db..ea5e371 100644
--- a/app/gfx/chrome_canvas_linux.cc
+++ b/app/gfx/chrome_canvas_linux.cc
@@ -6,10 +6,10 @@
#include <pango/pango.h>
+#include "app/gfx/chrome_font.h"
#include "base/gfx/rect.h"
#include "base/logging.h"
#include "base/string_util.h"
-#include "chrome/common/gfx/chrome_font.h"
namespace {
diff --git a/app/gfx/chrome_canvas_win.cc b/app/gfx/chrome_canvas_win.cc
index 4a4cd6a..76ca4d7 100644
--- a/app/gfx/chrome_canvas_win.cc
+++ b/app/gfx/chrome_canvas_win.cc
@@ -6,10 +6,10 @@
#include <limits>
+#include "app/gfx/chrome_font.h"
#include "app/l10n_util.h"
#include "base/gfx/rect.h"
#include "skia/include/SkShader.h"
-#include "chrome/common/gfx/chrome_font.h"
namespace {
diff --git a/app/gfx/chrome_font.h b/app/gfx/chrome_font.h
new file mode 100644
index 0000000..3672593
--- /dev/null
+++ b/app/gfx/chrome_font.h
@@ -0,0 +1,237 @@
+// Copyright (c) 2006-2008 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 APP_GFX_CHROME_FONT_H_
+#define APP_GFX_CHROME_FONT_H_
+
+#include "build/build_config.h"
+
+#include <string>
+
+#if defined(OS_WIN)
+typedef struct HFONT__* HFONT;
+#elif defined(OS_LINUX)
+#include "skia/include/SkRefCnt.h"
+class SkPaint;
+class SkTypeface;
+#endif
+
+#if defined(OS_WIN)
+typedef struct HFONT__* NativeFont;
+#elif defined(OS_MACOSX)
+#ifdef __OBJC__
+@class NSFont;
+#else
+class NSFont;
+#endif
+typedef NSFont* NativeFont;
+#elif defined(OS_LINUX)
+class SkTypeface;
+typedef SkTypeface* NativeFont;
+#else // null port.
+#error No known OS defined
+#endif
+
+#include "base/basictypes.h"
+#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
+
+// ChromeFont provides a wrapper around an underlying font. Copy and assignment
+// operators are explicitly allowed, and cheap.
+class ChromeFont {
+ public:
+ // The following constants indicate the font style.
+ enum {
+ NORMAL = 0,
+ BOLD = 1,
+ ITALIC = 2,
+ UNDERLINED = 4,
+ };
+
+ // Creates a ChromeFont given font name (e.g. arial), font size (e.g. 12).
+ // Skia actually expects a family name and not a font name.
+ static ChromeFont CreateFont(const std::wstring& font_name, int font_size);
+
+ ~ChromeFont() { }
+
+ // Returns a new Font derived from the existing font.
+ // size_deta is the size to add to the current font. For example, a value
+ // of 5 results in a font 5 units bigger than this font.
+ ChromeFont DeriveFont(int size_delta) const {
+ return DeriveFont(size_delta, style());
+ }
+
+ // Returns a new Font derived from the existing font.
+ // size_deta is the size to add to the current font. See the single
+ // argument version of this method for an example.
+ // The style parameter specifies the new style for the font, and is a
+ // bitmask of the values: BOLD, ITALIC and UNDERLINED.
+ ChromeFont DeriveFont(int size_delta, int style) const;
+
+ // Returns the number of vertical pixels needed to display characters from
+ // the specified font.
+ int height() const;
+
+ // Returns the baseline, or ascent, of the font.
+ int baseline() const;
+
+ // Returns the average character width for the font.
+ int ave_char_width() const;
+
+ // Returns the number of horizontal pixels needed to display the specified
+ // string.
+ int GetStringWidth(const std::wstring& text) const;
+
+ // Returns the expected number of horizontal pixels needed to display
+ // the specified length of characters.
+ // Call GetStringWidth() to retrieve the actual number.
+ int GetExpectedTextWidth(int length) const;
+
+ // Returns the style of the font.
+ int style() const;
+
+ // Font Name.
+ // It is actually a font family name, because Skia expects a family name
+ // and not a font name.
+ std::wstring FontName();
+
+ // Font Size.
+ int FontSize();
+
+ NativeFont nativeFont() const;
+
+ // Creates a font with the default name and style.
+ ChromeFont();
+
+#if defined(OS_WIN)
+ // Creates a ChromeFont from the specified HFONT. The supplied HFONT is
+ // effectively copied.
+ static ChromeFont CreateFont(HFONT hfont);
+
+ // Returns the handle to the underlying HFONT. This is used by ChromeCanvas to
+ // draw text.
+ HFONT hfont() const { return font_ref_->hfont(); }
+
+ // Dialog units to pixels conversion.
+ // See http://support.microsoft.com/kb/145994 for details.
+ int horizontal_dlus_to_pixels(int dlus) {
+ return dlus * font_ref_->dlu_base_x() / 4;
+ }
+ int vertical_dlus_to_pixels(int dlus) {
+ return dlus * font_ref_->height() / 8;
+ }
+#elif defined(OS_LINUX)
+ // We need a copy constructor and assignment operator to deal with
+ // the Skia reference counting.
+ ChromeFont(const ChromeFont& other);
+ ChromeFont& operator=(const ChromeFont& other);
+ // Setup a Skia context to use the current typeface
+ void PaintSetup(SkPaint* paint) const;
+#endif
+
+ private:
+
+#if defined(OS_WIN)
+ // Chrome text drawing bottoms out in the Windows GDI functions that take an
+ // HFONT (an opaque handle into Windows). To avoid lots of GDI object
+ // allocation and destruction, ChromeFont indirectly refers to the HFONT
+ // by way of an HFontRef. That is, every ChromeFont has an HFontRef, which
+ // has an HFONT.
+ //
+ // HFontRef is reference counted. Upon deletion, it deletes the HFONT.
+ // By making HFontRef maintain the reference to the HFONT, multiple
+ // HFontRefs can share the same HFONT, and ChromeFont can provide value
+ // semantics.
+ class HFontRef : public base::RefCounted<HFontRef> {
+ public:
+ // This constructor takes control of the HFONT, and will delete it when
+ // the HFontRef is deleted.
+ HFontRef(HFONT hfont,
+ int height,
+ int baseline,
+ int ave_char_width,
+ int style,
+ int dlu_base_x);
+ ~HFontRef();
+
+ // Accessors
+ HFONT hfont() const { return hfont_; }
+ int height() const { return height_; }
+ int baseline() const { return baseline_; }
+ int ave_char_width() const { return ave_char_width_; }
+ int style() const { return style_; }
+ int dlu_base_x() const { return dlu_base_x_; }
+
+ private:
+ const HFONT hfont_;
+ const int height_;
+ const int baseline_;
+ const int ave_char_width_;
+ const int style_;
+ // Constants used in converting dialog units to pixels.
+ const int dlu_base_x_;
+
+ DISALLOW_COPY_AND_ASSIGN(HFontRef);
+ };
+
+ // Returns the base font ref. This should ONLY be invoked on the
+ // UI thread.
+ static HFontRef* GetBaseFontRef();
+
+ // Creates and returns a new HFONTRef from the specified HFONT.
+ static HFontRef* CreateHFontRef(HFONT font);
+
+ explicit ChromeFont(HFontRef* font_ref) : font_ref_(font_ref) { }
+
+ // Reference to the base font all fonts are derived from.
+ static HFontRef* base_font_ref_;
+
+ // Indirect reference to the HFontRef, which references the underlying HFONT.
+ scoped_refptr<HFontRef> font_ref_;
+#elif defined(OS_LINUX)
+ explicit ChromeFont(SkTypeface* typeface, const std::wstring& name,
+ int size, int style);
+ // Calculate and cache the font metrics.
+ void calculateMetrics();
+ // Make |this| a copy of |other|.
+ void CopyChromeFont(const ChromeFont& other);
+
+ // The default font, used for the default constructor.
+ static ChromeFont* default_font_;
+
+ // These two both point to the same SkTypeface. We use the SkAutoUnref to
+ // handle the reference counting, but without @typeface_ we would have to
+ // cast the SkRefCnt from @typeface_helper_ every time.
+ scoped_ptr<SkAutoUnref> typeface_helper_;
+ SkTypeface *typeface_;
+
+ // Additional information about the face
+ // Skia actually expects a family name and not a font name.
+ std::wstring font_family_;
+ int font_size_;
+ int style_;
+
+ // Cached metrics, generated at construction
+ int height_;
+ int ascent_;
+ int avg_width_;
+#elif defined(OS_MACOSX)
+ explicit ChromeFont(const std::wstring& font_name, int font_size, int style);
+
+ // Calculate and cache the font metrics.
+ void calculateMetrics();
+
+ std::wstring font_name_;
+ int font_size_;
+ int style_;
+
+ // Cached metrics, generated at construction
+ int height_;
+ int ascent_;
+ int avg_width_;
+#endif
+
+};
+
+#endif // APP_GFX_CHROME_FONT_H_
diff --git a/app/gfx/chrome_font_gtk.cc b/app/gfx/chrome_font_gtk.cc
new file mode 100644
index 0000000..39acf85
--- /dev/null
+++ b/app/gfx/chrome_font_gtk.cc
@@ -0,0 +1,85 @@
+// Copyright (c) 2006-2008 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 "app/gfx/chrome_font.h"
+
+#include <fontconfig/fontconfig.h>
+#include <gtk/gtk.h>
+
+#include "base/string_util.h"
+
+ChromeFont* ChromeFont::default_font_ = NULL;
+
+// Find the best match font for |family_name| in the same way as Skia
+// to make sure CreateFont() successfully creates default font.
+// In Skia, it only checks the best match font. If it failed to find,
+// SkTypeface will be NULL for that font family. It eventually causes segfault.
+// For example, family_name = "Sans" and system may have various fonts.
+// The first font family in FcPattern will be "DejaVu Sans" but a font family
+// returned by FcFontMatch will be "VL PGothic".
+// In this case, SkTypeface for "Sans" returns NULL even if system has font
+// for "Sans" font family.
+// See FontMatch() in skia/ports/SkFontHost_fontconfig.cpp for more detail.
+static std::wstring FindBestMatchFontFamilyName(const char* family_name) {
+ FcPattern* pattern = FcPatternCreate();
+ FcValue fcvalue;
+ fcvalue.type = FcTypeString;
+ char* family_name_copy = strdup(family_name);
+ fcvalue.u.s = reinterpret_cast<FcChar8*>(family_name_copy);
+ FcPatternAdd(pattern, FC_FAMILY, fcvalue, 0);
+ FcConfigSubstitute(0, pattern, FcMatchPattern);
+ FcDefaultSubstitute(pattern);
+ FcResult result;
+ FcPattern* match = FcFontMatch(0, pattern, &result);
+ DCHECK(match) << "Could not find font: " << family_name;
+ FcChar8* match_family;
+ FcPatternGetString(match, FC_FAMILY, 0, &match_family);
+
+ std::wstring font_family = UTF8ToWide(
+ reinterpret_cast<char*>(match_family));
+ FcPatternDestroy(match);
+ FcPatternDestroy(pattern);
+ free(family_name_copy);
+ return font_family;
+}
+
+// Get the default gtk system font (name and size).
+ChromeFont::ChromeFont() {
+ if (default_font_ == NULL) {
+ gtk_init(NULL, NULL);
+ GtkSettings* settings = gtk_settings_get_default();
+
+ GValue value = {0};
+ g_value_init(&value, G_TYPE_STRING);
+ g_object_get_property(G_OBJECT(settings), "gtk-font-name", &value);
+
+ // gtk-font-name may be wrapped in quotes.
+ gchar* font_name = g_strdup_value_contents(&value);
+ gchar* font_ptr = font_name;
+ if (font_ptr[0] == '\"')
+ font_ptr++;
+ if (font_ptr[strlen(font_ptr) - 1] == '\"')
+ font_ptr[strlen(font_ptr) - 1] = '\0';
+
+ PangoFontDescription* desc =
+ pango_font_description_from_string(font_ptr);
+ gint size = pango_font_description_get_size(desc);
+ const char* family_name = pango_font_description_get_family(desc);
+
+ // Find best match font for |family_name| to make sure we can get
+ // SkTypeface for default font.
+ // TODO(agl): remove this.
+ std::wstring font_family = FindBestMatchFontFamilyName(family_name);
+
+ default_font_ = new ChromeFont(CreateFont(font_family, size / PANGO_SCALE));
+
+ pango_font_description_free(desc);
+ g_free(font_name);
+ g_value_unset(&value);
+
+ DCHECK(default_font_);
+ }
+
+ CopyChromeFont(*default_font_);
+}
diff --git a/app/gfx/chrome_font_mac.mm b/app/gfx/chrome_font_mac.mm
new file mode 100644
index 0000000..87605ad
--- /dev/null
+++ b/app/gfx/chrome_font_mac.mm
@@ -0,0 +1,87 @@
+// Copyright (c) 2009 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 "app/gfx/chrome_font.h"
+
+#include <Cocoa/Cocoa.h>
+
+#include "base/logging.h"
+#include "base/sys_string_conversions.h"
+
+// static
+ChromeFont ChromeFont::CreateFont(const std::wstring& font_name,
+ int font_size) {
+ return ChromeFont(font_name, font_size, NORMAL);
+}
+
+ChromeFont::ChromeFont(const std::wstring& font_name, int font_size, int style)
+ : font_name_(font_name),
+ font_size_(font_size),
+ style_(style) {
+ calculateMetrics();
+}
+
+ChromeFont::ChromeFont()
+ : font_size_([NSFont systemFontSize]),
+ style_(NORMAL) {
+ NSFont* system_font = [NSFont systemFontOfSize:font_size_];
+ font_name_ = base::SysNSStringToWide([system_font fontName]);
+ calculateMetrics();
+}
+
+void ChromeFont::calculateMetrics() {
+ NSFont* font = nativeFont();
+ height_ = [font xHeight];
+ ascent_ = [font ascender];
+ avg_width_ = [font boundingRectForGlyph:[font glyphWithName:@"x"]].size.width;
+}
+
+ChromeFont ChromeFont::DeriveFont(int size_delta, int style) const {
+ return ChromeFont(font_name_, font_size_ + size_delta, style);
+}
+
+int ChromeFont::height() const {
+ return height_;
+}
+
+int ChromeFont::baseline() const {
+ return ascent_;
+}
+
+int ChromeFont::ave_char_width() const {
+ return avg_width_;
+}
+
+int ChromeFont::GetStringWidth(const std::wstring& text) const {
+ NSFont* font = nativeFont();
+ NSString* ns_string = base::SysWideToNSString(text);
+ NSDictionary* attributes =
+ [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
+ NSSize string_size = [ns_string sizeWithAttributes:attributes];
+ return string_size.width;
+}
+
+int ChromeFont::GetExpectedTextWidth(int length) const {
+ return length * avg_width_;
+}
+
+int ChromeFont::style() const {
+ return style_;
+}
+
+std::wstring ChromeFont::FontName() {
+ return font_name_;
+}
+
+int ChromeFont::FontSize() {
+ return font_size_;
+}
+
+NativeFont ChromeFont::nativeFont() const {
+ // TODO(pinkerton): apply |style_| to font.
+ // We could cache this, but then we'd have to conditionally change the
+ // dtor just for MacOS. Not sure if we want to/need to do that.
+ return [NSFont fontWithName:base::SysWideToNSString(font_name_)
+ size:font_size_];
+}
diff --git a/app/gfx/chrome_font_skia.cc b/app/gfx/chrome_font_skia.cc
new file mode 100644
index 0000000..87f4ad6
--- /dev/null
+++ b/app/gfx/chrome_font_skia.cc
@@ -0,0 +1,163 @@
+// Copyright (c) 2006-2008 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 "app/gfx/chrome_font.h"
+
+#include "base/logging.h"
+#include "base/sys_string_conversions.h"
+
+#include "skia/include/SkTypeface.h"
+#include "skia/include/SkPaint.h"
+
+ChromeFont::ChromeFont(const ChromeFont& other) {
+ CopyChromeFont(other);
+}
+
+ChromeFont& ChromeFont::operator=(const ChromeFont& other) {
+ CopyChromeFont(other);
+ return *this;
+}
+
+ChromeFont::ChromeFont(SkTypeface* tf, const std::wstring& font_family,
+ int font_size, int style)
+ : typeface_helper_(new SkAutoUnref(tf)),
+ typeface_(tf),
+ font_family_(font_family),
+ font_size_(font_size),
+ style_(style) {
+ tf->ref();
+ calculateMetrics();
+}
+
+void ChromeFont::calculateMetrics() {
+ SkPaint paint;
+ SkPaint::FontMetrics metrics;
+
+ PaintSetup(&paint);
+ paint.getFontMetrics(&metrics);
+
+ ascent_ = SkScalarRound(-metrics.fAscent);
+ height_ = SkScalarRound(-metrics.fAscent + metrics.fDescent +
+ metrics.fLeading);
+
+ if (metrics.fAvgCharWidth) {
+ avg_width_ = SkScalarRound(metrics.fAvgCharWidth);
+ } else {
+ static const char x_char = 'x';
+ paint.setTextEncoding(SkPaint::kUTF8_TextEncoding);
+ SkScalar width = paint.measureText(&x_char, 1);
+
+ avg_width_ = static_cast<int>(ceilf(SkScalarToFloat(width)));
+ }
+}
+
+void ChromeFont::CopyChromeFont(const ChromeFont& other) {
+ typeface_helper_.reset(new SkAutoUnref(other.typeface_));
+ typeface_ = other.typeface_;
+ typeface_->ref();
+ font_family_ = other.font_family_;
+ font_size_ = other.font_size_;
+ style_ = other.style_;
+ height_ = other.height_;
+ ascent_ = other.ascent_;
+ avg_width_ = other.avg_width_;
+}
+
+int ChromeFont::height() const {
+ return height_;
+}
+
+int ChromeFont::baseline() const {
+ return ascent_;
+}
+
+int ChromeFont::ave_char_width() const {
+ return avg_width_;
+}
+
+ChromeFont ChromeFont::CreateFont(const std::wstring& font_family,
+ int font_size) {
+ DCHECK_GT(font_size, 0);
+
+ SkTypeface* tf = SkTypeface::Create(base::SysWideToUTF8(font_family).c_str(),
+ SkTypeface::kNormal);
+ DCHECK(tf) << "Could not find font: " << base::SysWideToUTF8(font_family);
+ SkAutoUnref tf_helper(tf);
+
+ return ChromeFont(tf, font_family, font_size, NORMAL);
+}
+
+ChromeFont ChromeFont::DeriveFont(int size_delta, int style) const {
+ // If the delta is negative, if must not push the size below 1
+ if (size_delta < 0) {
+ DCHECK_LT(-size_delta, font_size_);
+ }
+
+ if (style == style_) {
+ // Fast path, we just use the same typeface at a different size
+ return ChromeFont(typeface_, font_family_, font_size_ + size_delta, style_);
+ }
+
+ // If the style has changed we may need to load a new face
+ int skstyle = SkTypeface::kNormal;
+ if (BOLD & style)
+ skstyle |= SkTypeface::kBold;
+ if (ITALIC & style)
+ skstyle |= SkTypeface::kItalic;
+
+ SkTypeface* tf = SkTypeface::Create(base::SysWideToUTF8(font_family_).c_str(),
+ static_cast<SkTypeface::Style>(skstyle));
+ SkAutoUnref tf_helper(tf);
+
+ return ChromeFont(tf, font_family_, font_size_ + size_delta, skstyle);
+}
+
+void ChromeFont::PaintSetup(SkPaint* paint) const {
+ paint->setAntiAlias(false);
+ paint->setSubpixelText(false);
+ paint->setTextSize(SkFloatToScalar(font_size_));
+ paint->setTypeface(typeface_);
+ paint->setFakeBoldText((BOLD & style_) && !typeface_->isBold());
+ paint->setTextSkewX((ITALIC & style_) && !typeface_->isItalic() ?
+ -SK_Scalar1/4 : 0);
+}
+
+int ChromeFont::GetStringWidth(const std::wstring& text) const {
+ const std::string utf8(base::SysWideToUTF8(text));
+
+ SkPaint paint;
+ PaintSetup(&paint);
+ paint.setTextEncoding(SkPaint::kUTF8_TextEncoding);
+ SkScalar width = paint.measureText(utf8.data(), utf8.size());
+
+ int breadth = static_cast<int>(ceilf(SkScalarToFloat(width)));
+ // Check for overflow. We should probably be returning an unsigned
+ // int, but in practice we'll never have a screen massive enough
+ // to show that much text anyway.
+ if (breadth < 0)
+ return INT_MAX;
+
+ return breadth;
+}
+
+int ChromeFont::GetExpectedTextWidth(int length) const {
+ return length * avg_width_;
+}
+
+
+int ChromeFont::style() const {
+ return style_;
+}
+
+std::wstring ChromeFont::FontName() {
+ return font_family_;
+}
+
+int ChromeFont::FontSize() {
+ return font_size_;
+}
+
+NativeFont ChromeFont::nativeFont() const {
+ return typeface_;
+}
diff --git a/app/gfx/chrome_font_unittest.cc b/app/gfx/chrome_font_unittest.cc
new file mode 100644
index 0000000..5ad7973
--- /dev/null
+++ b/app/gfx/chrome_font_unittest.cc
@@ -0,0 +1,57 @@
+// Copyright (c) 2006-2008 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 "app/gfx/chrome_font.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class ChromeFontTest : public testing::Test {
+};
+
+TEST_F(ChromeFontTest, LoadArial) {
+ ChromeFont cf(ChromeFont::CreateFont(L"Arial", 16));
+ ASSERT_TRUE(cf.nativeFont());
+ ASSERT_EQ(cf.style(), ChromeFont::NORMAL);
+ ASSERT_EQ(cf.FontSize(), 16);
+ ASSERT_EQ(cf.FontName(), L"Arial");
+}
+
+TEST_F(ChromeFontTest, LoadArialBold) {
+ ChromeFont cf(ChromeFont::CreateFont(L"Arial", 16));
+ ChromeFont bold(cf.DeriveFont(0, ChromeFont::BOLD));
+ ASSERT_TRUE(bold.nativeFont());
+ ASSERT_EQ(bold.style(), ChromeFont::BOLD);
+}
+
+TEST_F(ChromeFontTest, Ascent) {
+ ChromeFont cf(ChromeFont::CreateFont(L"Arial", 16));
+ ASSERT_GT(cf.baseline(), 2);
+ ASSERT_LT(cf.baseline(), 20);
+}
+
+TEST_F(ChromeFontTest, Height) {
+ ChromeFont cf(ChromeFont::CreateFont(L"Arial", 16));
+ ASSERT_GT(cf.baseline(), 2);
+ ASSERT_LT(cf.baseline(), 20);
+}
+
+TEST_F(ChromeFontTest, AvgWidths) {
+ ChromeFont cf(ChromeFont::CreateFont(L"Arial", 16));
+ ASSERT_EQ(cf.GetExpectedTextWidth(0), 0);
+ ASSERT_GT(cf.GetExpectedTextWidth(1), cf.GetExpectedTextWidth(0));
+ ASSERT_GT(cf.GetExpectedTextWidth(2), cf.GetExpectedTextWidth(1));
+ ASSERT_GT(cf.GetExpectedTextWidth(3), cf.GetExpectedTextWidth(2));
+}
+
+TEST_F(ChromeFontTest, Widths) {
+ ChromeFont cf(ChromeFont::CreateFont(L"Arial", 16));
+ ASSERT_EQ(cf.GetStringWidth(L""), 0);
+ ASSERT_GT(cf.GetStringWidth(L"a"), cf.GetStringWidth(L""));
+ ASSERT_GT(cf.GetStringWidth(L"ab"), cf.GetStringWidth(L"a"));
+ ASSERT_GT(cf.GetStringWidth(L"abc"), cf.GetStringWidth(L"ab"));
+}
+
+} // anonymous namespace
diff --git a/app/gfx/chrome_font_win.cc b/app/gfx/chrome_font_win.cc
new file mode 100644
index 0000000..b5ddb18
--- /dev/null
+++ b/app/gfx/chrome_font_win.cc
@@ -0,0 +1,211 @@
+// Copyright (c) 2006-2008 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 "app/gfx/chrome_font.h"
+
+#include <windows.h>
+#include <math.h>
+
+#include <algorithm>
+
+#include "app/l10n_util_win.h"
+#include "base/logging.h"
+#include "base/win_util.h"
+#include "grit/generated_resources.h"
+#include "grit/locale_settings.h"
+
+/*static*/
+ChromeFont::HFontRef* ChromeFont::base_font_ref_;
+
+// If the tmWeight field of a TEXTMETRIC structure has a value >= this, the
+// font is bold.
+static const int kTextMetricWeightBold = 700;
+
+//
+// ChromeFont
+//
+
+ChromeFont::ChromeFont()
+ : font_ref_(GetBaseFontRef()) {
+}
+
+int ChromeFont::height() const {
+ return font_ref_->height();
+}
+
+int ChromeFont::baseline() const {
+ return font_ref_->baseline();
+}
+
+int ChromeFont::ave_char_width() const {
+ return font_ref_->ave_char_width();
+}
+
+int ChromeFont::GetExpectedTextWidth(int length) const {
+ return length * std::min(font_ref_->dlu_base_x(), ave_char_width());
+}
+
+int ChromeFont::style() const {
+ return font_ref_->style();
+}
+
+NativeFont ChromeFont::nativeFont() const {
+ return hfont();
+}
+
+// static
+ChromeFont ChromeFont::CreateFont(HFONT font) {
+ DCHECK(font);
+ LOGFONT font_info;
+ GetObject(font, sizeof(LOGFONT), &font_info);
+ return ChromeFont(CreateHFontRef(CreateFontIndirect(&font_info)));
+}
+
+ChromeFont ChromeFont::CreateFont(const std::wstring& font_name,
+ int font_size) {
+ HDC hdc = GetDC(NULL);
+ long lf_height = -MulDiv(font_size, GetDeviceCaps(hdc, LOGPIXELSY), 72);
+ ReleaseDC(NULL, hdc);
+ HFONT hf = ::CreateFont(lf_height, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ font_name.c_str());
+ return ChromeFont::CreateFont(hf);
+}
+
+// static
+ChromeFont::HFontRef* ChromeFont::GetBaseFontRef() {
+ if (base_font_ref_ == NULL) {
+ NONCLIENTMETRICS metrics;
+ win_util::GetNonClientMetrics(&metrics);
+
+ l10n_util::AdjustUIFont(&metrics.lfMessageFont);
+
+ // See comment in ChromeFont::DeriveFont() about font size.
+ // TODO(jungshik): Add a per-locale resource entry for the minimum
+ // font size and actually enforce the lower-bound. 5 is way too small
+ // for CJK, Thai, and Indian locales.
+ DCHECK_GE(abs(metrics.lfMessageFont.lfHeight), 5);
+ HFONT font = CreateFontIndirect(&metrics.lfMessageFont);
+ DLOG_ASSERT(font);
+ base_font_ref_ = ChromeFont::CreateHFontRef(font);
+ // base_font_ref_ is global, up the ref count so it's never deleted.
+ base_font_ref_->AddRef();
+ }
+ return base_font_ref_;
+}
+
+std::wstring ChromeFont::FontName() {
+ LOGFONT font_info;
+ GetObject(hfont(), sizeof(LOGFONT), &font_info);
+ return (std::wstring(font_info.lfFaceName));
+}
+
+int ChromeFont::FontSize() {
+ LOGFONT font_info;
+ GetObject(hfont(), sizeof(LOGFONT), &font_info);
+ long lf_height = font_info.lfHeight;
+ HDC hdc = GetDC(NULL);
+ int device_caps = GetDeviceCaps(hdc, LOGPIXELSY);
+ int font_size = 0;
+ if (device_caps != 0) {
+ float font_size_float = -static_cast<float>(lf_height)*72/device_caps;
+ font_size = static_cast<int>(::ceil(font_size_float - 0.5));
+ }
+ ReleaseDC(NULL, hdc);
+ return font_size;
+}
+
+ChromeFont::HFontRef::HFontRef(HFONT hfont,
+ int height,
+ int baseline,
+ int ave_char_width,
+ int style,
+ int dlu_base_x)
+ : hfont_(hfont),
+ height_(height),
+ baseline_(baseline),
+ ave_char_width_(ave_char_width),
+ style_(style),
+ dlu_base_x_(dlu_base_x) {
+ DLOG_ASSERT(hfont);
+}
+
+ChromeFont::HFontRef::~HFontRef() {
+ DeleteObject(hfont_);
+}
+
+
+ChromeFont ChromeFont::DeriveFont(int size_delta, int style) const {
+ LOGFONT font_info;
+ GetObject(hfont(), sizeof(LOGFONT), &font_info);
+ // LOGFONT returns two types of font heights, negative is measured slightly
+ // differently (character height, vs cell height).
+ if (font_info.lfHeight < 0) {
+ font_info.lfHeight -= size_delta;
+ } else {
+ font_info.lfHeight += size_delta;
+ }
+ // Even with "Small Fonts", the smallest readable font size is 5. It is easy
+ // to create a non-drawing font and forget about the fact that text should be
+ // drawn in the UI. This test ensures that the font will be readable.
+ DCHECK_GE(abs(font_info.lfHeight), 5);
+ font_info.lfUnderline = ((style & UNDERLINED) == UNDERLINED);
+ font_info.lfItalic = ((style & ITALIC) == ITALIC);
+ font_info.lfWeight = (style & BOLD) ? FW_BOLD : FW_NORMAL;
+
+ HFONT hfont = CreateFontIndirect(&font_info);
+ return ChromeFont(CreateHFontRef(hfont));
+}
+
+int ChromeFont::GetStringWidth(const std::wstring& text) const {
+ int width = 0;
+ HDC dc = GetDC(NULL);
+ HFONT previous_font = static_cast<HFONT>(SelectObject(dc, hfont()));
+ SIZE size;
+ if (GetTextExtentPoint32(dc, text.c_str(), static_cast<int>(text.size()),
+ &size)) {
+ width = size.cx;
+ } else {
+ width = 0;
+ }
+ SelectObject(dc, previous_font);
+ ReleaseDC(NULL, dc);
+ return width;
+}
+
+ChromeFont::HFontRef* ChromeFont::CreateHFontRef(HFONT font) {
+ TEXTMETRIC font_metrics;
+ HDC screen_dc = GetDC(NULL);
+ HFONT previous_font = static_cast<HFONT>(SelectObject(screen_dc, font));
+ int last_map_mode = SetMapMode(screen_dc, MM_TEXT);
+ GetTextMetrics(screen_dc, &font_metrics);
+ // Yes, this is how Microsoft recommends calculating the dialog unit
+ // conversions.
+ SIZE ave_text_size;
+ GetTextExtentPoint32(screen_dc,
+ L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
+ 52, &ave_text_size);
+ const int dlu_base_x = (ave_text_size.cx / 26 + 1) / 2;
+ // To avoid the DC referencing font_handle_, select the previous font.
+ SelectObject(screen_dc, previous_font);
+ SetMapMode(screen_dc, last_map_mode);
+ ReleaseDC(NULL, screen_dc);
+
+ const int height = std::max(1, static_cast<int>(font_metrics.tmHeight));
+ const int baseline = std::max(1, static_cast<int>(font_metrics.tmAscent));
+ const int ave_char_width =
+ std::max(1, static_cast<int>(font_metrics.tmAveCharWidth));
+ int style = 0;
+ if (font_metrics.tmItalic) {
+ style |= ChromeFont::ITALIC;
+ }
+ if (font_metrics.tmUnderlined) {
+ style |= ChromeFont::UNDERLINED;
+ }
+ if (font_metrics.tmWeight >= kTextMetricWeightBold) {
+ style |= ChromeFont::BOLD;
+ }
+
+ return new HFontRef(font, height, baseline, ave_char_width, style,
+ dlu_base_x);
+}