| Index: ios/chrome/browser/ui/util/manual_text_framer_unittest.mm
|
| diff --git a/ios/chrome/browser/ui/util/manual_text_framer_unittest.mm b/ios/chrome/browser/ui/util/manual_text_framer_unittest.mm
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..532b351d670b7c2d766e5d604873b3b2df055a5d
|
| --- /dev/null
|
| +++ b/ios/chrome/browser/ui/util/manual_text_framer_unittest.mm
|
| @@ -0,0 +1,301 @@
|
| +// Copyright 2015 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 "ios/chrome/browser/ui/util/manual_text_framer.h"
|
| +
|
| +#include "base/mac/foundation_util.h"
|
| +#import "base/mac/scoped_nsobject.h"
|
| +#include "base/time/time.h"
|
| +#import "ios/chrome/browser/ui/util/core_text_util.h"
|
| +#import "ios/chrome/browser/ui/util/text_frame.h"
|
| +#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +#include "testing/gtest_mac.h"
|
| +#include "testing/platform_test.h"
|
| +#include "url/gurl.h"
|
| +
|
| +namespace {
|
| +// Copy of ManualTextFramer's alignment function.
|
| +enum class AlignmentFunction : short { CEIL = 0, FLOOR };
|
| +CGFloat AlignValueToPixel(CGFloat value, AlignmentFunction function) {
|
| + static CGFloat scale = [[UIScreen mainScreen] scale];
|
| + return function == AlignmentFunction::CEIL ? ceil(value * scale) / scale
|
| + : floor(value * scale) / scale;
|
| +}
|
| +
|
| +class ManualTextFramerTest : public PlatformTest {
|
| + protected:
|
| + void SetUp() override {
|
| + attributes_.reset([[NSMutableDictionary alloc] init]);
|
| + string_.reset([[NSMutableAttributedString alloc] init]);
|
| + }
|
| +
|
| + NSString* text() { return [string_ string]; }
|
| + NSRange text_range() { return NSMakeRange(0, [string_ length]); }
|
| + id<TextFrame> text_frame() {
|
| + return static_cast<id<TextFrame>>(text_frame_.get());
|
| + }
|
| +
|
| + void SetText(NSString* text) {
|
| + DCHECK(text.length);
|
| + [[string_ mutableString] setString:text];
|
| + }
|
| +
|
| + void FrameTextInBounds(CGRect bounds) {
|
| + base::scoped_nsobject<ManualTextFramer> manual_framer(
|
| + [[ManualTextFramer alloc] initWithString:string_ inBounds:bounds]);
|
| + [manual_framer frameText];
|
| + id frame = [manual_framer textFrame];
|
| + text_frame_.reset([frame retain]);
|
| + }
|
| +
|
| + UIFont* RobotoFontWithSize(CGFloat size) {
|
| + return [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:size];
|
| + }
|
| +
|
| + NSParagraphStyle* CreateParagraphStyle(CGFloat line_height,
|
| + NSTextAlignment alignment,
|
| + NSLineBreakMode line_break_mode) {
|
| + NSMutableParagraphStyle* style =
|
| + [[[NSMutableParagraphStyle alloc] init] autorelease];
|
| + style.alignment = alignment;
|
| + style.lineBreakMode = line_break_mode;
|
| + style.minimumLineHeight = line_height;
|
| + style.maximumLineHeight = line_height;
|
| + return style;
|
| + }
|
| +
|
| + NSMutableDictionary* attributes() { return attributes_; }
|
| +
|
| + void ApplyAttributesForRange(NSRange range) {
|
| + [string_ setAttributes:attributes_ range:range];
|
| + }
|
| +
|
| + void CheckForLineCountAndFramedRange(NSUInteger line_count,
|
| + NSRange framed_range) {
|
| + EXPECT_EQ(line_count, text_frame().lines.count);
|
| + EXPECT_EQ(framed_range.location, text_frame().framedRange.location);
|
| + EXPECT_EQ(framed_range.length, text_frame().framedRange.length);
|
| + }
|
| +
|
| + base::scoped_nsobject<NSMutableDictionary> attributes_;
|
| + base::scoped_nsobject<NSMutableAttributedString> string_;
|
| + base::scoped_nsprotocol<id<TextFrame>> text_frame_;
|
| +};
|
| +
|
| +// Tests that newline characters cause an attributed string to be laid out on
|
| +// multiple lines.
|
| +TEST_F(ManualTextFramerTest, NewlineTest) {
|
| + SetText(@"line one\nline two\nline three");
|
| + attributes()[NSFontAttributeName] = RobotoFontWithSize(14.0);
|
| + attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
|
| + 20.0, NSTextAlignmentNatural, NSLineBreakByWordWrapping);
|
| + ApplyAttributesForRange(text_range());
|
| + CGRect bounds = CGRectMake(0, 0, 500, 500);
|
| + FrameTextInBounds(bounds);
|
| + CheckForLineCountAndFramedRange(3, text_range());
|
| +}
|
| +
|
| +// Tests that strings with no spaces fail correctly.
|
| +TEST_F(ManualTextFramerTest, NoSpacesText) {
|
| + // "St. Mary's church in the hollow of the white hazel near the the rapid
|
| + // whirlpool of Llantysilio of the red cave."
|
| + SetText(
|
| + @"Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch");
|
| + attributes()[NSFontAttributeName] = RobotoFontWithSize(16.0);
|
| + attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
|
| + 20.0, NSTextAlignmentNatural, NSLineBreakByWordWrapping);
|
| + ApplyAttributesForRange(text_range());
|
| + CGRect bounds = CGRectMake(0, 0, 200, 60);
|
| + FrameTextInBounds(bounds);
|
| + CheckForLineCountAndFramedRange(0, NSMakeRange(0, 0));
|
| +}
|
| +
|
| +// Tests that multiple newlines are accounted for. Only the first three
|
| +// newlines should be added to |lines_|.
|
| +TEST_F(ManualTextFramerTest, MultipleNewlineTest) {
|
| + SetText(@"\n\n\ntext");
|
| + attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
|
| + 20.0, NSTextAlignmentNatural, NSLineBreakByWordWrapping);
|
| + ApplyAttributesForRange(text_range());
|
| + CGRect bounds = CGRectMake(0, 0, 500, 60);
|
| + FrameTextInBounds(bounds);
|
| + CheckForLineCountAndFramedRange(3, NSMakeRange(0, 3));
|
| +}
|
| +
|
| +// Tests that the framed range for text that will be rendered with ligatures is
|
| +// corresponds with the actual range of the text.
|
| +TEST_F(ManualTextFramerTest, LigatureTest) {
|
| + SetText(@"fffi");
|
| + attributes()[NSFontAttributeName] = RobotoFontWithSize(14.0);
|
| + attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
|
| + 20.0, NSTextAlignmentNatural, NSLineBreakByWordWrapping);
|
| + ApplyAttributesForRange(text_range());
|
| + CGRect bounds = CGRectMake(0, 0, 500, 20);
|
| + FrameTextInBounds(bounds);
|
| + CheckForLineCountAndFramedRange(1, text_range());
|
| +}
|
| +
|
| +// Tests that ManualTextFramer correctly frames Å
|
| +TEST_F(ManualTextFramerTest, DiacriticTest) {
|
| + SetText(@"A\u030A");
|
| + attributes()[NSFontAttributeName] = RobotoFontWithSize(14.0);
|
| + attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
|
| + 20.0, NSTextAlignmentNatural, NSLineBreakByWordWrapping);
|
| + ApplyAttributesForRange(text_range());
|
| + CGRect bounds = CGRectMake(0, 0, 500, 20);
|
| + FrameTextInBounds(bounds);
|
| + CheckForLineCountAndFramedRange(1, text_range());
|
| +}
|
| +
|
| +// String text, attributes, and bounds are chosen to match the "Terms of
|
| +// Service" text in WelcomeToChromeView, as the text is not properly framed by
|
| +// CTFrameSetter. http://crbug.com/537212
|
| +TEST_F(ManualTextFramerTest, TOSTextTest) {
|
| + CGRect bounds = CGRectMake(0, 0, 300.0, 40.0);
|
| + NSString* const kTOSLinkText = @"Terms of Service";
|
| + NSString* const kTOSText =
|
| + @"By using this application, you agree to Chrome’s Terms of Service.";
|
| + SetText(kTOSText);
|
| + attributes()[NSFontAttributeName] = RobotoFontWithSize(14.0);
|
| + attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
|
| + 20.0, NSTextAlignmentCenter, NSLineBreakByTruncatingTail);
|
| + attributes()[NSForegroundColorAttributeName] = [UIColor blackColor];
|
| + ApplyAttributesForRange(text_range());
|
| + attributes()[NSForegroundColorAttributeName] = [UIColor blueColor];
|
| + ApplyAttributesForRange([kTOSText rangeOfString:kTOSLinkText]);
|
| + FrameTextInBounds(bounds);
|
| + CheckForLineCountAndFramedRange(2, text_range());
|
| +}
|
| +
|
| +// Tests that the origin of a left-aligned single line is correct.
|
| +TEST_F(ManualTextFramerTest, SimpleOriginTest) {
|
| + SetText(@"test");
|
| + UIFont* font = RobotoFontWithSize(14.0);
|
| + attributes()[NSFontAttributeName] = font;
|
| + CGFloat line_height = 20.0;
|
| + attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
|
| + line_height, NSTextAlignmentLeft, NSLineBreakByWordWrapping);
|
| + ApplyAttributesForRange(text_range());
|
| + CGRect bounds = CGRectMake(0, 0, 500, 21);
|
| + FrameTextInBounds(bounds);
|
| + CheckForLineCountAndFramedRange(1, text_range());
|
| + FramedLine* line = [text_frame().lines firstObject];
|
| + EXPECT_EQ(0, line.origin.x);
|
| + EXPECT_EQ(
|
| + AlignValueToPixel(CGRectGetHeight(bounds) - line_height - font.descender,
|
| + AlignmentFunction::FLOOR),
|
| + line.origin.y);
|
| +}
|
| +
|
| +// Tests that lines that are laid out in RTL are right aligned.
|
| +TEST_F(ManualTextFramerTest, OriginRTLTest) {
|
| + SetText(@"\u0641\u064e\u0628\u064e\u0642\u064e\u064a\u0652\u062a\u064f\u0020"
|
| + @"\u0645\u064f\u062a\u064e\u0627\u0628\u0650\u0639\u064e\u0627\u064b"
|
| + @"\u0020\u0028\u0634\u064f\u063a\u0652\u0644\u0650\u064a\u0029\u0020"
|
| + @"\u0644\u064e\u0639\u064e\u0644\u064e\u0643\u0650\u0020\u062a\u064e"
|
| + @"\u062a\u064e\u0639\u064e\u0644\u0651\u064e\u0645\u064e\u0020\u0627"
|
| + @"\u0644\u062d\u0650\u0631\u0652\u0635\u064e\u0020\u0639\u064e\u0644"
|
| + @"\u064e\u0649\u0020\u0627\u0644\u0648\u064e\u0642\u0652\u062a\u0650"
|
| + @"\u0020\u002e\u0020\u0641\u064e\u0627\u0644\u062d\u064e\u064a\u064e"
|
| + @"\u0627\u0629\u064f");
|
| + attributes()[NSFontAttributeName] = RobotoFontWithSize(14.0);
|
| + attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
|
| + 20.0, NSTextAlignmentNatural, NSLineBreakByWordWrapping);
|
| + ApplyAttributesForRange(text_range());
|
| + CGRect bounds = CGRectMake(0, 0, 100.0, 60.0);
|
| + FrameTextInBounds(bounds);
|
| + CheckForLineCountAndFramedRange(3, text_range());
|
| + for (FramedLine* line in text_frame().lines) {
|
| + CGFloat line_width =
|
| + AlignValueToPixel(core_text_util::GetTrimmedLineWidth(line.line),
|
| + AlignmentFunction::CEIL);
|
| + EXPECT_EQ(CGRectGetMaxX(bounds), line.origin.x + line_width);
|
| + }
|
| +}
|
| +
|
| +TEST_F(ManualTextFramerTest, CJKLineBreakTest) {
|
| + // Example from our strings. Framer will put “触摸搜索” on one line, and then
|
| + // fail to frame the second.
|
| + // clang-format off
|
| + SetText(@"“触摸搜索”会将所选字词和当前页面(作为上下文)一起发送给 Google 搜索。"
|
| + @"您可以在设置中停用此功能。");
|
| + // clang-format on
|
| + attributes()[NSFontAttributeName] = RobotoFontWithSize(16.0);
|
| + attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
|
| + 16 * 1.15, NSTextAlignmentNatural, NSLineBreakByWordWrapping);
|
| + ApplyAttributesForRange(text_range());
|
| + CGRect bounds = CGRectMake(0, 0, 300.0, 65.0);
|
| + FrameTextInBounds(bounds);
|
| + CheckForLineCountAndFramedRange(3, NSMakeRange(0, 53));
|
| +
|
| + // Example without any space-ish characters:
|
| + // clang-format off
|
| + SetText(@"会将所选字词和当前页面(作为上下文)一起发送给Google搜索。"
|
| + @"您可以在设置中停用此功能。");
|
| + // clang-format on
|
| + attributes()[NSFontAttributeName] = RobotoFontWithSize(16.0);
|
| + attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
|
| + 16 * 1.15, NSTextAlignmentNatural, NSLineBreakByWordWrapping);
|
| + ApplyAttributesForRange(text_range());
|
| + FrameTextInBounds(bounds);
|
| + CheckForLineCountAndFramedRange(2, NSMakeRange(0, 45));
|
| +}
|
| +
|
| +// Tests that paragraphs with NSTextAlignmentCenter are actually centered.
|
| +TEST_F(ManualTextFramerTest, CenterAlignedTest) {
|
| + SetText(@"xxxx\nyyy\nwww");
|
| + attributes()[NSFontAttributeName] = RobotoFontWithSize(14.0);
|
| + attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
|
| + 20.0, NSTextAlignmentCenter, NSLineBreakByWordWrapping);
|
| + ApplyAttributesForRange(text_range());
|
| + CGRect bounds = CGRectMake(0, 0, 200.0, 60.0);
|
| + FrameTextInBounds(bounds);
|
| + CheckForLineCountAndFramedRange(3, text_range());
|
| + for (FramedLine* line in text_frame().lines) {
|
| + CGFloat line_width =
|
| + AlignValueToPixel(core_text_util::GetTrimmedLineWidth(line.line),
|
| + AlignmentFunction::CEIL);
|
| + EXPECT_EQ(AlignValueToPixel(CGRectGetMidX(bounds) - 0.5 * line_width,
|
| + AlignmentFunction::FLOOR),
|
| + line.origin.x);
|
| + }
|
| +}
|
| +
|
| +// Tests that words with a large line height will not be framed if they don't
|
| +// fit in the bounding height.
|
| +TEST_F(ManualTextFramerTest, LargeLineHeightTest) {
|
| + SetText(@"the last word is very LARGE");
|
| + attributes()[NSFontAttributeName] = RobotoFontWithSize(14.0);
|
| + attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
|
| + 20.0, NSTextAlignmentCenter, NSLineBreakByWordWrapping);
|
| + ApplyAttributesForRange(text_range());
|
| + attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
|
| + 500.0, NSTextAlignmentCenter, NSLineBreakByWordWrapping);
|
| + ApplyAttributesForRange(NSMakeRange(22, 5)); // "LARGE"
|
| + CGRect bounds = CGRectMake(0, 0, 500, 20.0);
|
| + FrameTextInBounds(bounds);
|
| + CheckForLineCountAndFramedRange(1, NSMakeRange(0, 22));
|
| +}
|
| +
|
| +// Tests a preexisting error condition in which a BiDi string containing Arabic
|
| +// is correctly laid out (crbug.com/584549).
|
| +TEST_F(ManualTextFramerTest, RTLTest) {
|
| + SetText(@"\u0642\u062F\u0020\u064A\u0633\u062A\u062E\u062F\u0645\u0020\u0047"
|
| + "\u006F\u006F\u0067\u006C\u0065\u0020\u0043\u0068\u0072\u006F\u006D"
|
| + "\u0065\u0020\u062E\u062F\u0645\u0627\u062A\u0020\u0627\u0644\u0648"
|
| + "\u064A\u0628\u0020\u0644\u062A\u062D\u0633\u064A\u0646\u0020\u062A"
|
| + "\u062C\u0631\u0628\u0629\u0020\u0627\u0644\u062A\u0635\u0641\u062D"
|
| + "\u002E\u0020\u0648\u064A\u0645\u0643\u0646\u0643\u0020\u0628\u0634"
|
| + "\u0643\u0644\u0020\u0627\u062E\u062A\u064A\u0627\u0631\u064A\u0020"
|
| + "\u062A\u0639\u0637\u064A\u0644\u0020\u0647\u0630\u0647\u0020\u0627"
|
| + "\u0644\u062E\u062F\u0645\u0627\u062A\u002E");
|
| + attributes()[NSFontAttributeName] = [UIFont systemFontOfSize:20.0];
|
| + ApplyAttributesForRange(text_range());
|
| + CGRect bounds = CGRectMake(0, 0, 500, 100);
|
| + FrameTextInBounds(bounds);
|
| + CheckForLineCountAndFramedRange(2, text_range());
|
| +}
|
| +
|
| +} // namespace
|
|
|