123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- //
- // YYTextUtilities.h
- // YYKit <https://github.com/ibireme/YYKit>
- //
- // Created by ibireme on 15/4/6.
- // Copyright (c) 2015 ibireme.
- //
- // This source code is licensed under the MIT-style license found in the
- // LICENSE file in the root directory of this source tree.
- //
- #import <UIKit/UIKit.h>
- #import <CoreText/CoreText.h>
- #if __has_include(<YYKit/YYKit.h>)
- #import <YYKit/YYKitMacro.h>
- #else
- #import "YYKitMacro.h"
- #endif
- YY_EXTERN_C_BEGIN
- NS_ASSUME_NONNULL_BEGIN
- /**
- Whether the character is 'line break char':
- U+000D (\\r or CR)
- U+2028 (Unicode line separator)
- U+000A (\\n or LF)
- U+2029 (Unicode paragraph separator)
-
- @param c A character
- @return YES or NO.
- */
- static inline BOOL YYTextIsLinebreakChar(unichar c) {
- switch (c) {
- case 0x000D:
- case 0x2028:
- case 0x000A:
- case 0x2029:
- return YES;
- default:
- return NO;
- }
- }
- /**
- Whether the string is a 'line break':
- U+000D (\\r or CR)
- U+2028 (Unicode line separator)
- U+000A (\\n or LF)
- U+2029 (Unicode paragraph separator)
- \\r\\n, in that order (also known as CRLF)
-
- @param str A string
- @return YES or NO.
- */
- static inline BOOL YYTextIsLinebreakString(NSString * _Nullable str) {
- if (str.length > 2 || str.length == 0) return NO;
- if (str.length == 1) {
- unichar c = [str characterAtIndex:0];
- return YYTextIsLinebreakChar(c);
- } else {
- return ([str characterAtIndex:0] == '\r') && ([str characterAtIndex:1] == '\n');
- }
- }
- /**
- If the string has a 'line break' suffix, return the 'line break' length.
-
- @param str A string.
- @return The length of the tail line break: 0, 1 or 2.
- */
- static inline NSUInteger YYTextLinebreakTailLength(NSString * _Nullable str) {
- if (str.length >= 2) {
- unichar c2 = [str characterAtIndex:str.length - 1];
- if (YYTextIsLinebreakChar(c2)) {
- unichar c1 = [str characterAtIndex:str.length - 2];
- if (c1 == '\r' && c2 == '\n') return 2;
- else return 1;
- } else {
- return 0;
- }
- } else if (str.length == 1) {
- return YYTextIsLinebreakChar([str characterAtIndex:0]) ? 1 : 0;
- } else {
- return 0;
- }
- }
- /**
- Convert `UIDataDetectorTypes` to `NSTextCheckingType`.
-
- @param types The `UIDataDetectorTypes` type.
- @return The `NSTextCheckingType` type.
- */
- static inline NSTextCheckingType NSTextCheckingTypeFromUIDataDetectorType(UIDataDetectorTypes types) {
- NSTextCheckingType t = 0;
- if (types & UIDataDetectorTypePhoneNumber) t |= NSTextCheckingTypePhoneNumber;
- if (types & UIDataDetectorTypeLink) t |= NSTextCheckingTypeLink;
- if (types & UIDataDetectorTypeAddress) t |= NSTextCheckingTypeAddress;
- if (types & UIDataDetectorTypeCalendarEvent) t |= NSTextCheckingTypeDate;
- return t;
- }
- /**
- Whether the font is `AppleColorEmoji` font.
-
- @param font A font.
- @return YES: the font is Emoji, NO: the font is not Emoji.
- */
- static inline BOOL UIFontIsEmoji(UIFont *font) {
- return [font.fontName isEqualToString:@"AppleColorEmoji"];
- }
- /**
- Whether the font is `AppleColorEmoji` font.
-
- @param font A font.
- @return YES: the font is Emoji, NO: the font is not Emoji.
- */
- static inline BOOL CTFontIsEmoji(CTFontRef font) {
- BOOL isEmoji = NO;
- CFStringRef name = CTFontCopyPostScriptName(font);
- if (name && CFEqual(CFSTR("AppleColorEmoji"), name)) isEmoji = YES;
- if (name) CFRelease(name);
- return isEmoji;
- }
- /**
- Whether the font is `AppleColorEmoji` font.
-
- @param font A font.
- @return YES: the font is Emoji, NO: the font is not Emoji.
- */
- static inline BOOL CGFontIsEmoji(CGFontRef font) {
- BOOL isEmoji = NO;
- CFStringRef name = CGFontCopyPostScriptName(font);
- if (name && CFEqual(CFSTR("AppleColorEmoji"), name)) isEmoji = YES;
- if (name) CFRelease(name);
- return isEmoji;
- }
- /**
- Whether the font contains color bitmap glyphs.
-
- @discussion Only `AppleColorEmoji` contains color bitmap glyphs in iOS system fonts.
- @param font A font.
- @return YES: the font contains color bitmap glyphs, NO: the font has no color bitmap glyph.
- */
- static inline BOOL CTFontContainsColorBitmapGlyphs(CTFontRef font) {
- return (CTFontGetSymbolicTraits(font) & kCTFontTraitColorGlyphs) != 0;
- }
- /**
- Whether the glyph is bitmap.
-
- @param font The glyph's font.
- @param glyph The glyph which is created from the specified font.
- @return YES: the glyph is bitmap, NO: the glyph is vector.
- */
- static inline BOOL CGGlyphIsBitmap(CTFontRef font, CGGlyph glyph) {
- if (!font && !glyph) return NO;
- if (!CTFontContainsColorBitmapGlyphs(font)) return NO;
- CGPathRef path = CTFontCreatePathForGlyph(font, glyph, NULL);
- if (path) {
- CFRelease(path);
- return NO;
- }
- return YES;
- }
- /**
- Get the `AppleColorEmoji` font's ascent with a specified font size.
- It may used to create custom emoji.
-
- @param fontSize The specified font size.
- @return The font ascent.
- */
- static inline CGFloat YYEmojiGetAscentWithFontSize(CGFloat fontSize) {
- if (fontSize < 16) {
- return 1.25 * fontSize;
- } else if (16 <= fontSize && fontSize <= 24) {
- return 0.5 * fontSize + 12;
- } else {
- return fontSize;
- }
- }
- /**
- Get the `AppleColorEmoji` font's descent with a specified font size.
- It may used to create custom emoji.
-
- @param fontSize The specified font size.
- @return The font descent.
- */
- static inline CGFloat YYEmojiGetDescentWithFontSize(CGFloat fontSize) {
- if (fontSize < 16) {
- return 0.390625 * fontSize;
- } else if (16 <= fontSize && fontSize <= 24) {
- return 0.15625 * fontSize + 3.75;
- } else {
- return 0.3125 * fontSize;
- }
- return 0;
- }
- /**
- Get the `AppleColorEmoji` font's glyph bounding rect with a specified font size.
- It may used to create custom emoji.
-
- @param fontSize The specified font size.
- @return The font glyph bounding rect.
- */
- static inline CGRect YYEmojiGetGlyphBoundingRectWithFontSize(CGFloat fontSize) {
- CGRect rect;
- rect.origin.x = 0.75;
- rect.size.width = rect.size.height = YYEmojiGetAscentWithFontSize(fontSize);
- if (fontSize < 16) {
- rect.origin.y = -0.2525 * fontSize;
- } else if (16 <= fontSize && fontSize <= 24) {
- rect.origin.y = 0.1225 * fontSize -6;
- } else {
- rect.origin.y = -0.1275 * fontSize;
- }
- return rect;
- }
- /**
- Convert a UTF-32 character (equal or larger than 0x10000) to two UTF-16 surrogate pair.
-
- @param char32 Input: a UTF-32 character (equal or larger than 0x10000, not in BMP)
- @param char16 Output: two UTF-16 characters.
- */
- static inline void UTF32CharToUTF16SurrogatePair(UTF32Char char32, UTF16Char char16[_Nonnull 2]) {
- char32 -= 0x10000;
- char16[0] = (char32 >> 10) + 0xD800;
- char16[1] = (char32 & 0x3FF) + 0xDC00;
- }
- /**
- Convert UTF-16 surrogate pair to a UTF-32 character.
-
- @param char16 Two UTF-16 characters.
- @return A single UTF-32 character.
- */
- static inline UTF32Char UTF16SurrogatePairToUTF32Char(UTF16Char char16[_Nonnull 2]) {
- return ((char16[0] - 0xD800) << 10) + (char16[1] - 0xDC00) + 0x10000;
- }
- /**
- Get the character set which should rotate in vertical form.
- @return The shared character set.
- */
- NSCharacterSet *YYTextVerticalFormRotateCharacterSet();
- /**
- Get the character set which should rotate and move in vertical form.
- @return The shared character set.
- */
- NSCharacterSet *YYTextVerticalFormRotateAndMoveCharacterSet();
- NS_ASSUME_NONNULL_END
- YY_EXTERN_C_END
|