Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(124)

Unified Diff: ios/chrome/browser/ui/util/core_text_util.mm

Issue 2588733002: Upstream Chrome on iOS source code [9/11]. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ios/chrome/browser/ui/util/core_text_util.h ('k') | ios/chrome/browser/ui/util/core_text_util_unittest.mm » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ios/chrome/browser/ui/util/core_text_util.mm
diff --git a/ios/chrome/browser/ui/util/core_text_util.mm b/ios/chrome/browser/ui/util/core_text_util.mm
new file mode 100644
index 0000000000000000000000000000000000000000..7dec519b065d4acf46d45c901060b58b5b089562
--- /dev/null
+++ b/ios/chrome/browser/ui/util/core_text_util.mm
@@ -0,0 +1,226 @@
+// 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.
+
+#import "ios/chrome/browser/ui/util/core_text_util.h"
+
+#import <UIKit/UIKit.h>
+
+#include "base/i18n/rtl.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/scoped_nsobject.h"
+#import "ios/chrome/browser/ui/util/manual_text_framer.h"
+#import "ios/chrome/browser/ui/util/text_frame.h"
+#import "ios/chrome/browser/ui/util/unicode_util.h"
+
+namespace core_text_util {
+
+namespace {
+// Returns the range within |string| for which |text_frame|'s glyph information
+// is non-repeating.
+CFRange GetValidRangeForTextFrame(CTFrameRef text_frame,
+ NSAttributedString* string) {
+ DCHECK(text_frame);
+ DCHECK(string.length);
+ CFRange range = CFRangeMake(0, 0);
+ bool is_rtl =
+ GetEffectiveWritingDirection(string) == NSWritingDirectionRightToLeft;
+ for (id line_id in base::mac::CFToNSCast(CTFrameGetLines(text_frame))) {
+ CTLineRef line = static_cast<CTLineRef>(line_id);
+ NSArray* runs = base::mac::CFToNSCast(CTLineGetGlyphRuns(line));
+ NSInteger run_idx = is_rtl ? runs.count - 1 : 0;
+ while (run_idx >= 0 && run_idx < static_cast<NSInteger>(runs.count)) {
+ CTRunRef run = static_cast<CTRunRef>(runs[run_idx]);
+ CFRange run_range = CTRunGetStringRange(run);
+ if (run_range.location == range.location + range.length)
+ range.length += run_range.length;
+ else
+ break;
+ run_idx += is_rtl ? -1 : 1;
+ }
+ }
+ return range;
+}
+} // namespace
+
+base::ScopedCFTypeRef<CTFrameRef> CreateTextFrameForStringInBounds(
+ NSAttributedString* string,
+ CGRect bounds) {
+ base::ScopedCFTypeRef<CTFramesetterRef> frame_setter(
+ CTFramesetterCreateWithAttributedString(base::mac::NSToCFCast(string)));
+ DCHECK(frame_setter);
+ base::ScopedCFTypeRef<CGPathRef> path(CGPathCreateWithRect(bounds, nullptr));
+ DCHECK(path);
+ base::ScopedCFTypeRef<CTFrameRef> text_frame(
+ CTFramesetterCreateFrame(frame_setter, CFRangeMake(0, 0), path, nullptr));
+ DCHECK(text_frame);
+ return text_frame;
+}
+
+bool IsTextFrameValid(CTFrameRef text_frame,
+ ManualTextFramer* manual_framer,
+ NSAttributedString* string) {
+ DCHECK(text_frame);
+ DCHECK(manual_framer);
+ CFRange visible_range = CTFrameGetVisibleStringRange(text_frame);
+ CFRange valid_range = GetValidRangeForTextFrame(text_frame, string);
+ NSRange unsigned_visible_range;
+ // If |visible_range| has invalid values, return early.
+ if (!base::mac::CFRangeToNSRange(visible_range, &unsigned_visible_range))
+ return false;
+ NSRange manual_range = manual_framer.textFrame.framedRange;
+ return visible_range.location == valid_range.location &&
+ visible_range.length == valid_range.length &&
+ manual_range.length == unsigned_visible_range.length;
+}
+
+CGFloat GetTrimmedLineWidth(CTLineRef line) {
+ DCHECK(line);
+ return CTLineGetTypographicBounds(line, nullptr, nullptr, nullptr) -
+ CTLineGetTrailingWhitespaceWidth(line);
+}
+
+CGFloat GetRunWidthWithRange(CTRunRef run, CFRange range) {
+ DCHECK(run);
+ CFIndex glyph_count = CTRunGetGlyphCount(run);
+ if (range.location < 0 || range.location >= glyph_count ||
+ range.location + range.length > glyph_count || !range.length) {
+ return 0;
+ }
+ return CTRunGetTypographicBounds(run, range, nullptr, nullptr, nullptr);
+}
+
+CGFloat GetGlyphWidth(CTRunRef run, CFIndex glyph_idx) {
+ return GetRunWidthWithRange(run, CFRangeMake(glyph_idx, 1));
+}
+
+CFIndex GetGlyphIdxForCharInSet(CTRunRef run,
+ CFRange range,
+ NSAttributedString* string,
+ NSCharacterSet* set) {
+ DCHECK(run);
+ CFIndex glyph_count = CTRunGetGlyphCount(run);
+ DCHECK_LT(range.location, glyph_count);
+ DCHECK_LE(range.location + range.length, glyph_count);
+ DCHECK(string.length);
+ DCHECK(set);
+ BOOL isRTL =
+ GetEffectiveWritingDirection(string) == NSWritingDirectionRightToLeft;
+ CFIndex glyph_idx =
+ isRTL ? range.location + range.length - 1 : range.location;
+ CFIndex string_idx = GetStringIdxForGlyphIdx(run, glyph_idx);
+ while (![set characterIsMember:[string.string characterAtIndex:string_idx]]) {
+ glyph_idx += isRTL ? -1 : 1;
+ string_idx = GetStringIdxForGlyphIdx(run, glyph_idx);
+ if (string_idx == NSNotFound)
+ return kCFNotFound;
+ }
+ return glyph_idx;
+}
+
+NSUInteger GetStringIdxForGlyphIdx(CTRunRef run, CFIndex glyph_idx) {
+ DCHECK(run);
+ if (glyph_idx < 0 || glyph_idx >= CTRunGetGlyphCount(run))
+ return NSNotFound;
+ CFIndex string_idx;
+ CTRunGetStringIndices(run, CFRangeMake(glyph_idx, 1), &string_idx);
+ return static_cast<NSUInteger>(string_idx);
+}
+
+NSRange GetStringRangeForRun(CTRunRef run) {
+ DCHECK(run);
+ NSRange stringRange;
+ if (base::mac::CFRangeToNSRange(CTRunGetStringRange(run), &stringRange))
+ return stringRange;
+ return NSMakeRange(NSNotFound, 0);
+}
+
+void EnumerateAttributesInString(NSAttributedString* string,
+ NSRange range,
+ AttributesBlock block) {
+ DCHECK(string.length);
+ DCHECK_LT(range.location, string.length);
+ DCHECK_LE(range.location + range.length, string.length);
+ DCHECK(block);
+ NSUInteger char_idx = range.location;
+ NSRange effectiveRange = NSMakeRange(0, 0);
+ while (char_idx < range.location + range.length) {
+ NSDictionary* attributes =
+ [string attributesAtIndex:char_idx effectiveRange:&effectiveRange];
+ block(attributes);
+ char_idx += range.length;
+ }
+}
+
+CGFloat GetLineHeight(NSAttributedString* string, NSRange range) {
+ __block CGFloat line_height = 0;
+ AttributesBlock block = ^(NSDictionary* attributes) {
+ NSParagraphStyle* style = attributes[NSParagraphStyleAttributeName];
+ CGFloat run_line_height = 0;
+ UIFont* font = attributes[NSFontAttributeName];
+ if (!font)
+ font = [UIFont systemFontOfSize:[UIFont systemFontSize]];
+ DCHECK(font);
+ run_line_height = font.ascender - font.descender;
+ if (style.lineHeightMultiple > 0)
+ run_line_height *= style.lineHeightMultiple;
+ if (style.minimumLineHeight > 0)
+ run_line_height = std::max(run_line_height, style.minimumLineHeight);
+ if (style.maximumLineHeight > 0)
+ run_line_height = std::min(run_line_height, style.maximumLineHeight);
+ line_height = std::max(line_height, run_line_height);
+ };
+ EnumerateAttributesInString(string, range, block);
+ return line_height;
+}
+
+CGFloat GetLineSpacing(NSAttributedString* string, NSRange range) {
+ __block CGFloat line_spacing = 0;
+ AttributesBlock block = ^(NSDictionary* attributes) {
+ NSParagraphStyle* style = attributes[NSParagraphStyleAttributeName];
+ line_spacing = std::max(line_spacing, style.lineSpacing);
+ };
+ EnumerateAttributesInString(string, range, block);
+ return line_spacing;
+}
+
+NSTextAlignment GetEffectiveTextAlignment(NSAttributedString* string) {
+ DCHECK(string.length);
+ NSTextAlignment alignment = NSTextAlignmentLeft;
+ NSParagraphStyle* style = [string attribute:NSParagraphStyleAttributeName
+ atIndex:0
+ effectiveRange:nullptr];
+ if (style) {
+ alignment = style.alignment;
+ if (alignment == NSTextAlignmentNatural ||
+ alignment == NSTextAlignmentJustified) {
+ NSWritingDirection direction = GetEffectiveWritingDirection(string);
+ alignment = direction == NSWritingDirectionRightToLeft
+ ? NSTextAlignmentRight
+ : NSTextAlignmentLeft;
+ }
+ }
+ return alignment;
+}
+
+NSWritingDirection GetEffectiveWritingDirection(NSAttributedString* string) {
+ DCHECK(string.length);
+ // Search for unicode bidirectionality characters within |string|.
+ NSWritingDirection direction =
+ unicode_util::UnicodeWritingDirectionForString(string.string);
+ if (direction == NSWritingDirectionNatural) {
+ // If there are no characters with bidirectionality information, default to
+ // NSWritingDirectionLeftToRight.
+ direction = NSWritingDirectionLeftToRight;
+ }
+ NSParagraphStyle* style = [string attribute:NSParagraphStyleAttributeName
+ atIndex:0
+ effectiveRange:nullptr];
+ if (style && style.baseWritingDirection != NSWritingDirectionNatural) {
+ // Use the NSParagraphStyle's writing direction if specified.
+ direction = style.baseWritingDirection;
+ }
+ return direction;
+}
+
+} // namespace core_text_util
« no previous file with comments | « ios/chrome/browser/ui/util/core_text_util.h ('k') | ios/chrome/browser/ui/util/core_text_util_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698