diff options
author | stuartmorgan <stuartmorgan@chromium.org> | 2015-03-09 13:19:15 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-03-09 20:20:12 +0000 |
commit | 018f5c02de9fc3e41c273b19e8eb60a503b05d57 (patch) | |
tree | 01d854a2bc80bc57be906d82e51d7065e62e146c /ui/gfx/ios | |
parent | 9b40df656981fa2e9eaf158f22016b0d566bdaa8 (diff) | |
download | chromium_src-018f5c02de9fc3e41c273b19e8eb60a503b05d57.zip chromium_src-018f5c02de9fc3e41c273b19e8eb60a503b05d57.tar.gz chromium_src-018f5c02de9fc3e41c273b19e8eb60a503b05d57.tar.bz2 |
Eliminate ui/ios
Per the explanation in the bug, ui/ios should not have been created in
the first place; this code belongs in the ui/gfx subcomponent.
BUG=446643
Review URL: https://codereview.chromium.org/983413004
Cr-Commit-Position: refs/heads/master@{#319720}
Diffstat (limited to 'ui/gfx/ios')
-rw-r--r-- | ui/gfx/ios/NSString+CrStringDrawing.h | 55 | ||||
-rw-r--r-- | ui/gfx/ios/NSString+CrStringDrawing.mm | 40 | ||||
-rw-r--r-- | ui/gfx/ios/NSString+CrStringDrawing_unittest.mm | 151 | ||||
-rw-r--r-- | ui/gfx/ios/OWNERS | 3 | ||||
-rw-r--r-- | ui/gfx/ios/uikit_util.h | 26 | ||||
-rw-r--r-- | ui/gfx/ios/uikit_util.mm | 23 | ||||
-rw-r--r-- | ui/gfx/ios/uikit_util_unittest.mm | 51 |
7 files changed, 349 insertions, 0 deletions
diff --git a/ui/gfx/ios/NSString+CrStringDrawing.h b/ui/gfx/ios/NSString+CrStringDrawing.h new file mode 100644 index 0000000..10916e9 --- /dev/null +++ b/ui/gfx/ios/NSString+CrStringDrawing.h @@ -0,0 +1,55 @@ +// 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_GFX_IOS_NSSTRING_CR_STRING_DRAWING_H_ +#define UI_GFX_IOS_NSSTRING_CR_STRING_DRAWING_H_ + +#import <UIKit/UIKit.h> + +@interface NSString (CrStringDrawing) + +// Calculates and returns the bounding rect for the receiver drawn using the +// given size and font. +// This method is implemented as a wrapper around +// |boundingRectWithSize:options:attributes:context:| using the following values +// for the parameters: +// - size: the provided |size| +// - options: NSStringDrawingUsesLineFragmentOrigin +// - attributes: a NSDictionary with the provided |font| +// - context: nil. +// +// Note that the rect returned may contain fractional values. +- (CGRect)cr_boundingRectWithSize:(CGSize)size + font:(UIFont*)font; + +// Convenience wrapper to just return the size of |boundingRectWithSize:font:|. +// +// Note that the size returned may contain fractional values. +- (CGSize)cr_boundingSizeWithSize:(CGSize)size + font:(UIFont*)font; + +// 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_GFX_IOS_NSSTRING_CR_STRING_DRAWING_H_ diff --git a/ui/gfx/ios/NSString+CrStringDrawing.mm b/ui/gfx/ios/NSString+CrStringDrawing.mm new file mode 100644 index 0000000..0d6d0b4 --- /dev/null +++ b/ui/gfx/ios/NSString+CrStringDrawing.mm @@ -0,0 +1,40 @@ +// 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/gfx/ios/NSString+CrStringDrawing.h" + +#include "base/logging.h" +#include "ui/gfx/ios/uikit_util.h" + +@implementation NSString (CrStringDrawing) + +- (CGRect)cr_boundingRectWithSize:(CGSize)size + font:(UIFont*)font { + NSDictionary* attributes = font ? @{NSFontAttributeName: font} : @{}; + return [self boundingRectWithSize:size + options:NSStringDrawingUsesLineFragmentOrigin + attributes:attributes + context:nil]; +} + +- (CGSize)cr_boundingSizeWithSize:(CGSize)size + font:(UIFont*)font { + return [self cr_boundingRectWithSize:size font:font].size; +} + +- (CGSize)cr_pixelAlignedSizeWithFont:(UIFont*)font { + DCHECK(font) << "|font| can not be nil; it is used as a NSDictionary value"; + NSDictionary* attributes = @{ NSFontAttributeName : font }; + return ui::AlignSizeToUpperPixel([self sizeWithAttributes:attributes]); +} + +- (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/gfx/ios/NSString+CrStringDrawing_unittest.mm b/ui/gfx/ios/NSString+CrStringDrawing_unittest.mm new file mode 100644 index 0000000..02fc3c2 --- /dev/null +++ b/ui/gfx/ios/NSString+CrStringDrawing_unittest.mm @@ -0,0 +1,151 @@ +// 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/gfx/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 tests verify 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" + +// Verifies that |cr_boundingSizeWithSize| returns the same size as the +// deprecated |sizeWithFont:constrainedToSize| for most values. +// Note that the methods return different values in a few cases (so they are not +// included in the test cases): +// - the constrained size.width is less than a character. +// - the constrained size.height is less than the font height. +// - the string is empty. +TEST_F(NSStringCrStringDrawing, BoundingSizeWithSize) { + NSArray* fonts = @[ + [UIFont systemFontOfSize:16], + [UIFont boldSystemFontOfSize:10], + [UIFont fontWithName:@"Helvetica" size:12.0], + ]; + NSArray* strings = @[ + @"Test", + @"multi word test", + @"你好", + @"★ This is a test string that is very long.", + ]; + NSArray* sizes = @[ + [NSValue valueWithCGSize:CGSizeMake(20, 100)], + [NSValue valueWithCGSize:CGSizeMake(100, 100)], + [NSValue valueWithCGSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)], + ]; + for (UIFont* font in fonts) { + for (NSString* string in strings) { + for (NSValue* sizeValue in sizes) { + CGSize test_size = [sizeValue CGSizeValue]; + std::string test_tag = base::StringPrintf( + "for string '%s' with font %s and size %s", + base::SysNSStringToUTF8(string).c_str(), + base::SysNSStringToUTF8([font description]).c_str(), + base::SysNSStringToUTF8(NSStringFromCGSize(test_size)).c_str()); + + CGSize size_with_font = + [string sizeWithFont:font constrainedToSize:test_size]; + CGSize bounding_size = + [string cr_boundingSizeWithSize:test_size font:font]; + EXPECT_EQ(size_with_font.width, bounding_size.width) << test_tag; + EXPECT_EQ(size_with_font.height, bounding_size.height) << test_tag; + } + } + } +} + +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/gfx/ios/OWNERS b/ui/gfx/ios/OWNERS new file mode 100644 index 0000000..f2fff55 --- /dev/null +++ b/ui/gfx/ios/OWNERS @@ -0,0 +1,3 @@ +lliabraa@chromium.org +rohitrao@chromium.org +sdefresne@chromium.org diff --git a/ui/gfx/ios/uikit_util.h b/ui/gfx/ios/uikit_util.h new file mode 100644 index 0000000..fbacda3 --- /dev/null +++ b/ui/gfx/ios/uikit_util.h @@ -0,0 +1,26 @@ +// 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_GFX_IOS_UIKIT_UTIL_H_ +#define UI_GFX_IOS_UIKIT_UTIL_H_ + +#import <UIKit/UIKit.h> + +#include "base/compiler_specific.h" + +// UI Util containing functions that require UIKit. + +namespace ui { + +// Returns the closest pixel-aligned value higher than |value|, taking the scale +// factor into account. At a scale of 1, equivalent to ceil(). +CGFloat AlignValueToUpperPixel(CGFloat value) WARN_UNUSED_RESULT; + +// Returns the size resulting from applying AlignToUpperPixel to both +// components. +CGSize AlignSizeToUpperPixel(CGSize size) WARN_UNUSED_RESULT; + +} // namespace ui + +#endif // UI_GFX_IOS_UIKIT_UTIL_H_ diff --git a/ui/gfx/ios/uikit_util.mm b/ui/gfx/ios/uikit_util.mm new file mode 100644 index 0000000..2e0bfdb --- /dev/null +++ b/ui/gfx/ios/uikit_util.mm @@ -0,0 +1,23 @@ +// 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. + +#include "ui/gfx/ios/uikit_util.h" + +#import <UIKit/UIKit.h> + +#include <cmath> + +namespace ui { + +CGFloat AlignValueToUpperPixel(CGFloat value) { + CGFloat scale = [[UIScreen mainScreen] scale]; + return std::ceil(value * scale) / scale; +} + +CGSize AlignSizeToUpperPixel(CGSize size) { + return CGSizeMake(AlignValueToUpperPixel(size.width), + AlignValueToUpperPixel(size.height)); +} + +} // namespace ui diff --git a/ui/gfx/ios/uikit_util_unittest.mm b/ui/gfx/ios/uikit_util_unittest.mm new file mode 100644 index 0000000..b343f4e --- /dev/null +++ b/ui/gfx/ios/uikit_util_unittest.mm @@ -0,0 +1,51 @@ +// 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 <Foundation/Foundation.h> + +#include "base/basictypes.h" +#include "testing/platform_test.h" +#import "ui/gfx/ios/uikit_util.h" + +namespace { + +typedef PlatformTest UIKitUtilTest; + +TEST_F(UIKitUtilTest, AlignValueToUpperPixel) { + CGFloat scale = [[UIScreen mainScreen] scale]; + // Pick a few interesting values: already aligned, aligned on retina, and + // some unaligned values that would round differently. Ensure that all are + // "integer" values within <1 of the original value in the scaled space. + CGFloat test_values[] = { 10.0, 55.5, 3.1, 2.9 }; + const CGFloat kMaxAlignDelta = 0.9999; + size_t value_count = arraysize(test_values); + for (unsigned int i = 0; i < value_count; ++i) { + CGFloat aligned = ui::AlignValueToUpperPixel(test_values[i]); + EXPECT_FLOAT_EQ(aligned * scale, floor(aligned * scale)); + EXPECT_NEAR(aligned * scale, test_values[i] * scale, kMaxAlignDelta); + } +} + +TEST_F(UIKitUtilTest, AlignSizeToUpperPixel) { + CGFloat scale = [[UIScreen mainScreen] scale]; + // Pick a few interesting values: already aligned, aligned on retina, and + // some unaligned values that would round differently. Ensure that all are + // "integer" values within <1 of the original value in the scaled space. + CGFloat test_values[] = { 10.0, 55.5, 3.1, 2.9 }; + const CGFloat kMaxAlignDelta = 0.9999; + size_t value_count = arraysize(test_values); + for (unsigned int i = 0; i < value_count; ++i) { + CGFloat width = test_values[i]; + CGFloat height = test_values[(i + 1) % value_count]; + CGSize alignedSize = ui::AlignSizeToUpperPixel(CGSizeMake(width, height)); + EXPECT_FLOAT_EQ(floor(alignedSize.width * scale), + alignedSize.width * scale); + EXPECT_FLOAT_EQ(floor(alignedSize.height * scale), + alignedSize.height * scale); + EXPECT_NEAR(width * scale, alignedSize.width * scale, kMaxAlignDelta); + EXPECT_NEAR(height * scale, alignedSize.height * scale, kMaxAlignDelta); + } +} + +} // namespace |