summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build/all.gyp1
-rw-r--r--ui/gfx/DEPS1
-rw-r--r--ui/gfx/gfx.gyp3
-rw-r--r--ui/gfx/platform_font_ios.mm8
-rw-r--r--ui/gfx/text_utils_ios.mm6
-rw-r--r--ui/ios/NSString+CrStringDrawing.h35
-rw-r--r--ui/ios/NSString+CrStringDrawing.mm37
-rw-r--r--ui/ios/NSString+CrStringDrawing_unittest.mm107
-rw-r--r--ui/ios/ui_ios.gyp27
-rw-r--r--ui/ios/ui_ios_tests.gyp25
10 files changed, 240 insertions, 10 deletions
diff --git a/build/all.gyp b/build/all.gyp
index d7fe596..bb3479a 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -40,6 +40,7 @@
'dependencies': [
'../ios/ios.gyp:*',
'../ui/base/ui_base_tests.gyp:ui_unittests',
+ '../ui/ios/ui_ios_tests.gyp:ui_ios_unittests',
'../ui/gfx/gfx_tests.gyp:gfx_unittests',
],
}],
diff --git a/ui/gfx/DEPS b/ui/gfx/DEPS
index 758e42a..a1bf2f7 100644
--- a/ui/gfx/DEPS
+++ b/ui/gfx/DEPS
@@ -3,4 +3,5 @@ include_rules = [
"+skia/ext",
"+third_party/harfbuzz-ng",
"+third_party/skia",
+ "+ui/ios",
]
diff --git a/ui/gfx/gfx.gyp b/ui/gfx/gfx.gyp
index 99835fc..85ea553 100644
--- a/ui/gfx/gfx.gyp
+++ b/ui/gfx/gfx.gyp
@@ -309,6 +309,9 @@
],
'conditions': [
['OS=="ios"', {
+ 'dependencies': [
+ '<(DEPTH)/ui/ios/ui_ios.gyp:ui_ios',
+ ],
# iOS only uses a subset of UI.
'sources/': [
['exclude', '^codec/jpeg_codec\\.cc$'],
diff --git a/ui/gfx/platform_font_ios.mm b/ui/gfx/platform_font_ios.mm
index 0fd824f..502f1a4 100644
--- a/ui/gfx/platform_font_ios.mm
+++ b/ui/gfx/platform_font_ios.mm
@@ -13,6 +13,7 @@
#include "base/strings/utf_string_conversions.h"
#include "ui/gfx/font.h"
#include "ui/gfx/font_render_params.h"
+#include "ui/ios/NSString+CrStringDrawing.h"
namespace gfx {
@@ -112,12 +113,7 @@ void PlatformFontIOS::CalculateMetrics() {
height_ = font.lineHeight;
ascent_ = font.ascender;
cap_height_ = font.capHeight;
- if (font) {
- NSDictionary* attributes = @{ NSFontAttributeName : font };
- average_width_ = std::ceil([@"x" sizeWithAttributes:attributes].width);
- } else {
- average_width_ = 0;
- }
+ average_width_ = [@"x" cr_sizeWithFont:font].width;
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/ui/gfx/text_utils_ios.mm b/ui/gfx/text_utils_ios.mm
index e687f35..c6b8570 100644
--- a/ui/gfx/text_utils_ios.mm
+++ b/ui/gfx/text_utils_ios.mm
@@ -10,6 +10,7 @@
#include "base/strings/sys_string_conversions.h"
#include "ui/gfx/font_list.h"
+#include "ui/ios/NSString+CrStringDrawing.h"
namespace gfx {
@@ -20,10 +21,7 @@ int GetStringWidth(const base::string16& text, const FontList& font_list) {
float GetStringWidthF(const base::string16& text, const FontList& font_list) {
NSString* ns_text = base::SysUTF16ToNSString(text);
NativeFont native_font = font_list.GetPrimaryFont().GetNativeFont();
- if (!native_font)
- return 0;
- NSDictionary* attributes = @{ NSFontAttributeName : native_font };
- return std::ceil([ns_text sizeWithAttributes:attributes].width);
+ return [ns_text cr_sizeWithFont:native_font].width;
}
} // namespace gfx
diff --git a/ui/ios/NSString+CrStringDrawing.h b/ui/ios/NSString+CrStringDrawing.h
new file mode 100644
index 0000000..330593e
--- /dev/null
+++ b/ui/ios/NSString+CrStringDrawing.h
@@ -0,0 +1,35 @@
+// Copyright 2014 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_IOS_NSSTRING_CR_STRING_DRAWING_H_
+#define UI_IOS_NSSTRING_CR_STRING_DRAWING_H_
+
+#import <UIKit/UIKit.h>
+
+@interface NSString (CrStringDrawing)
+
+// Returns the size of the string if it were to be rendered with the specified
+// font on a single line. The width and height of the CGSize returned are
+// pixel-aligned.
+//
+// This method is a convenience wrapper around sizeWithAttributes: to avoid
+// boilerplate required to put |font| in a dictionary of attributes. Do not pass
+// nil into this method.
+- (CGSize)cr_pixelAlignedSizeWithFont:(UIFont*)font;
+
+// Deprecated: Use cr_pixelAlignedSizeWithFont: or sizeWithAttributes:
+// Provides a drop-in replacement for sizeWithFont:, which was deprecated in iOS
+// 7 in favor of -sizeWithAttributes:. Specifically, this method will return
+// CGSizeZero if |font| is nil, and the width and height returned are rounded up
+// to integer values.
+// TODO(lliabraa): This method was added to ease the transition off of the
+// deprecated sizeWithFont: method. New call sites should not be added and
+// existing call sites should be audited to determine the correct behavior for
+// nil |font| and rounding, then replaced with cr_pixelAlignedSizeWithFont: or
+// sizeWithAttributes: (crbug.com/364419).
+- (CGSize)cr_sizeWithFont:(UIFont*)font;
+
+@end
+
+#endif // UI_IOS_NSSTRING_CR_STRING_DRAWING_H_
diff --git a/ui/ios/NSString+CrStringDrawing.mm b/ui/ios/NSString+CrStringDrawing.mm
new file mode 100644
index 0000000..9f7d88b
--- /dev/null
+++ b/ui/ios/NSString+CrStringDrawing.mm
@@ -0,0 +1,37 @@
+// Copyright 2014 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.
+
+#import "ui/ios/NSString+CrStringDrawing.h"
+
+#include "base/logging.h"
+
+namespace {
+// Returns the closest pixel-aligned value higher than |value|, taking the scale
+// factor into account. At a scale of 1, equivalent to ceil().
+// TODO(lliabraa): Move this method to a common util file (crbug.com/409823).
+CGFloat alignValueToUpperPixel(CGFloat value) {
+ CGFloat scale = [[UIScreen mainScreen] scale];
+ return ceil(value * scale) / scale;
+}
+} // namespace
+
+@implementation NSString (CrStringDrawing)
+
+- (CGSize)cr_pixelAlignedSizeWithFont:(UIFont*)font {
+ DCHECK(font) << "|font| can not be nil; it is used as a NSDictionary value";
+ NSDictionary* attributes = @{ NSFontAttributeName : font };
+ CGSize size = [self sizeWithAttributes:attributes];
+ return CGSizeMake(alignValueToUpperPixel(size.width),
+ alignValueToUpperPixel(size.height));
+}
+
+- (CGSize)cr_sizeWithFont:(UIFont*)font {
+ if (!font)
+ return CGSizeZero;
+ NSDictionary* attributes = @{ NSFontAttributeName : font };
+ CGSize size = [self sizeWithAttributes:attributes];
+ return CGSizeMake(ceil(size.width), ceil(size.height));
+}
+
+@end
diff --git a/ui/ios/NSString+CrStringDrawing_unittest.mm b/ui/ios/NSString+CrStringDrawing_unittest.mm
new file mode 100644
index 0000000..6f0497d
--- /dev/null
+++ b/ui/ios/NSString+CrStringDrawing_unittest.mm
@@ -0,0 +1,107 @@
+// Copyright 2014 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.
+#import "ui/ios/NSString+CrStringDrawing.h"
+
+#include "base/mac/scoped_nsobject.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/sys_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+typedef PlatformTest NSStringCrStringDrawing;
+
+// These test verifies that the category methods return the same values as the
+// deprecated methods, so ignore warnings about using deprecated methods.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+TEST_F(NSStringCrStringDrawing, SizeWithFont) {
+ NSArray* fonts = @[
+ [NSNull null],
+ [UIFont systemFontOfSize:16],
+ [UIFont boldSystemFontOfSize:10],
+ [UIFont fontWithName:@"Helvetica" size:12.0],
+ ];
+ for (UIFont* font in fonts) {
+ if ([font isEqual:[NSNull null]])
+ font = nil;
+ std::string font_tag = "with font ";
+ font_tag.append(
+ base::SysNSStringToUTF8(font ? [font description] : @"nil"));
+ EXPECT_EQ([@"" sizeWithFont:font].width,
+ [@"" cr_sizeWithFont:font].width) << font_tag;
+ EXPECT_EQ([@"" sizeWithFont:font].height,
+ [@"" cr_sizeWithFont:font].height) << font_tag;
+ EXPECT_EQ([@"Test" sizeWithFont:font].width,
+ [@"Test" cr_sizeWithFont:font].width) << font_tag;
+ EXPECT_EQ([@"Test" sizeWithFont:font].height,
+ [@"Test" cr_sizeWithFont:font].height) << font_tag;
+ EXPECT_EQ([@"你好" sizeWithFont:font].width,
+ [@"你好" cr_sizeWithFont:font].width) << font_tag;
+ EXPECT_EQ([@"你好" sizeWithFont:font].height,
+ [@"你好" cr_sizeWithFont:font].height) << font_tag;
+ NSString* long_string = @"★ This is a test string that is very long.";
+ EXPECT_EQ([long_string sizeWithFont:font].width,
+ [long_string cr_sizeWithFont:font].width) << font_tag;
+ EXPECT_EQ([long_string sizeWithFont:font].height,
+ [long_string cr_sizeWithFont:font].height) << font_tag;
+ }
+}
+#pragma clang diagnostic pop // ignored "-Wdeprecated-declarations"
+
+TEST_F(NSStringCrStringDrawing, PixelAlignedSizeWithFont) {
+ NSArray* fonts = @[
+ [UIFont systemFontOfSize:16],
+ [UIFont boldSystemFontOfSize:10],
+ [UIFont fontWithName:@"Helvetica" size:12.0],
+ ];
+ NSArray* strings = @[
+ @"",
+ @"Test",
+ @"你好",
+ @"★ This is a test string that is very long.",
+ ];
+ for (UIFont* font in fonts) {
+ NSDictionary* attributes = @{ NSFontAttributeName : font };
+
+ for (NSString* string in strings) {
+ std::string test_tag = base::StringPrintf("for string '%s' with font %s",
+ base::SysNSStringToUTF8(string).c_str(),
+ base::SysNSStringToUTF8([font description]).c_str());
+
+ CGSize size_with_attributes = [string sizeWithAttributes:attributes];
+ CGSize size_with_pixel_aligned =
+ [string cr_pixelAlignedSizeWithFont:font];
+
+ // Verify that the pixel_aligned size is always rounded up (i.e. the size
+ // returned from sizeWithAttributes: is less than or equal to the pixel-
+ // aligned size).
+ EXPECT_LE(size_with_attributes.width,
+ size_with_pixel_aligned.width) << test_tag;
+ EXPECT_LE(size_with_attributes.height,
+ size_with_pixel_aligned.height) << test_tag;
+
+ // Verify that the pixel_aligned size is never more than a pixel different
+ // than the size returned from sizeWithAttributes:.
+ static CGFloat scale = [[UIScreen mainScreen] scale];
+ EXPECT_NEAR(size_with_attributes.width * scale,
+ size_with_pixel_aligned.width * scale,
+ 0.9999) << test_tag;
+ EXPECT_NEAR(size_with_attributes.height * scale,
+ size_with_pixel_aligned.height * scale,
+ 0.9999) << test_tag;
+
+ // Verify that the pixel-aligned value is pixel-aligned.
+ EXPECT_FLOAT_EQ(roundf(size_with_pixel_aligned.width * scale),
+ size_with_pixel_aligned.width * scale) << test_tag;
+ EXPECT_FLOAT_EQ(roundf(size_with_pixel_aligned.height * scale),
+ size_with_pixel_aligned.height * scale) << test_tag;
+ }
+ }
+}
+
+
+} // namespace
diff --git a/ui/ios/ui_ios.gyp b/ui/ios/ui_ios.gyp
new file mode 100644
index 0000000..afec667
--- /dev/null
+++ b/ui/ios/ui_ios.gyp
@@ -0,0 +1,27 @@
+# Copyright 2014 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.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'targets': [
+ {
+ 'target_name': 'ui_ios',
+ 'type': 'static_library',
+ # Linkable dependents need to set the linker flag '-ObjC' in order to use
+ # the categories in this target (e.g. NSString+CrStringDrawing.h).
+ 'link_settings': {
+ 'xcode_settings': {'OTHER_LDFLAGS': ['-ObjC']},
+ },
+ 'include_dirs': [
+ '../..',
+ ],
+ 'sources': [
+ 'NSString+CrStringDrawing.h',
+ 'NSString+CrStringDrawing.mm',
+ ],
+ },
+ ],
+}
diff --git a/ui/ios/ui_ios_tests.gyp b/ui/ios/ui_ios_tests.gyp
new file mode 100644
index 0000000..08f7e46
--- /dev/null
+++ b/ui/ios/ui_ios_tests.gyp
@@ -0,0 +1,25 @@
+# Copyright 2014 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.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'targets': [
+ {
+ 'target_name': 'ui_ios_unittests',
+ 'type': '<(gtest_target_type)',
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../../base/base.gyp:run_all_unittests',
+ '../../base/base.gyp:test_support_base',
+ '../../testing/gtest.gyp:gtest',
+ 'ui_ios.gyp:ui_ios',
+ ],
+ 'sources' : [
+ 'NSString+CrStringDrawing_unittest.mm',
+ ],
+ },
+ ],
+} \ No newline at end of file