├── .gitattributes ├── .gitignore ├── .gitmodules ├── .travis.yml ├── AppledocSettings.plist ├── Core ├── DTCoreText-Info.plist ├── DTCoreText-Prefix.pch ├── Source │ ├── CTLineUtils.h │ ├── CTLineUtils.m │ ├── DTAccessibilityElement.h │ ├── DTAccessibilityElement.m │ ├── DTAccessibilityViewProxy.h │ ├── DTAccessibilityViewProxy.m │ ├── DTAnchorHTMLElement.h │ ├── DTAnchorHTMLElement.m │ ├── DTAttributedLabel.h │ ├── DTAttributedLabel.m │ ├── DTAttributedTextCell.h │ ├── DTAttributedTextCell.m │ ├── DTAttributedTextContentView.h │ ├── DTAttributedTextContentView.m │ ├── DTAttributedTextView.h │ ├── DTAttributedTextView.m │ ├── DTBreakHTMLElement.h │ ├── DTBreakHTMLElement.m │ ├── DTCSSListStyle.h │ ├── DTCSSListStyle.m │ ├── DTCSSStylesheet.h │ ├── DTCSSStylesheet.m │ ├── DTColor+Compatibility.h │ ├── DTColor+Compatibility.m │ ├── DTColorFunctions.h │ ├── DTColorFunctions.m │ ├── DTCompatibility.h │ ├── DTCoreText.h │ ├── DTCoreTextConstants.h │ ├── DTCoreTextConstants.m │ ├── DTCoreTextFontCollection.h │ ├── DTCoreTextFontCollection.m │ ├── DTCoreTextFontDescriptor.h │ ├── DTCoreTextFontDescriptor.m │ ├── DTCoreTextFunctions.h │ ├── DTCoreTextFunctions.m │ ├── DTCoreTextGlyphRun.h │ ├── DTCoreTextGlyphRun.m │ ├── DTCoreTextLayoutFrame+Cursor.h │ ├── DTCoreTextLayoutFrame+Cursor.m │ ├── DTCoreTextLayoutFrame.h │ ├── DTCoreTextLayoutFrame.m │ ├── DTCoreTextLayoutFrameAccessibilityElementGenerator.h │ ├── DTCoreTextLayoutFrameAccessibilityElementGenerator.m │ ├── DTCoreTextLayoutLine.h │ ├── DTCoreTextLayoutLine.m │ ├── DTCoreTextLayouter.h │ ├── DTCoreTextLayouter.m │ ├── DTCoreTextMacros.h │ ├── DTCoreTextParagraphStyle.h │ ├── DTCoreTextParagraphStyle.m │ ├── DTDictationPlaceholderTextAttachment.h │ ├── DTDictationPlaceholderTextAttachment.m │ ├── DTDictationPlaceholderView.h │ ├── DTDictationPlaceholderView.m │ ├── DTHTMLAttributedStringBuilder.h │ ├── DTHTMLAttributedStringBuilder.m │ ├── DTHTMLElement.h │ ├── DTHTMLElement.m │ ├── DTHTMLParserNode.h │ ├── DTHTMLParserNode.m │ ├── DTHTMLParserTextNode.h │ ├── DTHTMLParserTextNode.m │ ├── DTHTMLWriter.h │ ├── DTHTMLWriter.m │ ├── DTHorizontalRuleHTMLElement.h │ ├── DTHorizontalRuleHTMLElement.m │ ├── DTIframeTextAttachment.h │ ├── DTIframeTextAttachment.m │ ├── DTImage+HTML.h │ ├── DTImage+HTML.m │ ├── DTImageTextAttachment.h │ ├── DTImageTextAttachment.m │ ├── DTLazyImageView.h │ ├── DTLazyImageView.m │ ├── DTLinkButton.h │ ├── DTLinkButton.m │ ├── DTListItemHTMLElement.h │ ├── DTListItemHTMLElement.m │ ├── DTObjectTextAttachment.h │ ├── DTObjectTextAttachment.m │ ├── DTStylesheetHTMLElement.h │ ├── DTStylesheetHTMLElement.m │ ├── DTTextAttachment.h │ ├── DTTextAttachment.m │ ├── DTTextAttachmentHTMLElement.h │ ├── DTTextAttachmentHTMLElement.m │ ├── DTTextBlock.h │ ├── DTTextBlock.m │ ├── DTTextHTMLElement.h │ ├── DTTextHTMLElement.m │ ├── DTVideoTextAttachment.h │ ├── DTVideoTextAttachment.m │ ├── DTWeakSupport.h │ ├── NSAttributedString+DTCoreText.h │ ├── NSAttributedString+DTCoreText.m │ ├── NSAttributedString+DTDebug.h │ ├── NSAttributedString+DTDebug.m │ ├── NSAttributedString+HTML.h │ ├── NSAttributedString+HTML.m │ ├── NSAttributedString+SmallCaps.h │ ├── NSAttributedString+SmallCaps.m │ ├── NSAttributedStringRunDelegates.h │ ├── NSAttributedStringRunDelegates.m │ ├── NSCharacterSet+HTML.h │ ├── NSCharacterSet+HTML.m │ ├── NSCoder+DTCompatibility.h │ ├── NSCoder+DTCompatibility.m │ ├── NSDictionary+DTCoreText.h │ ├── NSDictionary+DTCoreText.m │ ├── NSMutableAttributedString+HTML.h │ ├── NSMutableAttributedString+HTML.m │ ├── NSMutableString+HTML.h │ ├── NSMutableString+HTML.m │ ├── NSNumber+RomanNumerals.h │ ├── NSNumber+RomanNumerals.m │ ├── NSScanner+HTML.h │ ├── NSScanner+HTML.m │ ├── NSString+CSS.h │ ├── NSString+CSS.m │ ├── NSString+HTML.h │ ├── NSString+HTML.m │ ├── NSString+Paragraphs.h │ ├── NSString+Paragraphs.m │ ├── UIFont+DTCoreText.h │ ├── UIFont+DTCoreText.m │ └── default.css └── include │ └── DTCoreText │ ├── CTLineUtils.h │ ├── DTAccessibilityElement.h │ ├── DTAccessibilityViewProxy.h │ ├── DTAnchorHTMLElement.h │ ├── DTAttributedLabel.h │ ├── DTAttributedTextCell.h │ ├── DTAttributedTextContentView.h │ ├── DTAttributedTextView.h │ ├── DTBreakHTMLElement.h │ ├── DTCSSListStyle.h │ ├── DTCSSStylesheet.h │ ├── DTColor+Compatibility.h │ ├── DTColorFunctions.h │ ├── DTCompatibility.h │ ├── DTCoreTextConstants.h │ ├── DTCoreTextFontCollection.h │ ├── DTCoreTextFontDescriptor.h │ ├── DTCoreTextFunctions.h │ ├── DTCoreTextGlyphRun.h │ ├── DTCoreTextLayoutFrame+Cursor.h │ ├── DTCoreTextLayoutFrame.h │ ├── DTCoreTextLayoutFrameAccessibilityElementGenerator.h │ ├── DTCoreTextLayoutLine.h │ ├── DTCoreTextLayouter.h │ ├── DTCoreTextMacros.h │ ├── DTCoreTextParagraphStyle.h │ ├── DTDictationPlaceholderTextAttachment.h │ ├── DTDictationPlaceholderView.h │ ├── DTHTMLAttributedStringBuilder.h │ ├── DTHTMLElement.h │ ├── DTHTMLParserNode.h │ ├── DTHTMLParserTextNode.h │ ├── DTHTMLWriter.h │ ├── DTHorizontalRuleHTMLElement.h │ ├── DTIframeTextAttachment.h │ ├── DTImage+HTML.h │ ├── DTImageTextAttachment.h │ ├── DTLazyImageView.h │ ├── DTLinkButton.h │ ├── DTListItemHTMLElement.h │ ├── DTObjectTextAttachment.h │ ├── DTStylesheetHTMLElement.h │ ├── DTTextAttachment.h │ ├── DTTextAttachmentHTMLElement.h │ ├── DTTextBlock.h │ ├── DTTextHTMLElement.h │ ├── DTVideoTextAttachment.h │ ├── DTWeakSupport.h │ ├── NSAttributedString+DTCoreText.h │ ├── NSAttributedString+DTDebug.h │ ├── NSAttributedString+HTML.h │ ├── NSAttributedString+SmallCaps.h │ ├── NSAttributedStringRunDelegates.h │ ├── NSCharacterSet+HTML.h │ ├── NSCoder+DTCompatibility.h │ ├── NSDictionary+DTCoreText.h │ ├── NSMutableAttributedString+HTML.h │ ├── NSMutableString+HTML.h │ ├── NSNumber+RomanNumerals.h │ ├── NSScanner+HTML.h │ ├── NSString+CSS.h │ ├── NSString+HTML.h │ ├── NSString+Paragraphs.h │ └── UIFont+DTCoreText.h ├── DTCoreText.podspec ├── DTCoreText.xcodeproj ├── project.pbxproj └── xcshareddata │ └── xcschemes │ ├── DTCoreText (Mac).xcscheme │ ├── DTCoreText (iOS).xcscheme │ ├── DTCoreText (tvOS).xcscheme │ ├── DTCoreText-Package.xcscheme │ ├── DemoApp.xcscheme │ ├── Documentation.xcscheme │ └── UnitTest.xcscheme ├── Default-568h@2x.png ├── Demo ├── DemoApp-Info.plist ├── DemoApp-Prefix.pch ├── Resources │ ├── APOD.html │ ├── About.html │ ├── Alignment.html │ ├── ArabicTest.html │ ├── CoreTextIssues.html │ ├── CurrentTest.html │ ├── CustomFont.html │ ├── DTCoreTextFontOverrides.plist │ ├── EmojiTest.html │ ├── FontSizes.html │ ├── Icon.png │ ├── Icon@2x.png │ ├── Image.html │ ├── Languages.html │ ├── Launch.storyboard │ ├── LineHeight.html │ ├── ListTest.html │ ├── LoremIpsum.html │ ├── Objects.html │ ├── Oliver.jpg │ ├── Oliver@2x.jpg │ ├── README.html │ ├── Snippets.plist │ ├── Subviews.html │ ├── TextBoxes.html │ ├── Video.html │ ├── WarAndPeace.html │ ├── XB Niloofar.ttf │ ├── XB NiloofarBd.ttf │ ├── css.css │ ├── iOS6.html │ ├── icon_smile.gif │ └── styles.html └── Source │ ├── AutoLayoutDemoViewController.h │ ├── AutoLayoutDemoViewController.m │ ├── AutoLayoutDemoViewController.xib │ ├── CoreTextDemoAppDelegate.h │ ├── CoreTextDemoAppDelegate.m │ ├── DemoAboutViewController.h │ ├── DemoAboutViewController.m │ ├── DemoAboutViewController.xib │ ├── DemoSnippetsViewController.h │ ├── DemoSnippetsViewController.m │ ├── DemoTextViewController.h │ ├── DemoTextViewController.m │ ├── DemoWebVideoView.h │ ├── DemoWebVideoView.m │ └── main.m ├── Documentation ├── DTCoreText_Demo_App.png ├── DTCoreText_Linker_Flags.png ├── DTCoreText_Reference.png ├── DTCoreText_Search_Paths.png ├── Known Issues-template.markdown ├── Programming Guide-template.markdown └── Setup Guide-template.markdown ├── LICENSE ├── Package.swift ├── Readme.markdown ├── Test ├── MacUnitTest-Info.plist ├── MacUnitTest-Prefix.pch ├── Resources │ ├── AppleConverted.html │ ├── CSSCascading.html │ ├── CSSCascading.plist │ ├── CSSOOMCrash.html │ ├── CSSOOMCrash.plist │ ├── CustomFont.plist │ ├── Emoji.html │ ├── EmptyLinesAndFontAttribute.html │ ├── Empty_and_Unclosed_Paragraphs.html │ ├── KeepMeTogether.html │ ├── ListItemBulletColorAndFont.html │ ├── ListTest.plist │ ├── MalformedURL.html │ ├── NavTag.html │ ├── NavTag.plist │ ├── Oliver.jpg │ ├── Oliver@2x.jpg │ ├── PreWhitespace.html │ ├── PreWhitespace.plist │ ├── RTL.html │ ├── RetinaDataURL.html │ ├── SpaceBetweenUnderlines.html │ ├── Video.plist │ ├── WarAndPeace.plist │ └── WhitespaceFollowingImagePromotedToParagraph.html ├── Source │ ├── DTCSSListStyleTest.m │ ├── DTCSSStylesheetTest.h │ ├── DTCSSStylesheetTest.m │ ├── DTCoreTextFontDescriptorTest.m │ ├── DTCoreTextLayoutFrameTest.m │ ├── DTCoreTextParagraphStyleTest.h │ ├── DTCoreTextParagraphStyleTest.m │ ├── DTCoreTextTestCase.h │ ├── DTCoreTextTestCase.m │ ├── DTHTMLAttributedStringBuilderTest.h │ ├── DTHTMLAttributedStringBuilderTest.m │ ├── DTHTMLElementTest.h │ ├── DTHTMLElementTest.m │ ├── DTHTMLWriterTest.h │ ├── DTHTMLWriterTest.m │ ├── DTTextBlockTest.h │ ├── DTTextBlockTest.m │ ├── MacUnitTest.h │ ├── MacUnitTest.m │ ├── NSAttributedStringDTCoreTextTest.h │ ├── NSAttributedStringDTCoreTextTest.m │ ├── NSAttributedStringHTMLTest.h │ ├── NSAttributedStringHTMLTest.m │ ├── NSDictionaryDTCoreText.m │ ├── NSMutableAttributedStringHTMLTest.h │ ├── NSMutableAttributedStringHTMLTest.m │ ├── NSNumberRomanNumeralsTest.m │ ├── NSStringCSSTest.h │ ├── NSStringCSSTest.m │ ├── NSStringHTMLTest.h │ ├── NSStringHTMLTest.m │ ├── NSStringParagraphTest.h │ ├── NSStringParagraphTest.m │ ├── Resources │ ├── UIColorHTMLTest.h │ └── UIColorHTMLTest.m ├── UnitTest-Info.plist └── UnitTest-Prefix.pch ├── Tests ├── DTCoreTextTests │ ├── DTCoreTextTests.swift │ └── XCTestManifests.swift └── LinuxMain.swift ├── build.gradle └── coveralls.rb /.gitattributes: -------------------------------------------------------------------------------- 1 | Demo/* linguist-vendored 2 | Test/* linguist-vendored 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | build 3 | .build 4 | *.mode1v3 5 | *.pbxuser 6 | project.xcworkspace 7 | xcuserdata 8 | .svn 9 | .swiftpm 10 | .dependencies 11 | .derivedData -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Externals/DTFoundation"] 2 | path = Externals/DTFoundation 3 | url = https://github.com/Cocoanetics/DTFoundation.git 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | osx_image: xcode12 3 | 4 | script: 5 | - xcodebuild -project DTCoreText.xcodeproj -scheme DemoApp build -sdk iphonesimulator -arch i386 ONLY_ACTIVE_ARCH=NO | xcpretty -s 6 | - xcodebuild -project DTCoreText.xcodeproj -scheme "DTCoreText (iOS)" build test -sdk iphonesimulator | xcpretty -s 7 | - xcodebuild -project DTCoreText.xcodeproj -scheme "DTCoreText (Mac)" build | xcpretty -s 8 | -------------------------------------------------------------------------------- /AppledocSettings.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | --project-name 6 | DTCoreText 7 | --project-company 8 | Cocoanetics 9 | --project-version 10 | 1.6 11 | --company-id 12 | com.cocoanetics 13 | --docset-atom-filename 14 | DTCoreText.atom 15 | --docset-feed-url 16 | https://docs.cocoanetics.com/DTCoreText/%DOCSETATOMFILENAME 17 | --docset-package-url 18 | https://docs.cocoanetics.com/DTCoreText/%DOCSETPACKAGEFILENAME 19 | --docset-fallback-url 20 | https://docs.cocoanetics.com/DTCoreText/ 21 | --create-docset 22 | 23 | --publish-docset 24 | 25 | --install-docset 26 | 27 | --logformat 28 | xcode 29 | --keep-intermediate-files 30 | 31 | --no-repeat-first-par 32 | 33 | --ignore 34 | 35 | *.m 36 | Externals 37 | Demo 38 | Test 39 | 40 | --index-desc 41 | Readme.markdown 42 | --include 43 | 44 | ./Documentation/Setup Guide-template.markdown 45 | ./Documentation/Known Issues-template.markdown 46 | ./Documentation/Programming Guide-template.markdown 47 | ./Documentation/DTCoreText_Demo_App.png 48 | ./Documentation/DTCoreText_Linker_Flags.png 49 | ./Documentation/DTCoreText_Search_Paths.png 50 | ./Documentation/DTCoreText_Reference.png 51 | 52 | --warn-invalid-crossref 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /Core/DTCoreText-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | FMWK 19 | CFBundleShortVersionString 20 | $(CURRENT_PROJECT_VERSION) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Core/DTCoreText-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the Static Library and Framework targets in the 'DTCoreText' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | 7 | #import 8 | #import 9 | 10 | #import 11 | 12 | #if TARGET_OS_IPHONE 13 | #import 14 | #import 15 | #elif TARGET_OS_MAC 16 | #import 17 | #endif 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /Core/Source/CTLineUtils.h: -------------------------------------------------------------------------------- 1 | // 2 | // CTLineUtils.h 3 | // DTCoreText 4 | // 5 | // Created by Oleksandr Deundiak on 7/15/15. 6 | // Copyright 2015. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | BOOL areLinesEqual(CTLineRef line1, CTLineRef line2); 12 | CFIndex getTruncationIndex(CTLineRef line, CTLineRef trunc); 13 | -------------------------------------------------------------------------------- /Core/Source/DTAccessibilityElement.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTAccessibilityElement.h 3 | // DTCoreText 4 | // 5 | // Created by Austen Green on 3/13/13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTCompatibility.h" 10 | 11 | #if TARGET_OS_IPHONE && !TARGET_OS_WATCH 12 | 13 | #import 14 | 15 | /** 16 | A UIAccessibilityElement subclass that automatically converts its local accessibilityFrame to screen coordinates. 17 | */ 18 | @interface DTAccessibilityElement : UIAccessibilityElement 19 | /** 20 | The frame for the accessibility element in terms of the receiver's superview. 21 | */ 22 | @property (nonatomic, assign) CGRect localCoordinateAccessibilityFrame; 23 | 24 | /** 25 | The point for activating accessibility events in terms of the receiver's superview. 26 | */ 27 | @property (nonatomic, assign) CGPoint localCoordinateAccessibilityActivationPoint; 28 | 29 | /** 30 | The designated initializer. This class should be initialized with a UIView as its accessibility container. 31 | @param parentView The logical superview for the onscreen element the receiver represents. 32 | @returns Returns an initialized DTAccessibilityElement */ 33 | 34 | - (id)initWithParentView:(UIView *)parentView; 35 | 36 | @end 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /Core/Source/DTAccessibilityElement.m: -------------------------------------------------------------------------------- 1 | // 2 | // DTAccessibilityElement.m 3 | // DTCoreText 4 | // 5 | // Created by Austen Green on 3/13/13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTAccessibilityElement.h" 10 | 11 | #if TARGET_OS_IPHONE && !TARGET_OS_WATCH 12 | 13 | #import 14 | 15 | static const CGPoint DTAccessibilityElementNullActivationPoint = {CGFLOAT_MAX, CGFLOAT_MAX}; 16 | 17 | @interface DTAccessibilityElement() 18 | @property (nonatomic, DT_WEAK_PROPERTY) UIView *parentView; 19 | @end 20 | 21 | @implementation DTAccessibilityElement 22 | 23 | - (id)initWithParentView:(UIView *)parentView 24 | { 25 | self = [super initWithAccessibilityContainer:parentView]; 26 | if (self) 27 | { 28 | _parentView = parentView; 29 | _localCoordinateAccessibilityActivationPoint = DTAccessibilityElementNullActivationPoint; 30 | } 31 | return self; 32 | } 33 | 34 | - (CGRect)accessibilityFrame 35 | { 36 | CGRect frame = self.localCoordinateAccessibilityFrame; 37 | frame = [self.parentView.window convertRect:frame fromView:self.parentView]; 38 | return frame; 39 | } 40 | 41 | - (CGPoint)accessibilityActivationPoint 42 | { 43 | CGPoint point = self.localCoordinateAccessibilityActivationPoint; 44 | if (CGPointEqualToPoint(point, DTAccessibilityElementNullActivationPoint)) 45 | { 46 | point = [super accessibilityActivationPoint]; 47 | } 48 | 49 | point = [self.parentView.window convertPoint:point fromView:self.parentView]; 50 | 51 | return point; 52 | } 53 | 54 | @end 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /Core/Source/DTAccessibilityViewProxy.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTAccessibilityViewProxy.h 3 | // DTCoreText 4 | // 5 | // Created by Austen Green on 5/6/13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTCompatibility.h" 10 | #import "DTAccessibilityElement.h" 11 | 12 | #if TARGET_OS_IPHONE && !TARGET_OS_WATCH 13 | 14 | #import "DTTextAttachment.h" 15 | #import 16 | 17 | @protocol DTAccessibilityViewProxyDelegate; 18 | 19 | /** 20 | UIView proxy for DTAttributedTextContentView custom subviews for text attachments. 21 | */ 22 | 23 | @interface DTAccessibilityViewProxy : NSObject 24 | /** 25 | The delegate for the proxy 26 | */ 27 | @property (nonatomic, DT_WEAK_PROPERTY, readonly) id delegate; 28 | 29 | /** 30 | The text attachment represented by the proxy 31 | */ 32 | @property (nonatomic, strong, readonly) DTTextAttachment *textAttachment; 33 | 34 | /** 35 | Creates a text attachment proxy for use with the VoiceOver system. 36 | @param textAttachment The that will be represented by a view. 37 | @param delegate An object conforming to that will provide a view when needed by the proxy. 38 | @returns A new proxy object 39 | */ 40 | 41 | - (id)initWithTextAttachment:(DTTextAttachment *)textAttachment delegate:(id)delegate; 42 | 43 | @end 44 | 45 | /** 46 | Protocol to provide custom views for accessibility elements representing a DTTextAttachment. 47 | */ 48 | @protocol DTAccessibilityViewProxyDelegate 49 | @required 50 | /** 51 | Provides a view for an attachment, e.g. an imageView for images 52 | 53 | @param attachment The that the requested view should represent 54 | @param proxy The frame that the view should use to fit on top of the space reserved for the attachment. 55 | @returns The sender requesting the view. 56 | */ 57 | 58 | - (UIView *)viewForTextAttachment:(DTTextAttachment *)attachment proxy:(DTAccessibilityViewProxy *)proxy; 59 | @end 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /Core/Source/DTAccessibilityViewProxy.m: -------------------------------------------------------------------------------- 1 | // 2 | // DTAccessibilityViewProxy.m 3 | // DTCoreText 4 | // 5 | // Created by Austen Green on 5/6/13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTAccessibilityViewProxy.h" 10 | 11 | #if TARGET_OS_IPHONE && !TARGET_OS_WATCH 12 | 13 | @implementation DTAccessibilityViewProxy 14 | 15 | - (id)initWithTextAttachment:(DTTextAttachment *)textAttachment delegate:(id)delegate 16 | { 17 | _textAttachment = textAttachment; 18 | _delegate = delegate; 19 | return self; 20 | } 21 | 22 | - (UIView *)proxiedView 23 | { 24 | return [self.delegate viewForTextAttachment:self.textAttachment proxy:self]; 25 | } 26 | 27 | - (Class)class 28 | { 29 | Class aClass = [[self proxiedView] class]; 30 | 31 | if (!aClass) 32 | aClass = [DTAccessibilityViewProxy class]; 33 | 34 | return aClass; 35 | } 36 | 37 | - (NSMethodSignature *)methodSignatureForSelector:(SEL)sel 38 | { 39 | NSMethodSignature *signature = [UIView instanceMethodSignatureForSelector:sel]; 40 | 41 | return signature; 42 | } 43 | 44 | - (void)forwardInvocation:(NSInvocation *)invocation 45 | { 46 | UIView *view = [self proxiedView]; 47 | [invocation invokeWithTarget:view]; 48 | } 49 | 50 | - (BOOL)isEqual:(id)object 51 | { 52 | return [[self proxiedView] isEqual:object]; 53 | } 54 | 55 | - (NSUInteger)hash 56 | { 57 | return [[self proxiedView] hash]; 58 | } 59 | 60 | @end 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /Core/Source/DTAnchorHTMLElement.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTHTMLElementA.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 21.03.13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTHTMLElement.h" 10 | 11 | /** 12 | Specialized subclass of that represents a hyperlink. 13 | */ 14 | @interface DTAnchorHTMLElement : DTHTMLElement 15 | 16 | /** 17 | Foreground text color of the receiver when highlighted 18 | */ 19 | @property (nonatomic, strong) DTColor *highlightedTextColor; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /Core/Source/DTAnchorHTMLElement.m: -------------------------------------------------------------------------------- 1 | // 2 | // DTHTMLElementA.m 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 21.03.13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTCompatibility.h" 10 | #import "DTAnchorHTMLElement.h" 11 | #import "DTColorFunctions.h" 12 | 13 | @implementation DTAnchorHTMLElement 14 | { 15 | DTColor *_highlightedTextColor; 16 | } 17 | 18 | - (void)applyStyleDictionary:(NSDictionary *)styles 19 | { 20 | [super applyStyleDictionary:styles]; 21 | 22 | // get highlight color from a:active pseudo-selector 23 | NSString *activeColor = [styles objectForKey:@"active:color"]; 24 | 25 | if (activeColor) 26 | { 27 | self.highlightedTextColor = DTColorCreateWithHTMLName(activeColor); 28 | } 29 | } 30 | 31 | - (NSAttributedString *)attributedString 32 | { 33 | // super returns a mutable attributed string 34 | NSMutableAttributedString *mutableAttributedString = (NSMutableAttributedString *)[super attributedString]; 35 | 36 | if (_highlightedTextColor) 37 | { 38 | NSRange range = NSMakeRange(0, [mutableAttributedString length]); 39 | 40 | // this additional attribute keeps the highlight color 41 | [mutableAttributedString addAttribute:DTLinkHighlightColorAttribute value:(id)_highlightedTextColor range:range]; 42 | 43 | // we need to set the text color via the graphics context 44 | [mutableAttributedString addAttribute:(id)kCTForegroundColorFromContextAttributeName value:[NSNumber numberWithBool:YES] range:range]; 45 | } 46 | 47 | return mutableAttributedString; 48 | } 49 | 50 | #pragma mark - Properties 51 | 52 | @synthesize highlightedTextColor = _highlightedTextColor; 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /Core/Source/DTAttributedLabel.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTAttributedLabel.h 3 | // DTCoreText 4 | // 5 | // Created by Brian Kenny on 1/17/13. 6 | // Copyright (c) 2013 Cocoanetics.com. All rights reserved. 7 | // 8 | 9 | #import "DTCompatibility.h" 10 | 11 | #if TARGET_OS_IPHONE && !TARGET_OS_WATCH 12 | 13 | #import "DTAttributedTextContentView.h" 14 | 15 | /** 16 | A Rich Text replacement for `UILabel`. It inherits from and as such you can also set the delegate to provide custom subviews i.e. for images or hyperlinks. 17 | 18 | Contrary to DTAttributedTextContentView the intrinsicContentSize is only as wide as the text content. To shrink the DTAttributedLabel to that call -sizeToFit. 19 | */ 20 | 21 | @interface DTAttributedLabel : DTAttributedTextContentView 22 | 23 | /** 24 | @name Setting Attributes 25 | */ 26 | 27 | /** 28 | The number of lines to display in the receiver 29 | */ 30 | @property(nonatomic, assign) NSInteger numberOfLines; 31 | 32 | /** 33 | The line break mode of the receiver 34 | */ 35 | @property(nonatomic, assign) NSLineBreakMode lineBreakMode; 36 | 37 | /** 38 | The string to append to the visible string in case a truncation occurs 39 | */ 40 | @property(nonatomic, strong) NSAttributedString *truncationString; 41 | 42 | @end 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /Core/Source/DTAttributedLabel.m: -------------------------------------------------------------------------------- 1 | // 2 | // DTAttributedLabel.m 3 | // DTCoreText 4 | // 5 | // Created by Brian Kenny on 1/17/13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTAttributedLabel.h" 10 | 11 | #if TARGET_OS_IPHONE && !TARGET_OS_WATCH 12 | 13 | #import "DTCoreTextLayoutFrame.h" 14 | #import 15 | 16 | @implementation DTAttributedLabel 17 | 18 | + (Class)layerClass 19 | { 20 | // most likely the label will be less than a screen size and so we don't want any tiling behavior 21 | return [CALayer class]; 22 | } 23 | 24 | - (void) setupAttributedLabel 25 | { 26 | // we want to relayout the text if height or width change 27 | self.relayoutMask = DTAttributedTextContentViewRelayoutOnHeightChanged | DTAttributedTextContentViewRelayoutOnWidthChanged; 28 | 29 | self.layoutFrameHeightIsConstrainedByBounds = YES; // height is not flexible 30 | } 31 | 32 | - (id)initWithFrame:(CGRect)frame 33 | { 34 | self = [super initWithFrame:frame]; 35 | 36 | if (self) 37 | { 38 | [self setupAttributedLabel]; 39 | } 40 | 41 | return self; 42 | } 43 | 44 | - (id) initWithCoder:(NSCoder *)aDecoder { 45 | self = [super initWithCoder:aDecoder]; 46 | 47 | if (self != nil) 48 | { 49 | [self setupAttributedLabel]; 50 | } 51 | 52 | return self; 53 | } 54 | 55 | 56 | 57 | - (void) awakeFromNib 58 | { 59 | [super awakeFromNib]; 60 | [self setupAttributedLabel]; 61 | } 62 | 63 | #pragma mark - Sizing 64 | 65 | - (CGSize)intrinsicContentSize 66 | { 67 | if (!self.layoutFrame) // creates new layout frame if possible 68 | { 69 | return CGSizeMake(-1, -1); // UIViewNoIntrinsicMetric as of iOS 6 70 | } 71 | 72 | // we have a layout frame and from this we get the needed size 73 | CGSize intrisicContentSize = [_layoutFrame intrinsicContentFrame].size; 74 | return CGSizeMake(intrisicContentSize.width + _edgeInsets.left + _edgeInsets.right, 75 | intrisicContentSize.height + _edgeInsets.top + _edgeInsets.bottom); 76 | } 77 | 78 | #pragma mark - Properties 79 | 80 | - (NSInteger)numberOfLines 81 | { 82 | return _numberOfLines; 83 | } 84 | 85 | - (void)setNumberOfLines:(NSInteger)numberOfLines 86 | { 87 | if (numberOfLines != _numberOfLines) 88 | { 89 | _numberOfLines = numberOfLines; 90 | [self relayoutText]; 91 | } 92 | } 93 | 94 | - (NSLineBreakMode)lineBreakMode 95 | { 96 | return _lineBreakMode; 97 | } 98 | 99 | - (void)setLineBreakMode:(NSLineBreakMode)lineBreakMode 100 | { 101 | if (lineBreakMode != _lineBreakMode) 102 | { 103 | _lineBreakMode = lineBreakMode; 104 | [self relayoutText]; 105 | } 106 | } 107 | 108 | - (NSAttributedString*)truncationString 109 | { 110 | return _truncationString; 111 | } 112 | 113 | - (void)setTruncationString:(NSAttributedString *)truncationString 114 | { 115 | if (![truncationString isEqualToAttributedString:_truncationString]) 116 | { 117 | _truncationString = truncationString; 118 | [self relayoutText]; 119 | } 120 | } 121 | 122 | 123 | @end 124 | 125 | #endif 126 | -------------------------------------------------------------------------------- /Core/Source/DTAttributedTextCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTAttributedTextCell.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 8/4/11. 6 | // Copyright 2011 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTCompatibility.h" 10 | 11 | #if TARGET_OS_IPHONE && !TARGET_OS_WATCH 12 | 13 | #import 14 | 15 | #import "DTAttributedTextContentView.h" 16 | #import 17 | 18 | /** 19 | This class represents a tableview cell that contains an attributed text as its content. 20 | */ 21 | @interface DTAttributedTextCell : UITableViewCell 22 | 23 | /** 24 | @name Creating Cells 25 | */ 26 | 27 | /** 28 | Creates a tableview cell with a given reuse identifier. 29 | @param reuseIdentifier The reuse identifier to use for the cell 30 | @returns A prepared cell 31 | */ 32 | - (id)initWithReuseIdentifier:(NSString *)reuseIdentifier; 33 | 34 | /** 35 | @name Setting Attributed Content 36 | */ 37 | 38 | /** 39 | The attributed string content of the receiver 40 | */ 41 | @property (nonatomic, strong) NSAttributedString *attributedString; 42 | 43 | /** 44 | A delegate implementing DTAttributedTextContentViewDelegate to provide custom subviews for images and links. 45 | */ 46 | @property (nonatomic, DT_WEAK_PROPERTY) IBOutlet id textDelegate; 47 | 48 | /** 49 | This method allows to set HTML text directly as content of the receiver. 50 | 51 | This will be converted to an attributed string. 52 | @param html The HTML string to set as the receiver's text content 53 | */ 54 | - (void)setHTMLString:(NSString *)html; 55 | 56 | /** 57 | This method allows to set HTML text directly as content of the receiver. 58 | 59 | This will be converted to an attributed string. 60 | @param html The HTML string to set as the receiver's text content 61 | @param options The options used for rendering the HTML 62 | */ 63 | - (void) setHTMLString:(NSString *)html options:(NSDictionary*) options; 64 | 65 | 66 | /** 67 | @name Getting Information 68 | */ 69 | 70 | /** 71 | Determines the row height that is needed in a specific table view to show the entire text content. 72 | 73 | The table view is necessary because from this the method can know the style. Also the accessory type needs to be set before calling this method because this reduces the available space. 74 | @note This value is only useful for table views with variable row height. 75 | @param tableView The table view to determine the height for. 76 | */ 77 | - (CGFloat)requiredRowHeightInTableView:(UITableView *)tableView; 78 | 79 | /** 80 | Determines whether the cells built-in contentView is allowed to dictate the size available for text. If active then attributedTextContextView's height always matches the cell height. 81 | 82 | Set this to `YES` for use in fixed row height table views, leave it `NO` for flexible row height table views. 83 | */ 84 | @property (nonatomic, assign) BOOL hasFixedRowHeight; 85 | 86 | /** 87 | The attributed text content view that the receiver uses to display the attributed text content. 88 | */ 89 | @property (nonatomic, readonly) DTAttributedTextContentView *attributedTextContextView; 90 | 91 | @end 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /Core/Source/DTBreakHTMLElement.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTHTMLElementBR.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 26.12.12. 6 | // Copyright (c) 2012 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTHTMLElement.h" 10 | 11 | /** 12 | Specialized subclass of that represents a line break. 13 | */ 14 | 15 | @interface DTBreakHTMLElement : DTHTMLElement 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Core/Source/DTBreakHTMLElement.m: -------------------------------------------------------------------------------- 1 | // 2 | // DTHTMLElementBR.m 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 26.12.12. 6 | // Copyright (c) 2012 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTBreakHTMLElement.h" 10 | 11 | @implementation DTBreakHTMLElement 12 | 13 | - (NSAttributedString *)attributedString 14 | { 15 | @synchronized(self) 16 | { 17 | NSDictionary *attributes = [self attributesForAttributedStringRepresentation]; 18 | return [[NSAttributedString alloc] initWithString:UNICODE_LINE_FEED attributes:attributes]; 19 | } 20 | } 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /Core/Source/DTCSSStylesheet.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTCSSStylesheet.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 9/5/11. 6 | // Copyright (c) 2011 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class DTHTMLElement; 12 | 13 | /** 14 | This class represents a CSS style sheet used for specifying formatting for certain CSS selectors. 15 | 16 | It supports matching styles by class, by id or by tag name. Hierarchy matching is not supported yet. 17 | */ 18 | @interface DTCSSStylesheet : NSObject 19 | 20 | 21 | /** 22 | @name Creating Stylesheets 23 | */ 24 | 25 | /** 26 | Creates the default stylesheet. 27 | 28 | This stylesheet is based on the standard styles that Webkit provides for these tags. This stylesheet is loaded from default.css. 29 | */ 30 | + (DTCSSStylesheet *)defaultStyleSheet; 31 | 32 | 33 | /** 34 | Creates a stylesheet with a given style block 35 | 36 | @param css The CSS string for the style block 37 | */ 38 | - (id)initWithStyleBlock:(NSString *)css; 39 | 40 | 41 | /** 42 | @name Working with CSS Style Blocks 43 | */ 44 | 45 | 46 | /** 47 | Parses a style block string and adds the found style rules to the receiver. 48 | 49 | @param css The CSS string for the style block 50 | */ 51 | - (void)parseStyleBlock:(NSString *)css; 52 | 53 | 54 | /** 55 | Merges styles from given stylesheet into the receiver 56 | 57 | @param stylesheet the stylesheet to merge 58 | */ 59 | - (void)mergeStylesheet:(DTCSSStylesheet *)stylesheet; 60 | 61 | 62 | /** 63 | @name Accessing Style Information 64 | */ 65 | 66 | /** 67 | Returns a dictionary that contains the merged style for a given element and the applicable style rules from the receiver. 68 | 69 | @param element The HTML element. 70 | @param matchedSelectors The CSS selectors that caused a match 71 | @param ignoreInlineStyle If `YES` then the inline styles of the element will be ignored and only the receiver's styles used 72 | @returns The merged style dictionary containing only styles which selector matches the element 73 | */ 74 | - (NSDictionary *)mergedStyleDictionaryForElement:(DTHTMLElement *)element matchedSelectors:(NSSet * __autoreleasing*)matchedSelectors ignoreInlineStyle:(BOOL)ignoreInlineStyle; 75 | 76 | /** 77 | Returns a dictionary of the styles of the receiver 78 | */ 79 | - (NSDictionary *)styles; 80 | 81 | /** 82 | Returns an ordered (by declaration) set of the selectors for all of the styles. 83 | */ 84 | - (NSArray *)orderedSelectors; 85 | 86 | @end 87 | -------------------------------------------------------------------------------- /Core/Source/DTColor+Compatibility.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTColor+Compatibility.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 1/9/11. 6 | // Copyright 2011 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTCompatibility.h" 10 | 11 | #if TARGET_OS_IPHONE 12 | 13 | #import 14 | 15 | /** 16 | Implementations of methods on NSColor/UIColor which are missing on the other platform. 17 | */ 18 | @interface UIColor (HTML) 19 | 20 | 21 | /** 22 | A quick method to return the alpha component of this UIColor by using the CGColorGetAlpha method. 23 | @returns The floating point alpha value of this UIColor. 24 | */ 25 | - (CGFloat)alphaComponent; 26 | 27 | @end 28 | 29 | #endif 30 | 31 | #if TARGET_OS_OSX 32 | #import 33 | 34 | /** 35 | Methods used to work with HTML representations of colors. 36 | */ 37 | @interface NSColor (HTML) 38 | 39 | 40 | /** 41 | Return a string hexadecimal representation of this NSColor. Splits the color into components with CGColor methods, re-maps them from percentages in the range 0-255, and returns the RGB color (alpha is stripped) in a six character string. 42 | @returns A CSS hexadecimal NSString specifying this NSColor. 43 | */ 44 | //- (NSString *)htmlHexString; 45 | 46 | #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_7 47 | /** 48 | Converts a CGColorRef into an NSColor by placing each component into an NSColor and pending on the component count to return a grayscale or rgb color. If there are not 2 (grayscale) or 4 (rgba) components the color is from an unsupported color space and nil is returned. 49 | @param cgColor The CGColorRef to convert 50 | @returns An NSColor of this CGColorRef 51 | */ 52 | + (NSColor *)colorWithCGColor:(CGColorRef)cgColor; 53 | 54 | /** 55 | Converts an NSColor into a CGColorRef. 56 | @returns A CGColorRef of this NSColor 57 | */ 58 | - (CGColorRef)CGColor DT_RETURNS_INNER_POINTER; 59 | #endif 60 | 61 | @end 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /Core/Source/DTColorFunctions.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTColorFunctions.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 9/9/13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTCompatibility.h" 10 | 11 | /** 12 | Takes a CSS color string ('333', 'F9FFF9'), determines the RGB values used, and returns a UIColor object of that color. 13 | For each part of the RGB color those numbers for that color are converted to a number using a category on NSString. Then that number is divided by the maximum value, 15 for 3 character strings and 255 for 6 character strings, making the color a percentage and within the range 0.0 and 1.0 that UIColor uses. 14 | @param hexString A CSS hexadecimal color string of length 6 or 3. 15 | @returns A UIColor object generated from the hexadecimal color string with alpha 1.0. 16 | */ 17 | DTColor *DTColorCreateWithHexString(NSString *hexString); 18 | 19 | 20 | /** 21 | Takes an English string representing a color and maps it to a numeric RGB value as declared by the HTML and CSS specifications (see http://www.w3schools.com/html/html_colornames.asp). Also accepts CSS `#` hexadecimal colors, `rgba`, and `rgb` and does the right thing returning a corresponding UIColor. 22 | If a color begins with a `#` we know that it is a hexadecimal color and send it to colorWithHexString:. If the string is an `rgba()` color declaration the comma delimited r, g, b, and a values are made into percentages and then made into a UIColor which is returned. If the string is an `rgb()` color declaration the same process happens except with an alpha of 1.0. 23 | The last case is that the color string is not a numeric declaration `#`, nor a `rgba` or `rgb` declaration so the CSS color value matching the English string is found in a lookup dictionary and then passed to colorWithHexString: which will make a UIColor out of the hexadecimal string. 24 | @param name The CSS color string that we want to map from a name into an RGB color. 25 | @returns A UIColor object representing the name parameter as numeric values declared by the HTML and CSS specifications, a `rgba()` color, or a `rgb()` color. 26 | */ 27 | DTColor *DTColorCreateWithHTMLName(NSString *name); 28 | 29 | 30 | /** 31 | Return a string hexadecimal representation of this UIColor. Splits the color into components with CGColor methods, re-maps them from percentages to the range 0-255, and depending on the number of components returns a grayscale (repeating string of two characters) or color RGB (alpha is stripped) six character string. In the event of a non-2 or non-4 component color nil is returned as it is from an unsupported color space. 32 | @returns A CSS hexadecimal NSString specifying this UIColor. 33 | */ 34 | NSString *DTHexStringFromDTColor(DTColor *color); 35 | -------------------------------------------------------------------------------- /Core/Source/DTCoreText.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | #if TARGET_OS_IPHONE 5 | #import 6 | #elif TARGET_OS_MAC 7 | #import 8 | #endif 9 | 10 | // global constants 11 | #import "DTCoreTextMacros.h" 12 | #import "DTCoreTextConstants.h" 13 | #import "DTCompatibility.h" 14 | 15 | #import "DTColor+Compatibility.h" 16 | #import "DTImage+HTML.h" 17 | 18 | // common utilities 19 | #if TARGET_OS_IPHONE 20 | #import "DTCoreTextFunctions.h" 21 | #endif 22 | 23 | #import "DTColorFunctions.h" 24 | 25 | // common classes 26 | #import "DTCSSListStyle.h" 27 | #import "DTTextBlock.h" 28 | #import "DTCSSStylesheet.h" 29 | #import "DTCoreTextFontDescriptor.h" 30 | #import "DTCoreTextParagraphStyle.h" 31 | #import "DTHTMLAttributedStringBuilder.h" 32 | #import "DTHTMLElement.h" 33 | #import "DTAnchorHTMLElement.h" 34 | #import "DTBreakHTMLElement.h" 35 | #import "DTListItemHTMLElement.h" 36 | #import "DTHorizontalRuleHTMLElement.h" 37 | #import "DTStylesheetHTMLElement.h" 38 | #import "DTTextAttachmentHTMLElement.h" 39 | #import "DTTextHTMLElement.h" 40 | #import "DTHTMLWriter.h" 41 | #import "NSCharacterSet+HTML.h" 42 | #import "NSCoder+DTCompatibility.h" 43 | #import "NSDictionary+DTCoreText.h" 44 | #import "NSAttributedString+HTML.h" 45 | #import "NSAttributedString+SmallCaps.h" 46 | #import "NSAttributedString+DTCoreText.h" 47 | #import "NSMutableAttributedString+HTML.h" 48 | #import "NSMutableString+HTML.h" 49 | #import "NSScanner+HTML.h" 50 | #import "NSString+CSS.h" 51 | #import "NSString+HTML.h" 52 | #import "NSString+Paragraphs.h" 53 | #import "NSNumber+RomanNumerals.h" 54 | 55 | // parsing classes 56 | #import "DTHTMLParserNode.h" 57 | #import "DTHTMLParserTextNode.h" 58 | 59 | // text attachment cluster 60 | #import "DTTextAttachment.h" 61 | #import "DTDictationPlaceholderTextAttachment.h" 62 | #import "DTIframeTextAttachment.h" 63 | #import "DTImageTextAttachment.h" 64 | #import "DTObjectTextAttachment.h" 65 | #import "DTVideoTextAttachment.h" 66 | 67 | #import "NSAttributedStringRunDelegates.h" 68 | 69 | #import "DTCoreTextGlyphRun.h" 70 | #import "DTCoreTextLayoutFrame.h" 71 | #import "DTCoreTextLayoutFrame+Cursor.h" 72 | #import "DTCoreTextLayoutLine.h" 73 | #import "DTCoreTextLayouter.h" 74 | 75 | // TARGET_OS_IPHONE is both tvOS and iOS 76 | #if TARGET_OS_IPHONE 77 | 78 | #import "DTLazyImageView.h" 79 | #import "DTLinkButton.h" 80 | 81 | #import "DTAttributedLabel.h" 82 | #import "DTAttributedTextCell.h" 83 | #import "DTAttributedTextContentView.h" 84 | #import "DTAttributedTextView.h" 85 | #import "DTCoreTextFontCollection.h" 86 | 87 | #import "DTDictationPlaceholderView.h" 88 | 89 | #import "UIFont+DTCoreText.h" 90 | 91 | #import "DTAccessibilityElement.h" 92 | #import "DTAccessibilityViewProxy.h" 93 | #import "DTCoreTextLayoutFrameAccessibilityElementGenerator.h" 94 | 95 | #endif 96 | 97 | -------------------------------------------------------------------------------- /Core/Source/DTCoreTextFontCollection.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTCoreTextFontCollection.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 5/23/11. 6 | // Copyright 2011 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @class DTCoreTextFontDescriptor; 13 | 14 | /** 15 | Class representing a collection of fonts 16 | */ 17 | 18 | @interface DTCoreTextFontCollection : NSObject 19 | 20 | /** 21 | @name Creating Font Collections 22 | */ 23 | 24 | /** 25 | Creates a font collection with all available fonts on the system 26 | */ 27 | + (DTCoreTextFontCollection *)availableFontsCollection; 28 | 29 | /** 30 | @name Getting Information about Font Collections 31 | */ 32 | 33 | /** 34 | The font family names that occur in the receiver's list of fonts 35 | */ 36 | - (NSArray *)fontFamilyNames; 37 | 38 | /** 39 | The font descriptors describing all fonts in the receiver's font collection 40 | */ 41 | - (NSArray *)fontDescriptors; 42 | 43 | /** 44 | @name Searching for Fonts 45 | */ 46 | 47 | /** 48 | The font descriptor describing a font in the receiver's collection that matches a given descriptor 49 | @param descriptor The font descriptor to search for 50 | @returns The first found font descriptor in the font collection 51 | */ 52 | - (DTCoreTextFontDescriptor *)matchingFontDescriptorForFontDescriptor:(DTCoreTextFontDescriptor *)descriptor; 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /Core/Source/DTCoreTextFunctions.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTCoreTextFunctions.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 21.12.12. 6 | // Copyright (c) 2012 Drobnik.com. All rights reserved. 7 | // 8 | #import 9 | 10 | #import "DTCompatibility.h" 11 | 12 | #if TARGET_OS_OSX 13 | #import 14 | #endif 15 | 16 | #import "DTCompatibility.h" 17 | 18 | #if TARGET_OS_IPHONE 19 | 20 | #import 21 | 22 | /** 23 | Creates a CTFont from a UIFont 24 | @param font The `UIFont` 25 | @returns The matching CTFont 26 | */ 27 | CTFontRef DTCTFontCreateWithUIFont(UIFont *font); 28 | #endif 29 | 30 | /** 31 | Converts an NSLineBreakMode into CoreText line truncation type 32 | */ 33 | CTLineTruncationType DTCTLineTruncationTypeFromNSLineBreakMode(NSLineBreakMode lineBreakMode); 34 | 35 | /** 36 | Rounds the passed value according to the specified content scale. 37 | 38 | With contentScale 1 the results are identical to roundf, with Retina content scale 2 the results are multiples of 0.5. 39 | */ 40 | CGFloat DTRoundWithContentScale(CGFloat value, CGFloat contentScale); 41 | 42 | /** 43 | Rounds up the passed value according to the specified content scale. 44 | 45 | With contentScale 1 the results are identical to roundf, with Retina content scale 2 the results are multiples of 0.5. 46 | */ 47 | CGFloat DTCeilWithContentScale(CGFloat value, CGFloat contentScale); 48 | 49 | /** 50 | Rounds down the passed value according to the sspecifiedcontent scale. 51 | 52 | With contentScale 1 the results are identical to roundf, with Retina content scale 2 the results are multiples of 0.5. 53 | */ 54 | CGFloat DTFloorWithContentScale(CGFloat value, CGFloat contentScale); 55 | 56 | #pragma mark - Alignment Conversion 57 | 58 | #if DTCORETEXT_SUPPORT_NS_ATTRIBUTES 59 | /** 60 | Converts from NSTextAlignment to CTTextAligment 61 | */ 62 | CTTextAlignment DTNSTextAlignmentToCTTextAlignment(NSTextAlignment nsTextAlignment); 63 | 64 | /** 65 | Converts from CTTextAlignment to NSTextAligment 66 | */ 67 | NSTextAlignment DTNSTextAlignmentFromCTTextAlignment(CTTextAlignment ctTextAlignment); 68 | #endif 69 | 70 | -------------------------------------------------------------------------------- /Core/Source/DTCoreTextLayoutFrame+Cursor.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTCoreTextLayoutFrame+Cursor.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 10.07.13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTCoreTextLayoutFrame.h" 10 | 11 | /** 12 | The **Cursor** category extends DTCoreTextLayoutFrame for working with a caret and determine the string index of touch coordinates. 13 | */ 14 | 15 | @interface DTCoreTextLayoutFrame (Cursor) 16 | 17 | /** 18 | Determines the closest string index to a point in the receiver's frame. 19 | 20 | This can be used to find the cursor position to position an input caret at. 21 | @param point The point 22 | @returns The resulting string index 23 | */ 24 | - (NSInteger)closestCursorIndexToPoint:(CGPoint)point; 25 | 26 | /** 27 | The rectangle to draw a caret for a given index 28 | @param index The string index for which to determine a cursor frame 29 | @returns The cursor rectangle 30 | */ 31 | - (CGRect)cursorRectAtIndex:(NSInteger)index; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /Core/Source/DTCoreTextLayoutFrame+Cursor.m: -------------------------------------------------------------------------------- 1 | // 2 | // DTCoreTextLayoutFrame+Cursor.m 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 10.07.13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTCoreTextLayoutFrame+Cursor.h" 10 | #import "DTCoreTextLayoutLine.h" 11 | 12 | @implementation DTCoreTextLayoutFrame (Cursor) 13 | 14 | - (NSInteger)closestCursorIndexToPoint:(CGPoint)point 15 | { 16 | NSArray *lines = self.lines; 17 | 18 | if (![lines count]) 19 | { 20 | return NSNotFound; 21 | } 22 | 23 | DTCoreTextLayoutLine *firstLine = [lines objectAtIndex:0]; 24 | if (point.y < CGRectGetMinY(firstLine.frame)) 25 | { 26 | return 0; 27 | } 28 | 29 | DTCoreTextLayoutLine *lastLine = [lines lastObject]; 30 | if (point.y > CGRectGetMaxY(lastLine.frame)) 31 | { 32 | NSRange stringRange = [self visibleStringRange]; 33 | 34 | if (stringRange.length) 35 | { 36 | return NSMaxRange([self visibleStringRange])-1; 37 | } 38 | } 39 | 40 | // find closest line 41 | DTCoreTextLayoutLine *closestLine = nil; 42 | CGFloat closestDistance = CGFLOAT_MAX; 43 | 44 | for (DTCoreTextLayoutLine *oneLine in lines) 45 | { 46 | // line contains point 47 | if (CGRectGetMinY(oneLine.frame) <= point.y && CGRectGetMaxY(oneLine.frame) >= point.y) 48 | { 49 | closestLine = oneLine; 50 | break; 51 | } 52 | 53 | CGFloat top = CGRectGetMinY(oneLine.frame); 54 | CGFloat bottom = CGRectGetMaxY(oneLine.frame); 55 | 56 | CGFloat distance = CGFLOAT_MAX; 57 | 58 | if (top > point.y) 59 | { 60 | distance = top - point.y; 61 | } 62 | else if (bottom < point.y) 63 | { 64 | distance = point.y - bottom; 65 | } 66 | 67 | if (distance < closestDistance) 68 | { 69 | closestLine = oneLine; 70 | closestDistance = distance; 71 | } 72 | } 73 | 74 | if (!closestLine) 75 | { 76 | return NSNotFound; 77 | } 78 | 79 | NSInteger closestIndex = [closestLine stringIndexForPosition:point]; 80 | 81 | NSInteger maxIndex = NSMaxRange([closestLine stringRange])-1; 82 | 83 | if (closestIndex > maxIndex) 84 | { 85 | closestIndex = maxIndex; 86 | } 87 | 88 | if (closestIndex>=0) 89 | { 90 | return closestIndex; 91 | } 92 | 93 | return NSNotFound; 94 | } 95 | 96 | - (CGRect)cursorRectAtIndex:(NSInteger)index 97 | { 98 | DTCoreTextLayoutLine *line = [self lineContainingIndex:index]; 99 | 100 | if (!line) 101 | { 102 | return CGRectZero; 103 | } 104 | 105 | CGFloat offset = [line offsetForStringIndex:index]; 106 | 107 | CGRect rect = line.frame; 108 | rect.size.width = 3.0; 109 | rect.origin.x += offset; 110 | 111 | return rect; 112 | } 113 | 114 | @end 115 | -------------------------------------------------------------------------------- /Core/Source/DTCoreTextLayoutFrameAccessibilityElementGenerator.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTCoreTextLayoutFrameAccessibilityElementGenerator.h 3 | // DTCoreText 4 | // 5 | // Created by Austen Green on 3/13/13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTCompatibility.h" 10 | 11 | #if TARGET_OS_IPHONE && !TARGET_OS_WATCH 12 | 13 | #import "DTAccessibilityElement.h" 14 | 15 | @class DTCoreTextLayoutFrame, DTTextAttachment; 16 | 17 | /** 18 | A block that provides accessibility information for the passed text attachments 19 | */ 20 | typedef id(^DTAttachmentViewProvider)(DTTextAttachment *textAttachment); 21 | 22 | /** 23 | Generates an array of objects conforming to the UIAccessibility informal protocol based on a . 24 | */ 25 | @interface DTCoreTextLayoutFrameAccessibilityElementGenerator : NSObject 26 | 27 | /** 28 | The designated initializer. The DTAttachmentViewProvider block may be used to provide custom subviews in place of a static accessibility element. 29 | @param frame The to generate accessibility elements for. 30 | @param view The logical superview of the elements - the view that owns the local coordinate system for drawing the frame. 31 | @param block A callback block which takes a object and returns an object that conforms to the UIAccessibility informal protocol. 32 | @returns Returns an array of objects conforming to the UIAccessibility informal protocol, suitable for presentation for the VoiceOver system. 33 | */ 34 | 35 | - (NSArray *)accessibilityElementsForLayoutFrame:(DTCoreTextLayoutFrame *)frame view:(UIView *)view attachmentViewProvider:(DTAttachmentViewProvider)block; 36 | 37 | @end 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /Core/Source/DTCoreTextLayouter.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTCoreTextLayouter.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 1/24/11. 6 | // Copyright 2011 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTCompatibility.h" 10 | 11 | #if TARGET_OS_IPHONE 12 | #import 13 | #elif TARGET_OS_MAC 14 | #import 15 | #endif 16 | 17 | #import "DTCoreTextLayoutFrame.h" 18 | #import "DTCoreTextLayoutLine.h" 19 | #import "DTCoreTextGlyphRun.h" 20 | 21 | /** 22 | This class owns an attributed string and is able to create layoutFrames for certain ranges in this string. Optionally it caches these layout frames. 23 | */ 24 | @interface DTCoreTextLayouter : NSObject 25 | 26 | /** 27 | @name Creating a Layouter 28 | */ 29 | 30 | /** 31 | Designated Initializer. Creates a new Layouter with an attributed string 32 | @param attributedString The `NSAttributedString` to layout for 33 | @returns An initialized layouter 34 | */ 35 | - (id)initWithAttributedString:(NSAttributedString *)attributedString; 36 | 37 | 38 | /** 39 | @name Creating Layout Frames 40 | */ 41 | 42 | /** 43 | Creates a layout frame with a given rectangle and string range. The layouter fills the layout frame with as many lines as fit. You can query [DTCoreTextLayoutFrame visibleStringRange] for the range the fits and create another layout frame that continues the text from there to create multiple pages, for example for an e-book. 44 | @param frame The rectangle to fill with text 45 | @param range The string range to fill, pass {0,0} for the entire string (as much as fits) 46 | */ 47 | - (DTCoreTextLayoutFrame *)layoutFrameWithRect:(CGRect)frame range:(NSRange)range; 48 | 49 | /** 50 | If set to `YES` then the receiver will cache layout frames generated with layoutFrameWithRect:range: for a given rect 51 | */ 52 | @property (nonatomic, assign) BOOL shouldCacheLayoutFrames; 53 | 54 | 55 | /** 56 | @name Getting Information 57 | */ 58 | 59 | /** 60 | The attributed string that the layouter currently owns 61 | */ 62 | @property (nonatomic, strong) NSAttributedString *attributedString; 63 | 64 | /** 65 | The internal framesetter of the receiver 66 | */ 67 | @property (nonatomic, readonly) CTFramesetterRef framesetter; 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /Core/Source/DTCoreTextMacros.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTCoreTextMacros.h 3 | // DTCoreText 4 | // 5 | // Created by Jean-Charles BERTIN on 5/28/14. 6 | // Copyright (c) 2014 Axinoe. All rights reserved. 7 | // 8 | 9 | #import "DTCompatibility.h" 10 | 11 | #ifndef DT_RETURNS_INNER_POINTER 12 | #if __has_attribute(objc_returns_inner_pointer) 13 | #define DT_RETURNS_INNER_POINTER __attribute__((objc_returns_inner_pointer)) 14 | #else 15 | #define DT_RETURNS_INNER_POINTER 16 | #endif 17 | #endif 18 | -------------------------------------------------------------------------------- /Core/Source/DTDictationPlaceholderTextAttachment.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTDictationPlaceholderTextAttachment.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 06.02.13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTTextAttachment.h" 10 | 11 | /** 12 | This is a special subclass of DTTextAttachment used to represent the dictation placeholder. 13 | 14 | When encountering such an element DTAttributedTextContentView does not call the delegate to provide a subclass but automatically creates and adds a DTDictationPlaceholderView. 15 | */ 16 | 17 | @interface DTDictationPlaceholderTextAttachment : DTTextAttachment 18 | 19 | /** 20 | The string that inserting the dictation placeholder replaced, used for Undoing 21 | */ 22 | @property (nonatomic, retain) NSAttributedString *replacedAttributedString; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /Core/Source/DTDictationPlaceholderTextAttachment.m: -------------------------------------------------------------------------------- 1 | // 2 | // DTDictationPlaceholderTextAttachment.m 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 06.02.13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTDictationPlaceholderTextAttachment.h" 10 | 11 | @implementation DTDictationPlaceholderTextAttachment 12 | { 13 | NSAttributedString *_replacedAttributedString; 14 | } 15 | 16 | - (instancetype)initWithCoder:(NSCoder *)aDecoder { 17 | self = [super initWithCoder:aDecoder]; 18 | if (self) { 19 | _replacedAttributedString = [aDecoder decodeObjectForKey:@"replacedAttributedString"]; 20 | } 21 | return self; 22 | } 23 | 24 | - (void)encodeWithCoder:(NSCoder *)aCoder { 25 | [super encodeWithCoder:aCoder]; 26 | [aCoder encodeObject:_replacedAttributedString forKey:@"replacedAttributedString"]; 27 | } 28 | 29 | // if you change any of these then also make sure to adjust the sizes in DTDictationPlaceholderTextAttachment 30 | #define DOT_WIDTH 10.0f 31 | #define DOT_DISTANCE 2.5f 32 | #define DOT_OUTSIDE_MARGIN 3.0f 33 | 34 | // several hard-coded items 35 | - (CGSize)displaySize 36 | { 37 | return CGSizeMake(DOT_OUTSIDE_MARGIN*2.0f + DOT_WIDTH*3.0f + DOT_DISTANCE*2.0f, DOT_OUTSIDE_MARGIN*2.0f + DOT_WIDTH); 38 | } 39 | 40 | - (CGSize)originalSize 41 | { 42 | return [self displaySize]; 43 | } 44 | 45 | - (CGFloat)ascentForLayout 46 | { 47 | return self.displaySize.height; 48 | } 49 | 50 | - (CGFloat)descentForLayout 51 | { 52 | return 0.0f; 53 | } 54 | 55 | #pragma mark - Properties 56 | 57 | @synthesize replacedAttributedString = _replacedAttributedString; 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /Core/Source/DTDictationPlaceholderView.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTDictationPlaceholderView.h 3 | // DTRichTextEditor 4 | // 5 | // Created by Oliver Drobnik on 05.02.13. 6 | // Copyright (c) 2013 Cocoanetics. All rights reserved. 7 | // 8 | 9 | #import "DTCompatibility.h" 10 | 11 | #if TARGET_OS_IPHONE && !TARGET_OS_WATCH 12 | 13 | #import 14 | 15 | /** 16 | A dictation placeholder to display in editors between the time the recording is complete until a recognized response is received. 17 | */ 18 | 19 | @interface DTDictationPlaceholderView : UIView 20 | 21 | /** 22 | Creates an appropriately sized DTDictationPlaceholderView with 3 animated purple dots 23 | */ 24 | + (DTDictationPlaceholderView *)placeholderView; 25 | 26 | /** 27 | The context of the receiver. This can be any object, for example the selection range to replace with the dictation result text 28 | */ 29 | @property (nonatomic, strong) id context; 30 | 31 | @end 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /Core/Source/DTHTMLParserNode.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTHTMLParserNode.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 26.12.12. 6 | // Copyright (c) 2012 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import 12 | 13 | @class DTHTMLParserTextNode; 14 | 15 | /** 16 | This class represents one node in an HTML DOM tree. 17 | */ 18 | @interface DTHTMLParserNode : NSObject 19 | { 20 | NSDictionary *_attributes; 21 | } 22 | 23 | /** 24 | Designated initializer 25 | @param name The element name 26 | @param attributes The attributes dictionary 27 | @returns An initialized parser node. 28 | */ 29 | - (id)initWithName:(NSString *)name attributes:(NSDictionary *)attributes; 30 | 31 | /** 32 | The name of the receiver 33 | */ 34 | @property (nonatomic, copy) NSString *name; 35 | 36 | /** 37 | The attributes of the receiver. 38 | */ 39 | @property (nonatomic, copy) NSDictionary *attributes; 40 | 41 | /** 42 | A weak link to the parent node of the receiver 43 | */ 44 | @property (nonatomic, DT_WEAK_PROPERTY) DTHTMLParserNode *parentNode; 45 | 46 | /** 47 | The child nodes of the receiver 48 | */ 49 | @property (nonatomic, readonly) NSArray *childNodes; 50 | 51 | /** 52 | Adds a child node to the receiver. 53 | @param childNode The child node to be appended to the list of children 54 | */ 55 | - (void)addChildNode:(DTHTMLParserNode *)childNode; 56 | 57 | /** 58 | Removes a child node from the receiver 59 | @param childNode The child node to remove 60 | */ 61 | - (void)removeChildNode:(DTHTMLParserNode *)childNode; 62 | 63 | /** 64 | Removes all child nodes from the receiver 65 | */ 66 | - (void)removeAllChildNodes; 67 | 68 | /** 69 | Hierarchy representation of the receiver including all attributes and children 70 | */ 71 | - (NSString *)debugDescription; 72 | 73 | /** 74 | Concatenated contents of all text nodes 75 | */ 76 | - (NSString *)text; 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /Core/Source/DTHTMLParserTextNode.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTHTMLParserTextNode.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 26.12.12. 6 | // Copyright (c) 2012 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "DTHTMLParserNode.h" 12 | 13 | /** 14 | Specialized sub class of that represents text inside a node 15 | */ 16 | @interface DTHTMLParserTextNode : DTHTMLParserNode 17 | 18 | /** 19 | Designated initializer with the characters that make up the text. 20 | @param characters The characters of the string 21 | @returns The initialized text node 22 | */ 23 | - (id)initWithCharacters:(NSString *)characters; 24 | 25 | /** 26 | Returns the receivers character contents 27 | */ 28 | @property (nonatomic, readonly) NSString *characters; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /Core/Source/DTHTMLParserTextNode.m: -------------------------------------------------------------------------------- 1 | // 2 | // DTHTMLParserTextNode.m 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 26.12.12. 6 | // Copyright (c) 2012 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTHTMLParserTextNode.h" 10 | #import "NSString+HTML.h" 11 | 12 | @implementation DTHTMLParserTextNode 13 | { 14 | NSString *_characters; 15 | } 16 | 17 | - (id)initWithCharacters:(NSString *)characters 18 | { 19 | self = [super init]; 20 | 21 | if (self) 22 | { 23 | self.name = @"#TEXT#"; 24 | 25 | _characters = characters; 26 | 27 | } 28 | return self; 29 | } 30 | 31 | #ifndef COVERAGE 32 | // exclude methods from coverage testing 33 | 34 | - (NSString *)description 35 | { 36 | return [NSString stringWithFormat:@"<%@ content='%@'>", NSStringFromClass([self class]), _characters]; 37 | } 38 | 39 | - (void)_appendHTMLToString:(NSMutableString *)string indentLevel:(NSUInteger)indentLevel 40 | { 41 | // indent to the level 42 | for (NSUInteger i=0; i 10 | #import 11 | 12 | /** 13 | Class to generate HTML from `NSAttributedString` instances. 14 | */ 15 | @interface DTHTMLWriter : NSObject 16 | 17 | /** 18 | @name Creating an HTML Writer 19 | */ 20 | 21 | /** 22 | Creates a writer with a given `NSAttributedString` as input 23 | @param attributedString An attributed string 24 | */ 25 | - (id)initWithAttributedString:(NSAttributedString *)attributedString; 26 | 27 | /** 28 | @name Generating HTML 29 | */ 30 | 31 | /** 32 | Generates a HTML representation of the attributed string 33 | @returns The generated string 34 | */ 35 | - (NSString *)HTMLString; 36 | 37 | 38 | /** 39 | Generates a HTML fragment representation of the attributed string including inlined styles and no html or head elements 40 | @returns The generated string 41 | */ 42 | - (NSString *)HTMLFragment; 43 | 44 | /** 45 | @name Properties 46 | */ 47 | 48 | /** 49 | If specified then all absolute font sizes (px) will be divided by this value. This is useful if you specified a text size multiplier when converting HTML to the attributed string you are processing. 50 | */ 51 | @property (nonatomic, assign) CGFloat textScale; 52 | 53 | /** 54 | If YES, preserve whitespaces in HTML by using "Apple-converted-space". Default YES. 55 | */ 56 | @property (nonatomic, assign) BOOL useAppleConvertedSpace; 57 | 58 | /** 59 | The attributed string that the writer is processing. 60 | */ 61 | @property (nonatomic, readonly) NSAttributedString *attributedString; 62 | 63 | 64 | /** 65 | The HTML element tag name to use for paragraphs. Defaults to @"p". 66 | */ 67 | @property (nonatomic, strong) NSString *paragraphTagName; 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /Core/Source/DTHorizontalRuleHTMLElement.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTHTMLElementHR.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 26.12.12. 6 | // Copyright (c) 2012 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTHTMLElement.h" 10 | 11 | /** 12 | Specialized subclass of that deals with list items. 13 | */ 14 | 15 | @interface DTHorizontalRuleHTMLElement : DTHTMLElement 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Core/Source/DTHorizontalRuleHTMLElement.m: -------------------------------------------------------------------------------- 1 | // 2 | // DTHTMLElementHR.m 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 26.12.12. 6 | // Copyright (c) 2012 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTHorizontalRuleHTMLElement.h" 10 | 11 | @implementation DTHorizontalRuleHTMLElement 12 | 13 | - (NSDictionary *)attributesForAttributedStringRepresentation 14 | { 15 | NSMutableDictionary *dict = [[super attributesForAttributedStringRepresentation] mutableCopy]; 16 | [dict setObject:[NSNumber numberWithBool:YES] forKey:DTHorizontalRuleStyleAttribute]; 17 | 18 | return dict; 19 | } 20 | 21 | - (NSAttributedString *)attributedString 22 | { 23 | @synchronized(self) 24 | { 25 | NSDictionary *attributes = [self attributesForAttributedStringRepresentation]; 26 | return [[NSAttributedString alloc] initWithString:@"\n" attributes:attributes]; 27 | } 28 | } 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /Core/Source/DTIframeTextAttachment.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTTextAttachmentIframe.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 22.04.13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTTextAttachment.h" 10 | 11 | /** 12 | A specialized subclass in the DTTextAttachment class cluster to represent an IFRAME 13 | */ 14 | 15 | @interface DTIframeTextAttachment : DTTextAttachment 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Core/Source/DTImage+HTML.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTImage+HTML.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 1/9/11. 6 | // Copyright 2011 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTCompatibility.h" 10 | 11 | #if TARGET_OS_IPHONE 12 | 13 | #import 14 | 15 | /** 16 | Category used to have the same method available for unit testing on Mac on iOS. 17 | */ 18 | @interface UIImage (HTML) 19 | 20 | /** 21 | Retrieve the NSData representation of a UIImage. Used to encode UIImages in DTTextAttachments. 22 | 23 | @returns The NSData representation of the UIImage instance receiving this message. Convenience method for UIImagePNGRepresentation(). 24 | */ 25 | - (NSData *)dataForPNGRepresentation; 26 | 27 | @end 28 | 29 | #endif 30 | 31 | #if TARGET_OS_OSX 32 | #import 33 | 34 | /** 35 | Category used to have the same method available for unit testing on Mac on iOS. 36 | */ 37 | @interface NSImage (HTML) 38 | 39 | 40 | /** 41 | Retrieve the NSData representation of a NSImage. 42 | 43 | @returns The NSData representation of the NSImage instance receiving this message. 44 | */ 45 | - (NSData *)dataForPNGRepresentation; 46 | 47 | @end 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /Core/Source/DTImage+HTML.m: -------------------------------------------------------------------------------- 1 | // 2 | // DTImage+HTML.m 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 31.01.12. 6 | // Copyright (c) 2012 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTImage+HTML.h" 10 | 11 | #if TARGET_OS_IPHONE 12 | 13 | @implementation UIImage (HTML) 14 | 15 | - (NSData *)dataForPNGRepresentation 16 | { 17 | return UIImagePNGRepresentation(self); 18 | } 19 | 20 | @end 21 | 22 | #endif 23 | 24 | #if TARGET_OS_OSX 25 | 26 | @implementation NSImage (HTML) 27 | 28 | - (NSData *)dataForPNGRepresentation 29 | { 30 | [self lockFocus]; 31 | NSBitmapImageRep *bitmapRep = [[NSBitmapImageRep alloc] initWithFocusedViewRect:NSMakeRect(0, 0, self.size.width, self.size.height)]; 32 | [self unlockFocus]; 33 | 34 | return [bitmapRep representationUsingType:NSPNGFileType properties:[NSDictionary new]]; 35 | } 36 | 37 | @end 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /Core/Source/DTImageTextAttachment.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTTextAttachmentImage.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 22.04.13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTCompatibility.h" 10 | #import "DTTextAttachment.h" 11 | 12 | @class DTImage; 13 | 14 | /** 15 | A specialized subclass in the DTTextAttachment class cluster to represent an embedded image 16 | */ 17 | 18 | @interface DTImageTextAttachment : DTTextAttachment 19 | 20 | /** 21 | The designated initializer which will be called by [DTTextAttachment textAttachmentWithElement:options:] for image attachments. 22 | @param element A DTHTMLElement that must have a valid tag name and should have a size. Any element attributes are copied to the text attachment's elements. 23 | @param options An NSDictionary of options. Used to specify the max image size with the key DTMaxImageSize. 24 | */ 25 | - (id)initWithElement:(DTHTMLElement *)element options:(NSDictionary *)options; 26 | 27 | /** 28 | @name Alternate Representations 29 | */ 30 | 31 | /** 32 | Retrieves a string which is in the format "data:image/png;base64,%@" with this DTTextAttachment's content's data representation encoded in Base64 string encoding. For image contents only. 33 | @returns A Base64 encoded string of the png data representation of this text attachment's image contents. 34 | */ 35 | - (NSString *)dataURLRepresentation; 36 | 37 | /** 38 | The image represented by the receiver 39 | */ 40 | @property (nonatomic, strong) DTImage *image; 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /Core/Source/DTLazyImageView.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTLazyImageView.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 5/20/11. 6 | // Copyright 2011 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTCompatibility.h" 10 | 11 | #if TARGET_OS_IPHONE && !TARGET_OS_WATCH 12 | 13 | #import 14 | #import "DTAttributedTextContentView.h" 15 | 16 | @class DTLazyImageView; 17 | 18 | // Notifications 19 | extern NSString * const DTLazyImageViewWillStartDownloadNotification; 20 | extern NSString * const DTLazyImageViewDidFinishDownloadNotification; 21 | 22 | /** 23 | Protocol for delegates of to inform them about the downloaded image dimensions. 24 | */ 25 | @protocol DTLazyImageViewDelegate 26 | @optional 27 | 28 | /** 29 | Method that informs the delegate about the image size so that it can re-layout text. 30 | @param lazyImageView The image view 31 | @param size The image size that is now known 32 | */ 33 | - (void)lazyImageView:(DTLazyImageView *)lazyImageView didChangeImageSize:(CGSize)size; 34 | @end 35 | 36 | /** 37 | This `UIImageView` subclass lazily loads an image from a URL and informs a delegate once the size of the image is known. 38 | */ 39 | 40 | @interface DTLazyImageView : UIImageView 41 | 42 | /** 43 | @name Providing Content 44 | */ 45 | 46 | /** 47 | The URL of the remote image 48 | */ 49 | @property (nonatomic, strong) NSURL *url; 50 | 51 | /** 52 | The URL Request that is to be used for downloading the image. If this is left `nil` the a new URL Request will be created 53 | */ 54 | @property (nonatomic, strong) NSMutableURLRequest *urlRequest; 55 | 56 | /** 57 | The DTAttributedTextContentView used to display remote images with DTAttributedTextCell 58 | */ 59 | @property (nonatomic, DT_WEAK_PROPERTY) DTAttributedTextContentView *contentView; 60 | 61 | /** 62 | @name Getting Information 63 | */ 64 | 65 | /** 66 | Set to `YES` to support progressive display of progressive downloads 67 | */ 68 | @property (nonatomic, assign) BOOL shouldShowProgressiveDownload; 69 | 70 | /** 71 | The delegate, conforming to , to inform when the image dimensions were determined 72 | */ 73 | @property (nonatomic, DT_WEAK_PROPERTY) id delegate; 74 | 75 | 76 | /** 77 | @name Cancelling Download 78 | */ 79 | 80 | /** 81 | Cancels the image downloading 82 | */ 83 | - (void)cancelLoading; 84 | 85 | @end 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /Core/Source/DTLinkButton.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTLinkButton.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 1/16/11. 6 | // Copyright 2011 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTCompatibility.h" 10 | 11 | #if TARGET_OS_IPHONE && !TARGET_OS_WATCH 12 | #import 13 | 14 | /** 15 | Constant for highlighting notification 16 | */ 17 | extern NSString *DTLinkButtonDidHighlightNotification; 18 | 19 | /** 20 | A button that corresponds to a hyperlink. 21 | 22 | Multiple parts of the same hyperlink synchronize their looks through the guid. You can show link text in a different color for normal and highlighted mode by setting the button images for these states. 23 | */ 24 | @interface DTLinkButton : UIButton 25 | 26 | 27 | /** 28 | The URL that this button corresponds to. 29 | */ 30 | @property (nonatomic, copy) NSURL *URL; 31 | 32 | 33 | /** 34 | The unique identifier (GUID) that all parts of the same hyperlink have in common. 35 | */ 36 | @property (nonatomic, copy) NSString *GUID; 37 | 38 | 39 | /** 40 | The minimum size that the receiver should respond on hits with. Adjusts the bounds if they are smaller than the passed size. 41 | */ 42 | @property (nonatomic, assign) CGSize minimumHitSize; 43 | 44 | 45 | /** 46 | A Boolean value that determines whether tapping the button causes it to show a gray rounded rectangle. Default is YES. 47 | */ 48 | @property(nonatomic) BOOL showsTouchWhenHighlighted; 49 | 50 | 51 | @end 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /Core/Source/DTListItemHTMLElement.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTHTMLElementLI.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 27.12.12. 6 | // Copyright (c) 2012 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTHTMLElement.h" 10 | 11 | /** 12 | Specialized subclass of that deals with list items. 13 | */ 14 | @interface DTListItemHTMLElement : DTHTMLElement 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Core/Source/DTObjectTextAttachment.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTObjectTextAttachment.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 22.04.13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTTextAttachment.h" 10 | 11 | /** 12 | A specialized subclass in the DTTextAttachment class cluster to represent an generic object 13 | */ 14 | 15 | @interface DTObjectTextAttachment : DTTextAttachment 16 | 17 | /** 18 | The DTHTMLElement child nodes of the receiver. This array is only used for object tags at the moment. 19 | */ 20 | @property (nonatomic, strong) NSArray *childNodes; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /Core/Source/DTStylesheetHTMLElement.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTHTMLElementStylesheet.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 29.12.12. 6 | // Copyright (c) 2012 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTHTMLElement.h" 10 | 11 | @class DTCSSStylesheet; 12 | 13 | /** 14 | This is a specialized subclass of representing a style block. 15 | */ 16 | @interface DTStylesheetHTMLElement : DTHTMLElement 17 | 18 | /** 19 | Parses the text children and assembles the resulting stylesheet. 20 | */ 21 | - (DTCSSStylesheet *)stylesheet; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Core/Source/DTStylesheetHTMLElement.m: -------------------------------------------------------------------------------- 1 | // 2 | // DTHTMLElementStylesheet.m 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 29.12.12. 6 | // Copyright (c) 2012 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTStylesheetHTMLElement.h" 10 | #import "DTCSSStylesheet.h" 11 | 12 | @implementation DTStylesheetHTMLElement 13 | 14 | - (NSAttributedString *)attributedString 15 | { 16 | return nil; 17 | } 18 | 19 | - (DTCSSStylesheet *)stylesheet 20 | { 21 | NSString *text = [self text]; 22 | 23 | return [[DTCSSStylesheet alloc] initWithStyleBlock:text]; 24 | } 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /Core/Source/DTTextAttachmentHTMLElement.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTHTMLElementAttachment.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 26.12.12. 6 | // Copyright (c) 2012 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTHTMLElement.h" 10 | 11 | /** 12 | Specialized subclass of for dealing with instances, e.g. images. 13 | */ 14 | 15 | @interface DTTextAttachmentHTMLElement : DTHTMLElement 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Core/Source/DTTextBlock.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTTextBlock.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 04.03.12. 6 | // Copyright (c) 2012 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTCompatibility.h" 10 | 11 | /** 12 | Class that represents a block of text with attributes like padding or a background color. 13 | */ 14 | @interface DTTextBlock : NSObject 15 | 16 | /** 17 | The space to be applied between the layouted text and the edges of the receiver 18 | */ 19 | @property (nonatomic, assign) DTEdgeInsets padding; 20 | 21 | 22 | /** 23 | The background color to paint behind the text in the receiver 24 | */ 25 | @property (nonatomic, strong) DTColor *backgroundColor; 26 | 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /Core/Source/DTTextBlock.m: -------------------------------------------------------------------------------- 1 | // 2 | // DTTextBlock.m 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 04.03.12. 6 | // Copyright (c) 2012 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTTextBlock.h" 10 | #import "NSCoder+DTCompatibility.h" 11 | 12 | @implementation DTTextBlock 13 | { 14 | DTEdgeInsets _padding; 15 | DTColor *_backgroundColor; 16 | } 17 | 18 | - (instancetype)initWithCoder:(NSCoder *)aDecoder { 19 | self = [super init]; 20 | if (self) { 21 | _padding = [aDecoder decodeDTEdgeInsetsForKey:@"padding"]; 22 | _backgroundColor = [aDecoder decodeObjectForKey:@"backgroundColor"]; 23 | } 24 | return self; 25 | } 26 | 27 | - (void)encodeWithCoder:(NSCoder *)aCoder { 28 | [aCoder encodeDTEdgeInsets:_padding forKey:@"padding"]; 29 | [aCoder encodeObject:_backgroundColor forKey:@"backgroundColor"]; 30 | } 31 | 32 | - (NSUInteger)hash 33 | { 34 | NSUInteger calcHash = 7; 35 | 36 | calcHash = calcHash*31 + [_backgroundColor hash]; 37 | calcHash = calcHash*31 + (NSUInteger)_padding.left; 38 | calcHash = calcHash*31 + (NSUInteger)_padding.top; 39 | calcHash = calcHash*31 + (NSUInteger)_padding.right; 40 | calcHash = calcHash*31 + (NSUInteger)_padding.bottom; 41 | 42 | return calcHash; 43 | } 44 | 45 | - (BOOL)isEqual:(id)object 46 | { 47 | if (!object) 48 | { 49 | return NO; 50 | } 51 | 52 | if (object == self) 53 | { 54 | return YES; 55 | } 56 | 57 | if (![object isKindOfClass:[DTTextBlock class]]) 58 | { 59 | return NO; 60 | } 61 | 62 | DTTextBlock *other = object; 63 | 64 | if (_padding.left != other->_padding.left || 65 | _padding.top != other->_padding.top || 66 | _padding.right != other->_padding.right || 67 | _padding.bottom != other->_padding.bottom) 68 | { 69 | return NO; 70 | } 71 | 72 | if (other->_backgroundColor == _backgroundColor) 73 | { 74 | return YES; 75 | } 76 | 77 | return [other->_backgroundColor isEqual:_backgroundColor]; 78 | } 79 | 80 | #pragma mark Properties 81 | 82 | @synthesize padding = _padding; 83 | @synthesize backgroundColor = _backgroundColor; 84 | 85 | @end 86 | -------------------------------------------------------------------------------- /Core/Source/DTTextHTMLElement.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTHTMLElementText.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 26.12.12. 6 | // Copyright (c) 2012 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTHTMLElement.h" 10 | 11 | /** 12 | Specialized subclass of that deals with text. It represents a text node. The text inside a DTHTMLElement can consist of any number of such text nodes. 13 | */ 14 | 15 | @interface DTTextHTMLElement : DTHTMLElement 16 | 17 | /** 18 | The text content of the element. 19 | */ 20 | @property (nonatomic, strong) NSString *text; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /Core/Source/DTVideoTextAttachment.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTTextAttachmentVideo.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 22.04.13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTTextAttachment.h" 10 | 11 | /** 12 | A specialized subclass in the DTTextAttachment class cluster to represent an embedded video 13 | */ 14 | 15 | @interface DTVideoTextAttachment : DTTextAttachment 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Core/Source/DTWeakSupport.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTWeakSupport.h 3 | // DTFoundation 4 | // 5 | // Created by Oliver Drobnik on 6/3/13. 6 | // Copyright (c) 2013 Cocoanetics. All rights reserved. 7 | // 8 | 9 | /** 10 | Useful defines for building code the compiles with zeroing weak references if the deployment target allows it. This is possible from minimum supported iOS 5.0 and OS X 10.7 and above. Note that on OS X 10.7 some AppKit classes do not support having a weak ref, e.g. NSWindowController or NSViewController. 11 | */ 12 | 13 | #import 14 | 15 | #if __has_feature(objc_arc_weak) 16 | 17 | // zeroing weak refs are supported for ivars and properties 18 | #define DT_WEAK_VARIABLE __weak 19 | #define DT_WEAK_PROPERTY weak 20 | 21 | #elif __has_feature(objc_arc) 22 | 23 | /// zeroing weak refs not supported, fall back to unsafe unretained and assigning 24 | #define DT_WEAK_VARIABLE __unsafe_unretained 25 | #define DT_WEAK_PROPERTY assign 26 | 27 | #else 28 | 29 | // define something, as this header might be included in a non-ARC project for using compiled code from an ARC static lib 30 | #define DT_WEAK_VARIABLE 31 | #define DT_WEAK_PROPERTY assign 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /Core/Source/NSAttributedString+DTDebug.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSAttributedString+DTDebug.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 29.04.13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** 12 | The *DTDebug* category contains methods for debugging and dumping attributed strings 13 | */ 14 | @interface NSAttributedString (DTDebug) 15 | 16 | - (void)dumpRangesOfAttribute:(id)attribute; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /Core/Source/NSAttributedString+DTDebug.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSAttributedString+DTDebug.m 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 29.04.13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "NSAttributedString+DTDebug.h" 10 | 11 | 12 | @implementation NSAttributedString (DTDebug) 13 | 14 | - (void)dumpRangesOfAttribute:(id)attribute 15 | { 16 | NSMutableString *tmpString = [NSMutableString string]; 17 | 18 | NSRange entireRange = NSMakeRange(0, [self length]); 19 | [self enumerateAttribute:attribute inRange:entireRange options:0 usingBlock:^(id value, NSRange range, BOOL *stop) { 20 | NSString *rangeString = [[self string] substringWithRange:range]; 21 | NSString *valueString; 22 | 23 | if ([value isKindOfClass:[NSArray class]]) 24 | { 25 | valueString = [(NSArray *)value componentsJoinedByString:@", "]; 26 | } 27 | else 28 | { 29 | valueString = [value debugDescription]; 30 | } 31 | 32 | [tmpString appendFormat:@"%@ %@ '%@'\n", NSStringFromRange(range), valueString, [rangeString stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"]]; 33 | }]; 34 | 35 | printf("%s", [tmpString UTF8String]); 36 | } 37 | 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /Core/Source/NSAttributedString+SmallCaps.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSAttributedString+SmallCaps.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 31.01.12. 6 | // Copyright (c) 2012 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTCompatibility.h" 10 | 11 | /** 12 | Methods that generated an attributed string with Small Caps, even if the used fonts don't support them natively. 13 | 14 | This category works equally for Mac and iOS attributed strings. 15 | */ 16 | 17 | @interface NSAttributedString (SmallCaps) 18 | 19 | /** 20 | Creates an `NSAttributedString` from the given text and attributes and synthesizes small caps. On iPad there is only one font that has native small caps, for all other fonts the small caps are synthesized by reducing the font size for all lowercase characters. 21 | 22 | @param text The string to convert into an attributed string 23 | @param attributes A dictionary with attributes for the attributed string 24 | @returns An attributed string with synthesized small caps. 25 | */ 26 | + (NSAttributedString *)synthesizedSmallCapsAttributedStringWithText:(NSString *)text attributes:(NSDictionary *)attributes; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /Core/Source/NSAttributedString+SmallCaps.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSAttributedString+SmallCaps.m 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 31.01.12. 6 | // Copyright (c) 2012 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "NSAttributedString+SmallCaps.h" 10 | #import "DTCoreTextFontDescriptor.h" 11 | #import "NSDictionary+DTCoreText.h" 12 | #import "DTCoreTextConstants.h" 13 | 14 | 15 | #if TARGET_OS_IPHONE 16 | #import "UIFont+DTCoreText.h" 17 | #endif 18 | 19 | @implementation NSAttributedString (SmallCaps) 20 | 21 | + (NSAttributedString *)synthesizedSmallCapsAttributedStringWithText:(NSString *)text attributes:(NSDictionary *)attributes 22 | { 23 | DTCoreTextFontDescriptor *fontDescriptor = [attributes fontDescriptor]; 24 | 25 | if (!fontDescriptor) 26 | { 27 | return nil; 28 | } 29 | 30 | DTCoreTextFontDescriptor *smallerFontDesc = [fontDescriptor copy]; 31 | smallerFontDesc.pointSize *= (CGFloat)0.7; 32 | 33 | CTFontRef smallerFont = [smallerFontDesc newMatchingFont]; 34 | 35 | if (!smallerFont) 36 | { 37 | return nil; 38 | } 39 | 40 | NSMutableDictionary *smallAttributes = [attributes mutableCopy]; 41 | 42 | #if DTCORETEXT_SUPPORT_NS_ATTRIBUTES && TARGET_OS_IPHONE 43 | if (___useiOS6Attributes) 44 | { 45 | UIFont *uiFont = [UIFont fontWithCTFont:smallerFont]; 46 | 47 | [smallAttributes setObject:uiFont forKey:NSFontAttributeName]; 48 | 49 | CFRelease(smallerFont); 50 | } 51 | else 52 | #endif 53 | { 54 | [smallAttributes setObject:CFBridgingRelease(smallerFont) forKey:(id)kCTFontAttributeName]; 55 | } 56 | 57 | NSMutableAttributedString *tmpString = [[NSMutableAttributedString alloc] init]; 58 | NSScanner *scanner = [NSScanner scannerWithString:text]; 59 | [scanner setCharactersToBeSkipped:nil]; 60 | 61 | NSCharacterSet *lowerCaseChars = [NSCharacterSet lowercaseLetterCharacterSet]; 62 | 63 | while (![scanner isAtEnd]) 64 | { 65 | NSString *part; 66 | 67 | if ([scanner scanCharactersFromSet:lowerCaseChars intoString:&part]) 68 | { 69 | part = [part uppercaseString]; 70 | NSAttributedString *partString = [[NSAttributedString alloc] initWithString:part attributes:smallAttributes]; 71 | [tmpString appendAttributedString:partString]; 72 | } 73 | 74 | if ([scanner scanUpToCharactersFromSet:lowerCaseChars intoString:&part]) 75 | { 76 | NSAttributedString *partString = [[NSAttributedString alloc] initWithString:part attributes:attributes]; 77 | [tmpString appendAttributedString:partString]; 78 | } 79 | } 80 | 81 | return tmpString; 82 | } 83 | 84 | @end 85 | -------------------------------------------------------------------------------- /Core/Source/NSAttributedStringRunDelegates.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSAttributedStringRunDelegates.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver on 14.01.11. 6 | // Copyright 2011 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTCompatibility.h" 10 | 11 | #import 12 | 13 | #if TARGET_OS_IPHONE 14 | #import 15 | #elif TARGET_OS_MAC 16 | #import 17 | #endif 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | void embeddedObjectDeallocCallback(void *_Nullable context); 24 | CGFloat embeddedObjectGetAscentCallback(void *_Nullable context); 25 | CGFloat embeddedObjectGetDescentCallback(void *_Nullable context); 26 | CGFloat embeddedObjectGetWidthCallback(void *_Nullable context); 27 | CTRunDelegateRef _Nullable createEmbeddedObjectRunDelegate(id _Nullable obj); 28 | 29 | #ifdef __cplusplus 30 | } 31 | #endif 32 | -------------------------------------------------------------------------------- /Core/Source/NSAttributedStringRunDelegates.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSAttributedStringRunDelegates.m 3 | // DTCoreText 4 | // 5 | // Created by Oliver on 14.01.11. 6 | // Copyright 2011 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "NSAttributedStringRunDelegates.h" 10 | #import "DTTextAttachment.h" 11 | 12 | 13 | void embeddedObjectDeallocCallback(void *_Nullable context) 14 | { 15 | } 16 | 17 | CGFloat embeddedObjectGetAscentCallback(void *_Nullable context) 18 | { 19 | if ([(__bridge id)context isKindOfClass:[DTTextAttachment class]]) 20 | { 21 | return [(__bridge DTTextAttachment *)context ascentForLayout]; 22 | } 23 | return 0; 24 | } 25 | CGFloat embeddedObjectGetDescentCallback(void *_Nullable context) 26 | { 27 | if ([(__bridge id)context isKindOfClass:[DTTextAttachment class]]) 28 | { 29 | return [(__bridge DTTextAttachment *)context descentForLayout]; 30 | } 31 | return 0; 32 | } 33 | 34 | CGFloat embeddedObjectGetWidthCallback(void *_Nullable context) 35 | { 36 | if ([(__bridge id)context isKindOfClass:[DTTextAttachment class]]) 37 | { 38 | return [(__bridge DTTextAttachment *)context displaySize].width; 39 | } 40 | return 35; 41 | } 42 | 43 | CTRunDelegateRef _Nullable createEmbeddedObjectRunDelegate(id _Nullable obj) 44 | { 45 | CTRunDelegateCallbacks callbacks; 46 | callbacks.version = kCTRunDelegateCurrentVersion; 47 | callbacks.dealloc = embeddedObjectDeallocCallback; 48 | callbacks.getAscent = embeddedObjectGetAscentCallback; 49 | callbacks.getDescent = embeddedObjectGetDescentCallback; 50 | callbacks.getWidth = embeddedObjectGetWidthCallback; 51 | return CTRunDelegateCreate(&callbacks, (__bridge void *)obj); 52 | } 53 | -------------------------------------------------------------------------------- /Core/Source/NSCoder+DTCompatibility.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSCoder+DTCompatibility.h 3 | // DTCoreText 4 | // 5 | // Created by Ryan Johnson on 14/02/19. 6 | // Copyright (c) 2014 Drobnik.com. All rights reserved. 7 | // 8 | 9 | 10 | #import 11 | 12 | #import "DTCompatibility.h" 13 | 14 | @interface NSCoder (DTCompatibility) 15 | 16 | #if !TARGET_OS_IPHONE 17 | - (void)encodeCGSize:(CGSize)size forKey:(NSString *)key; 18 | - (CGSize)decodeCGSizeForKey:(NSString *)key; 19 | #endif 20 | 21 | - (void)encodeDTEdgeInsets:(DTEdgeInsets)insets forKey:(NSString *)key; 22 | - (DTEdgeInsets)decodeDTEdgeInsetsForKey:(NSString *)key; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /Core/Source/NSCoder+DTCompatibility.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSCoder+DTCompatibility.m 3 | // DTCoreText 4 | // 5 | // Created by Ryan Johnson on 14/02/19. 6 | // Copyright (c) 2014 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "NSCoder+DTCompatibility.h" 10 | 11 | #if !TARGET_OS_IPHONE 12 | NSString* NSStringFromNSEdgeInsets(NSEdgeInsets insets); 13 | NSEdgeInsets NSEdgeInsetsFromString(NSString *string); 14 | #endif 15 | 16 | @implementation NSCoder (DTCompatibility) 17 | 18 | #if !TARGET_OS_IPHONE 19 | - (void)encodeCGSize:(CGSize)size forKey:(NSString *)key { 20 | [self encodeObject:NSStringFromCGSize(size) forKey:key]; 21 | } 22 | 23 | - (CGSize)decodeCGSizeForKey:(NSString *)key { 24 | return NSSizeToCGSize(NSSizeFromString([self decodeObjectForKey:key])); 25 | } 26 | #endif 27 | 28 | - (void)encodeDTEdgeInsets:(DTEdgeInsets)insets forKey:(NSString *)key { 29 | #if TARGET_OS_IPHONE 30 | [self encodeUIEdgeInsets:insets forKey:key]; 31 | #else 32 | [self encodeObject:NSStringFromNSEdgeInsets(insets) forKey:key]; 33 | #endif 34 | } 35 | 36 | - (DTEdgeInsets)decodeDTEdgeInsetsForKey:(NSString *)key { 37 | #if TARGET_OS_IPHONE 38 | return [self decodeUIEdgeInsetsForKey:key]; 39 | #else 40 | return NSEdgeInsetsFromString([self decodeObjectForKey:key]); 41 | #endif 42 | } 43 | 44 | 45 | @end 46 | 47 | #if !TARGET_OS_IPHONE 48 | NSString* NSStringFromNSEdgeInsets(NSEdgeInsets insets) { 49 | return [NSString stringWithFormat:@"{%f,%f,%f,%f}", insets.top, insets.left, insets.bottom, insets.right]; 50 | } 51 | 52 | NSEdgeInsets NSEdgeInsetsFromString(NSString *string) { 53 | // Cut off curly brackets 54 | string = [string substringWithRange:NSMakeRange(1, string.length - 2)]; 55 | 56 | NSArray *floatStrings = [string componentsSeparatedByString:@","]; 57 | if (floatStrings.count != 4) { 58 | return NSEdgeInsetsMake(0, 0, 0, 0); 59 | } 60 | CGFloat top = [floatStrings[0] floatValue]; 61 | CGFloat left = [floatStrings[1] floatValue]; 62 | CGFloat bottom = [floatStrings[2] floatValue]; 63 | CGFloat right = [floatStrings[3] floatValue]; 64 | 65 | return NSEdgeInsetsMake(top, left, bottom, right); 66 | } 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /Core/Source/NSDictionary+DTCoreText.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSDictionary+DTRichText.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 7/21/11. 6 | // Copyright 2011 Cocoanetics. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "DTCompatibility.h" 12 | 13 | @class DTCoreTextParagraphStyle; 14 | @class DTCoreTextFontDescriptor; 15 | 16 | /** 17 | Convenience methods for editors dealing with Core Text attribute dictionaries. 18 | */ 19 | @interface NSDictionary (DTCoreText) 20 | 21 | /** 22 | @name Getting State information 23 | */ 24 | 25 | /** 26 | Whether the font in the receiver's attributes is bold. 27 | @returns `YES` if the text has a bold trait 28 | */ 29 | - (BOOL)isBold; 30 | 31 | /** 32 | Whether the font in the receiver's attributes is italic. 33 | @returns `YES` if the text has an italic trait 34 | */ 35 | - (BOOL)isItalic; 36 | 37 | /** 38 | Whether the receiver's attributes contains underlining. 39 | @returns `YES` if the text is underlined 40 | */ 41 | - (BOOL)isUnderline; 42 | 43 | /** 44 | Whether the receiver's attributes contains strike-through. 45 | @returns `YES` if the text is strike-through 46 | */ 47 | - (BOOL)isStrikethrough; 48 | 49 | /** 50 | Whether the receiver's attributes contain a DTTextAttachment 51 | @returns `YES` if there is an attachment 52 | */ 53 | - (BOOL)hasAttachment; 54 | 55 | /** 56 | The header level of the receiver 57 | @returns The header level (1-6) or 0 if no header level is set 58 | */ 59 | - (NSUInteger)headerLevel; 60 | 61 | /** 62 | @name Getting Style Information 63 | */ 64 | 65 | /** 66 | Retrieves the DTCoreTextParagraphStyle from the receiver's attributes. This supports both `CTParagraphStyle` as well as `NSParagraphStyle` as a possible representation of the text's paragraph style. 67 | @returns The paragraph style 68 | */ 69 | - (DTCoreTextParagraphStyle *)paragraphStyle; 70 | 71 | /** 72 | Retrieves the DTCoreTextFontDescriptor from the receiver's attributes. This supports both `CTFont` as well as `UIFont` as a possible representation of the text's font. 73 | @returns The font descriptor 74 | */ 75 | - (DTCoreTextFontDescriptor *)fontDescriptor; 76 | 77 | /** 78 | Retrieves the foreground color. On iOS as UIColor, on Mac as NSColor. This supports both the CT as well as the NS/UIKit method of specifying the color. If no foreground color is defined in the receiver then black is assumed. 79 | @returns The platform-specific color defined for the foreground 80 | */ 81 | - (DTColor *)foregroundColor; 82 | 83 | /** 84 | Retrieves the background color. On iOS as UIColor, on Mac as NSColor. This supports both the DT as well as the NS/UIKit method of specifying the color. If no background color is defined in the receiver then `nil` is returned 85 | @returns The platform-specific color defined for the background, or `nil` if none is defined 86 | */ 87 | - (DTColor *)backgroundColor; 88 | 89 | /** 90 | The text kerning value 91 | @returns the kerning value 92 | */ 93 | - (CGFloat)kerning; 94 | 95 | @end 96 | -------------------------------------------------------------------------------- /Core/Source/NSMutableAttributedString+HTML.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSMutableAttributedString+HTML.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 4/14/11. 6 | // Copyright 2011 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTCompatibility.h" 10 | 11 | #import "DTCoreTextConstants.h" 12 | 13 | @class DTCoreTextParagraphStyle, DTCoreTextFontDescriptor; 14 | 15 | /** 16 | Methods for appending `NSString` instances to mutable attributed strings 17 | */ 18 | @interface NSMutableAttributedString (HTML) 19 | 20 | /** 21 | Appends a string with the same attributes as this string to this string. 22 | 23 | If the last character of the receiver contains a placeholder for a it is removed from the appended string. Also fields (e.g. list prefixes) are not extended 24 | @param string The string to be appended to this string. */ 25 | - (void)appendString:(NSString *)string; 26 | - (void)dt_appendString:(NSString *)string;// added this prefix version of appendString ,because the appendString method defined duplication in iOS18 ,appendString will also defined in ScreenReaderCore.framework 27 | 28 | /** 29 | Appends a string with a given paragraph style and font to this string. 30 | @param string The string to be appended to this string. 31 | @param paragraphStyle Paragraph style to be attributed to the appended string. 32 | @param fontDescriptor Font descriptor to be attributed to the appended string. */ 33 | - (void)appendString:(NSString *)string withParagraphStyle:(DTCoreTextParagraphStyle *)paragraphStyle fontDescriptor:(DTCoreTextFontDescriptor *)fontDescriptor; 34 | 35 | /** 36 | Adds the paragraph terminator `\n` and makes sure that the previous font and paragraph styles extend to include it 37 | */ 38 | - (void)appendEndOfParagraph; 39 | 40 | /** 41 | @name Working with Custom HTML Attributes 42 | */ 43 | 44 | /** 45 | Adds the custom HTML attributes with the given value on the given range, optionally replacing occurrences of an attribute with the same name. 46 | @param name The name of the custom HTML attribute 47 | @param value The value to set for the custom attribute 48 | @param range The range to add the custom attribute for 49 | @param replaceExisting `YES` if ranges that have an attribute with the same name should be replaced. With `NO` the attribute is only added for ranges where there is no attribute with the given name 50 | */ 51 | - (void)addHTMLAttribute:(NSString *)name value:(id)value range:(NSRange)range replaceExisting:(BOOL)replaceExisting; 52 | 53 | /** 54 | Adds the custom HTML attributes with the given value from the given range. 55 | @param name The name of the custom HTML attribute 56 | @param range The range to add the custom attribute for 57 | */ 58 | - (void)removeHTMLAttribute:(NSString *)name range:(NSRange)range; 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /Core/Source/NSMutableString+HTML.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSMutableString+HTML.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 01.02.12. 6 | // Copyright (c) 2012 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** 12 | Categories needed for modifying mutable strings, as needed for DTCoreText. 13 | */ 14 | @interface NSMutableString (HTML) 15 | 16 | /** 17 | Removes the trailing whitespace from the receiver. 18 | */ 19 | - (void)removeTrailingWhitespace; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /Core/Source/NSMutableString+HTML.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSMutableString+HTML.m 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 01.02.12. 6 | // Copyright (c) 2012 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "NSMutableString+HTML.h" 10 | 11 | 12 | #define IS_WHITESPACE(_c) (_c == ' ' || _c == '\t' || _c == 0xA || _c == 0xB || _c == 0xC || _c == 0xD || _c == 0x85) 13 | 14 | @implementation NSMutableString (HTML) 15 | 16 | - (void)removeTrailingWhitespace 17 | { 18 | NSUInteger length = self.length; 19 | 20 | NSInteger lastIndex = length-1; 21 | NSInteger index = lastIndex; 22 | NSInteger whitespaceLength = 0; 23 | 24 | while (index>=0 && IS_WHITESPACE([self characterAtIndex:index])) 25 | { 26 | index--; 27 | whitespaceLength++; 28 | } 29 | 30 | // do the removal once for all whitespace characters 31 | if (whitespaceLength) 32 | { 33 | [self deleteCharactersInRange:NSMakeRange(index+1, whitespaceLength)]; 34 | } 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /Core/Source/NSNumber+RomanNumerals.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSNumber+RomanNumerals.h 3 | // DTCoreText 4 | // 5 | // Created by Kai Maschke on 26.07.16. 6 | // Copyright © 2016 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSNumber (RomanNumerals) 12 | 13 | - (NSString *)romanNumeral; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Core/Source/NSNumber+RomanNumerals.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSNumber+RomanNumerals.m 3 | // DTCoreText 4 | // 5 | // Created by Kai Maschke on 26.07.16. 6 | // Copyright © 2016 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "NSNumber+RomanNumerals.h" 10 | 11 | @implementation NSNumber (RomanNumerals) 12 | 13 | static NSArray *romanNumerals; 14 | static NSUInteger const romanValues[] = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1}; 15 | static NSInteger const romanValueCount = 13; 16 | 17 | - (NSString *)romanNumeral 18 | { 19 | if (!romanNumerals) { 20 | romanNumerals = @[@"M", @"CM", @"D", @"CD", @"C", @"XC", @"L", @"XL", @"X", @"IX", @"V", @"IV", @"I"]; 21 | } 22 | 23 | NSInteger n = [self integerValue]; 24 | 25 | NSMutableString *numeralString = [NSMutableString string]; 26 | 27 | for (NSUInteger i = 0; i < romanValueCount; i++) 28 | { 29 | while (n >= romanValues[i]) 30 | { 31 | n -= romanValues[i]; 32 | [numeralString appendString:[romanNumerals objectAtIndex:i]]; 33 | } 34 | } 35 | 36 | return numeralString; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /Core/Source/NSScanner+HTML.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSScanner+HTML.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 1/12/11. 6 | // Copyright 2011 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "DTCompatibility.h" 12 | 13 | /** 14 | Extensions for NSScanner to deal with HTML-specific parsing, primarily CSS-related things 15 | */ 16 | @interface NSScanner (HTML) 17 | 18 | /** 19 | @name Working with CSS 20 | */ 21 | 22 | /** 23 | Scans for a CSS attribute used in CSS style sheets 24 | @param name An optional output parameter that will contain the name of the scanned attribute if successful 25 | @param value An optional output parameter that will contain the value of the scanned attribute if successful. This value may be a string or an array. 26 | @returns `YES` if an URL String could be scanned 27 | */ 28 | - (BOOL)scanCSSAttribute:(NSString * __autoreleasing*)name value:(id __autoreleasing*)value; 29 | 30 | 31 | /** 32 | Scans for URLs used in CSS style sheets 33 | @param urlString An optional output parameter that will contain the scanned URL string if successful 34 | @returns `YES` if an URL String could be scanned 35 | */ 36 | - (BOOL)scanCSSURL:(NSString * __autoreleasing*)urlString; 37 | 38 | 39 | /** 40 | Scans for a typical HTML color, typically either #FFFFFF, rgb(255,255,255) or a HTML color name. 41 | @param color An optional output parameter that will contain the scanned color if successful 42 | @returns `YES` if a color could be scanned 43 | */ 44 | - (BOOL)scanHTMLColor:(DTColor * __autoreleasing*)color; 45 | 46 | /** 47 | Scans for a typical HTML color, typically either #FFFFFF, rgb(255,255,255) or a HTML color name. 48 | @param color An optional output parameter that will contain the scanned color if successful 49 | @param name An optional output parameter that will contain the HTML color string 50 | @returns `YES` if a color could be scanned 51 | */ 52 | - (BOOL)scanHTMLColor:(DTColor * __autoreleasing*)color HTMLName:(NSString * __autoreleasing*)name; 53 | 54 | @end 55 | 56 | -------------------------------------------------------------------------------- /Core/Source/NSString+CSS.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+CSS.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 31.01.12. 6 | // Copyright (c) 2012 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTCompatibility.h" 10 | 11 | /** 12 | Methods to make dealing with CSS strings easier. Extract shadows from this string, extract CSS styles found in this string, extract the pixel size of a CSS measurement relative to the current text size, and extract the CSS pixel measurement of this string. 13 | */ 14 | @interface NSString (CSS) 15 | 16 | /** 17 | Examine a string for all CSS styles that are applied to it and return a dictionary of those styles. Implemented using scanCSSAttribute: which is defined in NSScanner+HTML.h. 18 | @returns A dictionary of strings containing the CSS styles which are applied to this string. 19 | */ 20 | - (NSDictionary *)dictionaryOfCSSStyles; 21 | 22 | /** 23 | Determines if the receiver contains a CSS length value, that is a number with optional period and unit (em, pt, px). 24 | @returns `YES` if this is a CSS length value 25 | */ 26 | - (BOOL)isCSSLengthValue; 27 | 28 | /** 29 | Calculates a pixel-based length from the receiver based on the current text size in pixels. Used in DTHTMLElement. 30 | @param textSize The current size which the CSS size is relative to. 31 | @param textScale The factor by which absolute sizes are scaled. Set to 1.0f to keep the original value. 32 | @returns A float that is the textSize 33 | */ 34 | - (CGFloat)pixelSizeOfCSSMeasureRelativeToCurrentTextSize:(CGFloat)textSize textScale:(CGFloat)textScale; 35 | 36 | /** 37 | Decodes edge inset values from the CSS attribute string. This is used for margin and padding which might have varying number of elements. 38 | @param textSize The current size which the CSS size is relative to. 39 | @param textScale The factor by which absolute sizes are scaled. Set to 1.0f to keep the original value. 40 | @returns The edge insets that this describes 41 | */ 42 | - (DTEdgeInsets)DTEdgeInsetsRelativeToCurrentTextSize:(CGFloat)textSize textScale:(CGFloat)textScale; 43 | 44 | /** 45 | Parse CSS shadow styles, consisting of color, blur, and offset, out of this string. The input string must be comma delimited in the format: ? ? where the third length and the color are not required per CSS shadows. To calculate the sizes of the blur and offset pixelSizeOfCSSMeasureRelativeToCurrentTextSize is used. Used in DTHTMLElement. 46 | @param textSize In order to determine the shadow offset we need what text size it will be displayed at. 47 | @param color Used if no shadow attribute color is found. 48 | @returns An array of dictionaries, each of which is a shadow consisting of color, blur, and offset keys value pairs. 49 | */ 50 | - (NSArray *)arrayOfCSSShadowsWithCurrentTextSize:(CGFloat)textSize currentColor:(DTColor *)color; 51 | 52 | /** 53 | Decodes a content attribute which might contained unicode sequences. 54 | */ 55 | - (NSString *)stringByDecodingCSSContentAttribute; 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /Core/Source/NSString+Paragraphs.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+Paragraphs.h 3 | // DTRichTextEditor 4 | // 5 | // Created by Oliver Drobnik on 11/11/11. 6 | // Copyright (c) 2011 Cocoanetics. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** 12 | Methods simplifying dealing with text that is in paragraphs. 13 | 14 | The character used to separate paragraphs from each other is '\n'. 15 | */ 16 | @interface NSString (Paragraphs) 17 | 18 | /** 19 | Extends the given range such that it contains only full paragraphs. 20 | 21 | @param range The string range 22 | @param parBegIndex An optional output parameter that is filled with the beginning index of the extended range 23 | @param parEndIndex An optional output parameter that is filled with the ending index of the extended range 24 | @returns The extended string range 25 | */ 26 | - (NSRange)rangeOfParagraphsContainingRange:(NSRange)range parBegIndex:(NSUInteger *)parBegIndex parEndIndex:(NSUInteger *)parEndIndex; 27 | 28 | 29 | /** 30 | Determines if the given index is the first character of a new paragraph. 31 | 32 | This is done by examining the string, index 0 or characters following a newline are considered to be a first character of a new paragraph. 33 | @param index The index to examine 34 | @returns `YES` if the given index is the first character of a new paragraph, `NO` otherwise 35 | */ 36 | - (BOOL)indexIsAtBeginningOfParagraph:(NSUInteger)index; 37 | 38 | /** 39 | Returns the string range of the paragraph with the given index. 40 | 41 | @param index The paragraph index to inspect 42 | @returns The string range of the paragraph 43 | */ 44 | - (NSRange)rangeOfParagraphAtIndex:(NSUInteger)index; 45 | 46 | 47 | /** 48 | Counts the number of paragraphs in the receiver 49 | @returns The number of paragraph characters (\n) in the receiver 50 | */ 51 | - (NSUInteger)numberOfParagraphs; 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /Core/Source/NSString+Paragraphs.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+Paragraphs.m 3 | // DTRichTextEditor 4 | // 5 | // Created by Oliver Drobnik on 11/11/11. 6 | // Copyright (c) 2011 Cocoanetics. All rights reserved. 7 | // 8 | 9 | #import "NSString+Paragraphs.h" 10 | 11 | @implementation NSString (Paragraphs) 12 | 13 | - (NSRange)rangeOfParagraphsContainingRange:(NSRange)range parBegIndex:(NSUInteger *)parBegIndex parEndIndex:(NSUInteger *)parEndIndex 14 | { 15 | // get beginning and end of paragraph containing the replaced range 16 | CFIndex beginIndex; 17 | CFIndex endIndex; 18 | 19 | CFStringGetParagraphBounds((__bridge CFStringRef)self, CFRangeMake(range.location, range.length), &beginIndex, &endIndex, NULL); 20 | 21 | if (parBegIndex) 22 | { 23 | *parBegIndex = beginIndex; 24 | } 25 | 26 | if (parEndIndex) 27 | { 28 | *parEndIndex = endIndex; 29 | } 30 | 31 | // endIndex is the first character of the following paragraph, so we don't need to add 1 32 | 33 | return NSMakeRange(beginIndex, endIndex - beginIndex); 34 | } 35 | 36 | - (BOOL)indexIsAtBeginningOfParagraph:(NSUInteger)index 37 | { 38 | // index zero is beginning of first paragraph 39 | if (!index) 40 | { 41 | return YES; 42 | } 43 | 44 | // beginning of any other paragraph is after NL 45 | if ([self characterAtIndex:index-1] == '\n') 46 | { 47 | return YES; 48 | } 49 | 50 | // no beginning 51 | return NO; 52 | } 53 | 54 | - (NSRange)rangeOfParagraphAtIndex:(NSUInteger)index 55 | { 56 | return [self rangeOfParagraphsContainingRange:NSMakeRange(index, 1) parBegIndex:NULL parEndIndex:NULL]; 57 | } 58 | 59 | - (NSUInteger)numberOfParagraphs 60 | { 61 | NSUInteger retValue = 0; 62 | 63 | for (NSUInteger i=0; i<[self length]; i++) 64 | { 65 | if ([self characterAtIndex:i] == '\n') 66 | { 67 | retValue++; 68 | } 69 | } 70 | 71 | return retValue; 72 | } 73 | 74 | @end 75 | -------------------------------------------------------------------------------- /Core/Source/UIFont+DTCoreText.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIFont+DTCoreText.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 11.12.12. 6 | // Copyright (c) 2012 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTCompatibility.h" 10 | 11 | #if TARGET_OS_IPHONE 12 | 13 | #import 14 | 15 | /** 16 | Methods to translate from `CTFont` to `UIFont` 17 | */ 18 | 19 | @interface UIFont (DTCoreText) 20 | 21 | /** 22 | Creates a UIFont that matches the provided CTFont. 23 | @param ctFont a `CTFontRef` 24 | @returns The matching UIFont 25 | */ 26 | + (UIFont *)fontWithCTFont:(CTFontRef)ctFont; 27 | 28 | @end 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /Core/Source/UIFont+DTCoreText.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIFont+DTCoreText.m 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 11.12.12. 6 | // Copyright (c) 2012 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "UIFont+DTCoreText.h" 10 | 11 | #if TARGET_OS_IPHONE 12 | 13 | @implementation UIFont (DTCoreText) 14 | 15 | + (UIFont *)fontWithCTFont:(CTFontRef)ctFont 16 | { 17 | NSString *fontName = (__bridge_transfer NSString *)CTFontCopyName(ctFont, kCTFontFullNameKey); 18 | 19 | CGFloat fontSize = CTFontGetSize(ctFont); 20 | UIFont *font = [UIFont fontWithName:fontName size:fontSize]; 21 | 22 | // fix for missing HelveticaNeue-Italic font in iOS 7.0.x 23 | if (!font && [fontName isEqualToString:@"HelveticaNeue-Italic"]) 24 | { 25 | font = [UIFont fontWithName:@"HelveticaNeue-LightItalic" size:fontSize]; 26 | } 27 | 28 | return font; 29 | } 30 | 31 | @end 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /Core/include/DTCoreText/CTLineUtils.h: -------------------------------------------------------------------------------- 1 | ../../Source/CTLineUtils.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTAccessibilityElement.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTAccessibilityElement.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTAccessibilityViewProxy.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTAccessibilityViewProxy.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTAnchorHTMLElement.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTAnchorHTMLElement.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTAttributedLabel.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTAttributedLabel.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTAttributedTextCell.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTAttributedTextCell.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTAttributedTextContentView.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTAttributedTextContentView.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTAttributedTextView.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTAttributedTextView.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTBreakHTMLElement.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTBreakHTMLElement.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTCSSListStyle.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTCSSListStyle.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTCSSStylesheet.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTCSSStylesheet.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTColor+Compatibility.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTColor+Compatibility.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTColorFunctions.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTColorFunctions.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTCompatibility.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTCompatibility.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTCoreTextConstants.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTCoreTextConstants.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTCoreTextFontCollection.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTCoreTextFontCollection.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTCoreTextFontDescriptor.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTCoreTextFontDescriptor.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTCoreTextFunctions.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTCoreTextFunctions.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTCoreTextGlyphRun.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTCoreTextGlyphRun.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTCoreTextLayoutFrame+Cursor.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTCoreTextLayoutFrame+Cursor.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTCoreTextLayoutFrame.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTCoreTextLayoutFrame.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTCoreTextLayoutFrameAccessibilityElementGenerator.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTCoreTextLayoutFrameAccessibilityElementGenerator.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTCoreTextLayoutLine.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTCoreTextLayoutLine.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTCoreTextLayouter.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTCoreTextLayouter.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTCoreTextMacros.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTCoreTextMacros.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTCoreTextParagraphStyle.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTCoreTextParagraphStyle.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTDictationPlaceholderTextAttachment.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTDictationPlaceholderTextAttachment.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTDictationPlaceholderView.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTDictationPlaceholderView.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTHTMLAttributedStringBuilder.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTHTMLAttributedStringBuilder.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTHTMLElement.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTHTMLElement.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTHTMLParserNode.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTHTMLParserNode.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTHTMLParserTextNode.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTHTMLParserTextNode.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTHTMLWriter.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTHTMLWriter.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTHorizontalRuleHTMLElement.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTHorizontalRuleHTMLElement.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTIframeTextAttachment.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTIframeTextAttachment.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTImage+HTML.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTImage+HTML.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTImageTextAttachment.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTImageTextAttachment.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTLazyImageView.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTLazyImageView.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTLinkButton.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTLinkButton.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTListItemHTMLElement.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTListItemHTMLElement.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTObjectTextAttachment.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTObjectTextAttachment.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTStylesheetHTMLElement.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTStylesheetHTMLElement.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTTextAttachment.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTTextAttachment.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTTextAttachmentHTMLElement.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTTextAttachmentHTMLElement.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTTextBlock.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTTextBlock.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTTextHTMLElement.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTTextHTMLElement.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTVideoTextAttachment.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTVideoTextAttachment.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/DTWeakSupport.h: -------------------------------------------------------------------------------- 1 | ../../Source/DTWeakSupport.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/NSAttributedString+DTCoreText.h: -------------------------------------------------------------------------------- 1 | ../../Source/NSAttributedString+DTCoreText.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/NSAttributedString+DTDebug.h: -------------------------------------------------------------------------------- 1 | ../../Source/NSAttributedString+DTDebug.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/NSAttributedString+HTML.h: -------------------------------------------------------------------------------- 1 | ../../Source/NSAttributedString+HTML.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/NSAttributedString+SmallCaps.h: -------------------------------------------------------------------------------- 1 | ../../Source/NSAttributedString+SmallCaps.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/NSAttributedStringRunDelegates.h: -------------------------------------------------------------------------------- 1 | ../../Source/NSAttributedStringRunDelegates.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/NSCharacterSet+HTML.h: -------------------------------------------------------------------------------- 1 | ../../Source/NSCharacterSet+HTML.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/NSCoder+DTCompatibility.h: -------------------------------------------------------------------------------- 1 | ../../Source/NSCoder+DTCompatibility.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/NSDictionary+DTCoreText.h: -------------------------------------------------------------------------------- 1 | ../../Source/NSDictionary+DTCoreText.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/NSMutableAttributedString+HTML.h: -------------------------------------------------------------------------------- 1 | ../../Source/NSMutableAttributedString+HTML.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/NSMutableString+HTML.h: -------------------------------------------------------------------------------- 1 | ../../Source/NSMutableString+HTML.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/NSNumber+RomanNumerals.h: -------------------------------------------------------------------------------- 1 | ../../Source/NSNumber+RomanNumerals.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/NSScanner+HTML.h: -------------------------------------------------------------------------------- 1 | ../../Source/NSScanner+HTML.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/NSString+CSS.h: -------------------------------------------------------------------------------- 1 | ../../Source/NSString+CSS.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/NSString+HTML.h: -------------------------------------------------------------------------------- 1 | ../../Source/NSString+HTML.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/NSString+Paragraphs.h: -------------------------------------------------------------------------------- 1 | ../../Source/NSString+Paragraphs.h -------------------------------------------------------------------------------- /Core/include/DTCoreText/UIFont+DTCoreText.h: -------------------------------------------------------------------------------- 1 | ../../Source/UIFont+DTCoreText.h -------------------------------------------------------------------------------- /DTCoreText.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |spec| 2 | spec.name = 'DTCoreText' 3 | spec.version = '1.6.27' 4 | spec.platforms = {:ios => '4.3', :tvos => '9.0' } 5 | spec.license = 'BSD' 6 | spec.source = { :git => 'https://github.com/Cocoanetics/DTCoreText.git', :tag => spec.version.to_s } 7 | spec.source_files = 'Core/Source/*.{h,m,c}' 8 | spec.ios.source_files = 'Core/Source/iOS/*.{h,m,c}' 9 | spec.dependency 'DTFoundation/Core', '~>1.7.5' 10 | spec.dependency 'DTFoundation/UIKit', '~>1.7.5' 11 | spec.dependency 'DTFoundation/DTHTMLParser', '~>1.7.5' 12 | spec.dependency 'DTFoundation/DTAnimatedGIF', '~>1.7.5' 13 | spec.frameworks = 'MediaPlayer', 'QuartzCore', 'CoreText', 'CoreGraphics', 'ImageIO' 14 | spec.requires_arc = true 15 | spec.homepage = 'https://github.com/Cocoanetics/DTCoreText' 16 | spec.summary = 'Methods to allow using HTML code with CoreText.' 17 | spec.author = { 'Oliver Drobnik' => 'oliver@cocoanetics.com' } 18 | spec.documentation_url = 'http://docs.cocoanetics.com/DTCoreText' 19 | spec.social_media_url = 'https://twitter.com/cocoanetics' 20 | spec.prefix_header_contents = '#import ' 21 | spec.xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited)' } 22 | spec.resource_bundles = { 'Resources': 'Core/Source/default.css' } 23 | 24 | spec.default_subspec = 'Core' 25 | 26 | spec.subspec 'Core' do |ap| 27 | ap.source_files = 'Core/Source/*.{h,m,c}' 28 | end 29 | 30 | spec.subspec 'Extension' do |ap| 31 | ap.source_files = 'Core/Source/*.{h,m,c}' 32 | ap.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) DT_APP_EXTENSIONS=1' } 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /DTCoreText.xcodeproj/xcshareddata/xcschemes/DTCoreText (tvOS).xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 52 | 53 | 59 | 60 | 66 | 67 | 68 | 69 | 71 | 72 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /DTCoreText.xcodeproj/xcshareddata/xcschemes/DTCoreText-Package.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 53 | 54 | 60 | 61 | 67 | 68 | 69 | 70 | 72 | 73 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /DTCoreText.xcodeproj/xcshareddata/xcschemes/Documentation.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 52 | 53 | 59 | 60 | 62 | 63 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /DTCoreText.xcodeproj/xcshareddata/xcschemes/UnitTest.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 14 | 15 | 17 | 23 | 24 | 25 | 27 | 28 | 29 | 30 | 31 | 32 | 42 | 43 | 49 | 50 | 52 | 53 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cocoanetics/DTCoreText/ccbf88514fdc01bc613fe983b1516fb396ab65f1/Default-568h@2x.png -------------------------------------------------------------------------------- /Demo/DemoApp-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleDisplayName 8 | Rich Text 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFile 12 | 13 | CFBundleIdentifier 14 | $(PRODUCT_BUNDLE_IDENTIFIER) 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | ${PRODUCT_NAME} 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | 1.0 23 | CFBundleSignature 24 | ???? 25 | CFBundleVersion 26 | 1.0 27 | LSRequiresIPhoneOS 28 | 29 | NSAppTransportSecurity 30 | 31 | NSAllowsArbitraryLoads 32 | 33 | 34 | UIAppFonts 35 | 36 | XB NiloofarBd.ttf 37 | XB Niloofar.ttf 38 | 39 | UILaunchStoryboardName 40 | Launch.storyboard 41 | UISupportedInterfaceOrientations 42 | 43 | UIInterfaceOrientationLandscapeRight 44 | UIInterfaceOrientationLandscapeLeft 45 | UIInterfaceOrientationPortraitUpsideDown 46 | UIInterfaceOrientationPortrait 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /Demo/DemoApp-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'CoreTextExtensions' target in the 'CoreTextExtensions' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | 7 | #import 8 | #import 9 | #import 10 | 11 | #import "DTCoreText.h" 12 | 13 | #endif -------------------------------------------------------------------------------- /Demo/Resources/APOD.html: -------------------------------------------------------------------------------- 1 |

Newline Spaces and BaseURL Handling

2 |

This HTML has text beginning after ending tags on new lines. These need to turn into spaces. Also the HTML links are relative links, this tests if they get turned into links relative to the supplied BaseURL

3 |

The remarkable view 5 | follows the locations of this galaxy's 6 | once and future stars. 8 | 9 | In reddish hues, image data from the large 10 | Herschel infrared 11 | observatory traces enormous lanes of dust, 12 | warmed by stars, sweeping along Andromeda's spiral arms. 13 | 14 | The dust, in conjunction with the galaxy's interstellar gas, 15 | comprises the raw material for future 16 | star formation. 17 | 18 | X-ray data from the XMM-Newton 19 | observatory in blue 20 | pinpoint Andromeda's X-ray binary 21 | star systems. 22 | 23 | These systems likely contain neutron stars or stellar mass 24 | black holes that represent final stages in stellar evolution. 25 | 26 | More than twice the size of our own Milky Way, 27 | the Andromeda Galaxy is over 200,000 light-years across.

-------------------------------------------------------------------------------- /Demo/Resources/About.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |

DTCoreText consists of two portions:

5 |
    6 |
  1. Parsing HTML and creating NSAttributedStrings
  2. 7 |
  3. UI Classes for properly displaying these
  4. 8 |
9 |

This page demonstrates a DTAttributedTextView being loaded from a XIB. You can see how this line wraps if you rotate the device.

10 |
11 |

For example you could create a rich text about view like this here

12 |

Note:You need to disable auto-layout on view controllers loading views from XIB because at present DTCoreText is not yet able to dynamically re-layout in auto-layout views.

13 | 14 | 15 | -------------------------------------------------------------------------------- /Demo/Resources/Alignment.html: -------------------------------------------------------------------------------- 1 |

Text Alignment

2 |

Supported are all text alignment options via CSS text-align or the center tag.

3 |

text-align: left, right, center, justify, inherit

4 | 5 |

Examples

6 | 7 |

Right

Center

Left

8 | 9 |

Non-Justified

10 |

This is normal text, naturally aligned

11 |

Proin lectus nisl, volutpat non aliquet id, suscipit sed est. Maecenas vitae metus eget nulla mattis bibendum a a dolor. Fusce vestibulum velit hendrerit nunc egestas non ullamcorper ipsum sagittis. Praesent dui sapien, egestas sed tincidunt vitae, posuere eu neque. Donec faucibus felis sed magna cursus in faucibus odio aliquam. Curabitur elit urna, ullamcorper ut placerat vitae, posuere sed nisl. Maecenas ac tellus nulla, a commodo purus. Suspendisse porta vulputate volutpat. Integer sodales turpis vitae ante sodales tempor. Cras iaculis accumsan ante, sed interdum sem faucibus vel. Aenean tincidunt eleifend elit at porta. Aenean sodales lacus quis lacus gravida consectetur. Sed at ligula ut diam porta auctor. Nunc libero mauris, feugiat id gravida sed, blandit non neque. Suspendisse ac mauris urna. Vivamus lacus ipsum, tincidunt nec laoreet quis, convallis id purus. Ut vehicula lobortis erat in viverra. Ut ut tellus eget ipsum malesuada dignissim. Donec quis dolor erat, id adipiscing ipsum. Donec vitae sagittis turpis. 12 |

13 | 14 |

Justified

15 |

Justified Text is ideal for articles and books because the left and right border appears visually the same

16 | 17 |

Proin lectus nisl, volutpat non aliquet id, suscipit sed est. Maecenas vitae metus eget nulla mattis bibendum a a dolor. Fusce vestibulum velit hendrerit nunc egestas non ullamcorper ipsum sagittis. Praesent dui sapien, egestas sed tincidunt vitae, posuere eu neque. Donec faucibus felis sed magna cursus in faucibus odio aliquam. Curabitur elit urna, ullamcorper ut placerat vitae, posuere sed nisl. Maecenas ac tellus nulla, a commodo purus. Suspendisse porta vulputate volutpat. Integer sodales turpis vitae ante sodales tempor. Cras iaculis accumsan ante, sed interdum sem faucibus vel. Aenean tincidunt eleifend elit at porta. Aenean sodales lacus quis lacus gravida consectetur. Sed at ligula ut diam porta auctor. Nunc libero mauris, feugiat id gravida sed, blandit non neque. Suspendisse ac mauris urna. Vivamus lacus ipsum, tincidunt nec laoreet quis, convallis id purus. Ut vehicula lobortis erat in viverra. Ut ut tellus eget ipsum malesuada dignissim. Donec quis dolor erat, id adipiscing ipsum. Donec vitae sagittis turpis. 18 |

19 |
-------------------------------------------------------------------------------- /Demo/Resources/ArabicTest.html: -------------------------------------------------------------------------------- 1 |

Arabic Text

2 |

Here are some examples of Arabic and RTL text. You are welcome to add additional samples as I don't understand any RTL languages

3 |

Ligation

4 |

Something about Ligation, I have no idea what this is about

5 |

بِسۡمِ ٱللَّهِ ٱلرَّحۡمَٰنِ ٱلرَّحِيمِ

6 |

بسم الله الرحمن الرحيم

7 |

Justified RTL Text

8 |

Using justified alignment should cause the last line in a paragraph or lines that are too short to be right-aligned

9 |

بسم الله الرحمن الرحيم لرحمن بسم الله الرحمن الرحيم لرحمن الرحيم بسم الله الرحمن الرحيم لرحمن بسم الله الرحمن ا
لرحيم لرحمن الرحيم

-------------------------------------------------------------------------------- /Demo/Resources/CoreTextIssues.html: -------------------------------------------------------------------------------- 1 |

Core Text Bugs

2 |

Bold for Chinese Glyphs

3 |

This is a bug that was present before iOS 6, the Chinese glyphs in the following line would be bold if the locale was set to Chinese due to an incorrect entry in the global font cascade table. Filed as rdar://11262229

4 |

English and 中文 -- Chinese characters

5 | 6 |

Italic for Chinese Glyphs in Fallback

7 |

东方盖饭

8 |

东方盖饭

9 | 10 |

Extra space above lines with whitespace glyphs

11 |

Bla bla Bla bla Bla bla Bla bla Bla bla Bla bla Bla bla Bla bla Bla bla Bla bla Bla bla Bla bla Bla bla Bla bla Bla bla Bla bla Bla bla

12 |

Bla bla Bla bla Bla bla Bla bla Bla bla Bla bla Bla bla Bla bla Bla bla Bla bla Bla bla Bla bla Bla bla Bla bla Bla bla Bla bla Bla bla

-------------------------------------------------------------------------------- /Demo/Resources/CurrentTest.html: -------------------------------------------------------------------------------- 1 | 2 |

3 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 4 |

5 | 6 |

7 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 8 |

9 | 10 |

11 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 12 |

13 | 14 |

15 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 16 |

-------------------------------------------------------------------------------- /Demo/Resources/EmojiTest.html: -------------------------------------------------------------------------------- 1 | Here is a Smiley: 😄 and Mr. Poop: 💩 -------------------------------------------------------------------------------- /Demo/Resources/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cocoanetics/DTCoreText/ccbf88514fdc01bc613fe983b1516fb396ab65f1/Demo/Resources/Icon.png -------------------------------------------------------------------------------- /Demo/Resources/Icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cocoanetics/DTCoreText/ccbf88514fdc01bc613fe983b1516fb396ab65f1/Demo/Resources/Icon@2x.png -------------------------------------------------------------------------------- /Demo/Resources/Image.html: -------------------------------------------------------------------------------- 1 |

Image Handling

2 |

Some basic image handling has been implemented

3 |

Inline

4 |

So far images work inline, sitting on the line's baseline. There is a workaround in place that if an image is more than twice as high as the surrounding text it will be treated as it's own block.

5 |

Block

6 |

There is a known issue with images as blocks, outside of p tags.

7 | 8 |

An Image outside of P is treated as a paragraph

9 |

The previous image has float style. As a Workaround a newline is added after it until we can support floating in the layouting. This is done if the inline image is more than 5 times as large as the current font pixel size. This should allow small inline images, like smileys to stay in line, while most float images would probably be larger than this.

10 |

Supported Attributes

11 |
    12 |
  • width, height in pixels
  • 13 |
  • src with a local file path relative to the app bundle
  • 14 |
15 |

Supported Image Formats

16 |

According to Apple the following image formats are supported for use with UIImage:

17 |
    18 |
  • png
  • 19 |
  • tif, tiff
  • 20 |
  • jpeg, jpg
  • 21 |
  • gif
  • 22 |
  • bmp, bmpf
  • 23 |
  • ico
  • 24 |
  • cur
  • 25 |
  • xbm
  • 26 |
27 |

Vertical Alignment

28 |

Limited support for the CSS vertical-align tag exists

29 |

Baseline:

30 |

text-top:

31 |

text-bottom:

32 |

middle:

33 |

Data Source

34 |

Base64 encoded data SRC is supported, for example this red dot: Red dot

37 |

Another example:

Base64 encoded image 41 | 42 |

Remote Images

43 |

Images can also be loaded from remote URLs, even without specifying a size in the HTML. The code demonstrates how to update the DTTextAttachment's display size after download and triggering a re-layout.

44 | 45 | -------------------------------------------------------------------------------- /Demo/Resources/LineHeight.html: -------------------------------------------------------------------------------- 1 |

Line Height

2 |

This demonstrates setting of different line heights. Note: Internally this is achieved by setting the minimum and maximum line height in the paragraph style. The paragraph style line height multiplier is ignored.

3 |

Relative Line Heights

4 |

Font Size 25px; Line Height: normal

5 |

Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg

6 |

Font Size 25px; Line Height: 150%

7 |

Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg

8 |

Font Size 25px; Line Height: 2

9 |

Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg

10 | 11 |

Absolut Line Heights

12 | 13 |

Font Size 25px; Line Height: 15px

14 |

Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg

15 |

Font Size 25px; Line Height: 25px

16 |

Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg

17 |

Font Size 25px; Line Height: 40px

18 |

Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg Xg

19 | -------------------------------------------------------------------------------- /Demo/Resources/Objects.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 |

Custom Objects

10 |

This demonstrates usage of the <object> tag for embedding your own views

11 |

12 | or

13 |

These views are writting in HTML like this:

14 |
<object style="display:inline;margin-bottom:1em;" someColorParameter="red" width=100 height=20></object>
15 |

You provide your own custom view in the -attributedTextContentView:viewForAttachment:frame: method.

16 |
if (attachment isKindOfClass:[DTTextAttachmentObject class])
17 | {
18 |   // somecolorparameter has a HTML color
19 |   UIColor *someColor = [UIColor colorWithHTMLName:[attachment.attributes objectForKey:@"somecolorparameter"]];
20 | 
21 |   UIView *someView = [[UIView alloc] initWithFrame:frame];
22 |   someView.backgroundColor = someColor;
23 |   someView.layer.borderWidth = 1;
24 |   someView.layer.borderColor = [UIColor blackColor].CGColor;
25 | 
26 |   return someView;
27 | }
28 | 29 |

Object tags can access their childNodes

30 |
31 | 	<object height=100 width=100>
32 | 		<special stuff="bla" />
33 | 	</object>
34 | 	
35 | 36 | 37 | 38 | 39 | 40 |

When creating the custom view for this object you access the text attachment childNodes to get special information you have put there in addition to the attributes

41 | -------------------------------------------------------------------------------- /Demo/Resources/Oliver.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cocoanetics/DTCoreText/ccbf88514fdc01bc613fe983b1516fb396ab65f1/Demo/Resources/Oliver.jpg -------------------------------------------------------------------------------- /Demo/Resources/Oliver@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cocoanetics/DTCoreText/ccbf88514fdc01bc613fe983b1516fb396ab65f1/Demo/Resources/Oliver@2x.jpg -------------------------------------------------------------------------------- /Demo/Resources/README.html: -------------------------------------------------------------------------------- 1 |

NSAttributedString HTML Additions

2 |

Introduction

3 |

This project aims to duplicate the methods present on Mac OSX which allow creation of NSAttributedString from HTML code. 4 | This is useful for drawing simple rich text - like this document - without having to use a web view.

5 |

6 |

Hi! I'm Oliver and I appreciate your help!

7 |

Features

8 |

At present the following tags are supported:

9 |
  • Headers H1 - H6
  • Paragraphs: P
  • Bold: B, STRONG
  • Italic: I, EM
  • 10 |
  • Underline U
  • 11 |
  • Superscript SUP and Subscript SUB, e.g. e = mc2
  • 12 |
  • Strike Out DEL, e.g. Something Removed or STRIKE e.g. Something Striked
  • 13 |
  • FONT (face,color and size 1-7)
  • 14 |
  • Horizontal Rule HR (coloring via background-color style, simplified)
  • 15 |
  • Hyperlinks A (Formatting only, clickable as custom view)
  • 16 |
  • Unordered Lists LI
  • 17 |
  • Ordered Lists OL
18 |

Currently attributes are inherited from enclosed tags via brute force. I don't know if this is accurate.

19 |

Known Differences

20 |

In many aspects DTCoreText is superior to the Mac version of generating NSAttributedStrings from HTML. These become apparent in the MacUnitTest where the output from both is directly compared. I am summarizing them here for references.

21 |

In the following "Mac" means the initWithHTML: methods there, "DTCoreText" means DTCoreText's initWithHTML and/or DTHTMLAttributedStringBuilder

22 |
    23 |
  • Mac does not support the video tag, DTCoreText does.
  • 24 |
  • DTCoreText is able to synthesize small caps by putting all characters in upper case and using a second smaller font for lowercase characters.
  • 25 |
  • I suspect that Mac makes use of the -webkit-margin-* CSS styles for spacing the paragraphs, DTCoreText only uses the -webkit-margin-bottom and margin-bottom at present.
  • 26 |
  • Mac supports CSS following addresses, e.g. "ul ul" to change the list style for stacked lists. DTCoreText does not support that and so list bullets stay the same for multiple levels.
  • 27 |
28 | 29 |

Please Help!

30 |

If you find brief test cases where the created NSAttributedString differs from the version on OSX please send them to us!

31 |

Also there are many small things that you could help this project with. You can either implement these yourself or sponsor their development.

32 |

Follow @cocoanetics on Twitter

33 |

This code is covered by a BSD License. © 2011 Oliver Drobnik

34 | -------------------------------------------------------------------------------- /Demo/Resources/Subviews.html: -------------------------------------------------------------------------------- 1 |

Custom Subviews for Hyperlinks

2 |

You can use the provided DTLinkButton view as custom subview for glyph runs that make up a hyperlink. Multiple glyph runs in the same line are merged for one single subview. A hyperlink wrapping over several lines are multiple buttons which are linked via a GUID so that they highlight together

3 |

Here's an example involving multiple gylph runs resulting from Chinese characters: Here are some chinese Glyphs #草原牧马# 草原 making up a hyperlink and Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ut adipiscing massa. Aliquam vitae nibh ac dui lobortis congue in non dui. Duis hendrerit metus ut neque sodales sodales. Duis a elit nibh. Praesent risus tortor, rutrum ac lobortis in, malesuada ac turpis. Fusce rhoncus adipiscing eleifend. Nulla sed arcu erat. Cras aliquam turpis a purus vestibulum vehicula. Pellentesque at sapien id eros ornare rutrum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Morbi quis ipsum a ante porta sodales nec nec arcu. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Etiam ac massa diam. Nullam vehicula consequat lectus in fermentum. Praesent tortor leo, facilisis ut sagittis suscipit, consequat quis dui. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.

4 |

Here some underlined text and a hyperlink with superscripted text. As you can see the underline of the superscripted part is at a different height.

5 | 6 |

Follow @cocoanetics on Twitter

7 | -------------------------------------------------------------------------------- /Demo/Resources/TextBoxes.html: -------------------------------------------------------------------------------- 1 |

Text Boxes

2 |

Block-Level tags (like P or DIV) can have a padding and background color.

3 |

Note: Only one level of boxing is properly supported. This is a crude workaround as CoreText does not support NSTextBlock on iOS.

4 |
<p style="background-color:yellow;padding:20px;">...</p>
5 |

By default the background is rectangle drawn for the entire width of the content view. There is a delegate method which you can override to do your own drawing. For example a stretchable UIImage. Or a rounded rectangle as shown here.

6 |

7 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 8 |

9 |

Some test cases

10 |

Before the list with 10px padding

11 |
    12 |
  • These items
  • have a fixed line height of 50px
  • Note: The line-height becomes the ascender. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
13 |

After the list with 25 px padding

14 | -------------------------------------------------------------------------------- /Demo/Resources/Video.html: -------------------------------------------------------------------------------- 1 |

Video

2 |

HTML5 Video

3 |

This demonstrates support for the HTML5 VIDEO (once it gets implemented)

4 | 7 | 8 | 9 |

To Do

10 |
    11 |
  • Add Rotation when video in fullscreen - there's a bug causing the navigation bar to shift under the status bar if Rotation is enabled
  • 12 |
  • Support for the different kinds of attributes to map to properties of media player
  • 13 |
  • Hide text contained in recognized tags
  • 14 |
15 | 16 |

YouTube in IFRAME

17 | -------------------------------------------------------------------------------- /Demo/Resources/XB Niloofar.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cocoanetics/DTCoreText/ccbf88514fdc01bc613fe983b1516fb396ab65f1/Demo/Resources/XB Niloofar.ttf -------------------------------------------------------------------------------- /Demo/Resources/XB NiloofarBd.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cocoanetics/DTCoreText/ccbf88514fdc01bc613fe983b1516fb396ab65f1/Demo/Resources/XB NiloofarBd.ttf -------------------------------------------------------------------------------- /Demo/Resources/css.css: -------------------------------------------------------------------------------- 1 | h1{ 2 | margin: 0px; 3 | direction:rtl; 4 | text-align:right; 5 | } 6 | .s2{ 7 | color: #000000; 8 | font-size: 68.7500%; 9 | font-style: normal; 10 | font-variant: normal; 11 | font-weight: normal; 12 | letter-spacing: 0.0000em; 13 | margin-bottom: 2.3148%; 14 | margin-top: 0.0000%; 15 | padding-left: 0.0000%; 16 | padding-right: 0.0000%; 17 | text-align: left; 18 | text-decoration: none; 19 | text-indent: 0.0000%; 20 | text-transform: none; 21 | } 22 | .s18{ 23 | font-size: 81.2500%; 24 | text-align: center; 25 | } 26 | .c10{ 27 | background: #FFFFFF; 28 | } 29 | -------------------------------------------------------------------------------- /Demo/Resources/icon_smile.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cocoanetics/DTCoreText/ccbf88514fdc01bc613fe983b1516fb396ab65f1/Demo/Resources/icon_smile.gif -------------------------------------------------------------------------------- /Demo/Resources/styles.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

CSS Styles Support

4 |

Currently CSS styling is supported inline in tags, and via simple rules.

5 |

For example:

6 |

<p style="color:red; font-size: 30px;text-decoration:underline;">Some fancy text</p>

7 |

Some fancy text

8 |

This way you can affect the way hyperlinks are decorated: @cocoanetics versus @cocoanetics

9 | 10 |

CSS Rules

11 | 12 |

One or more style blocks are merged into a style sheet. Multiple matching styles are combined in this order, later styles overriding earlier ones.

13 |
    14 |
  • Tag Name
  • 15 |
  • Class Name (multiple classes possible)
  • 16 |
  • Class Name + Tag Name
  • 17 |
  • Tag ID
  • 18 |
  • Local Style attribute of Tag
  • 19 |
20 |

Not yet implemented are pseudo-selectors (first child).

21 | 22 |

Supported Attributes

23 |
    24 |
  • color - names (red) or hex (#FF0000) or rbg rgb(255, 0, 0);
  • 25 |
  • decoration - underline, line-through
  • 26 |
  • font-size - specified in pixels (12px)
  • 27 |
  • font-family - to specify the postscript name of a family like Courier
  • 28 |
  • font-style - normal, inherit, italic, oblique
  • 29 |
  • font-weight - normal, bold
  • 30 |
  • letter-spacing - tighter or wider
  • 31 |
32 | 33 |

Font Families

34 |
35 |

serif

36 |

sans-serif

37 |

monospace

38 |

cursive

39 |

fantasy

40 |
41 | 42 |

Text Shadows

43 |

The text-shadow property is supported.

44 |

Text with Shadow

45 |

Embossed

46 |

Glowing

47 |

Multiple Shadows

50 |

Text with Shadow

51 |

OUTLINE

52 | 53 | 54 | -------------------------------------------------------------------------------- /Demo/Source/AutoLayoutDemoViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // AutoLayoutDemoViewController.h 3 | // DTCoreText 4 | // 5 | // Created by David Whetstone on 5/8/15. 6 | // Copyright (c) 2015 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface AutoLayoutDemoViewController : UIViewController 13 | @property (nonatomic, strong) id fileName; 14 | @end -------------------------------------------------------------------------------- /Demo/Source/AutoLayoutDemoViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // AutoLayoutDemoViewController.m 3 | // DTCoreText 4 | // 5 | // Created by David Whetstone on 5/8/15. 6 | // Copyright (c) 2015 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "AutoLayoutDemoViewController.h" 10 | 11 | @interface AutoLayoutDemoViewController () 12 | 13 | @property (nonatomic, DT_WEAK_PROPERTY) IBOutlet DTAttributedTextContentView *textView; 14 | @end 15 | 16 | @implementation AutoLayoutDemoViewController 17 | 18 | - (void)viewDidLoad { 19 | 20 | [super viewDidLoad]; 21 | 22 | NSString *html = @"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; 23 | NSData *data = [html dataUsingEncoding:NSUTF8StringEncoding]; 24 | self.textView.attributedString = [[NSAttributedString alloc] initWithHTMLData:data documentAttributes:NULL]; 25 | } 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /Demo/Source/CoreTextDemoAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // DemoAppDelegate.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 1/9/11. 6 | // Copyright 2011 Drobnik.com. All rights reserved. 7 | // 8 | 9 | @class DemoTextViewController; 10 | 11 | @interface CoreTextDemoAppDelegate : NSObject 12 | { 13 | UIWindow *_window; 14 | UINavigationController *_navigationController; 15 | } 16 | 17 | @property (nonatomic, strong) UIWindow *window; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Demo/Source/CoreTextDemoAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // DemoAppDelegate.m 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 1/9/11. 6 | // Copyright 2011 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "CoreTextDemoAppDelegate.h" 10 | #import "DemoSnippetsViewController.h" 11 | 12 | #import "DTCoreText.h" 13 | #import "UIView+DTDebug.h" 14 | 15 | @implementation CoreTextDemoAppDelegate 16 | 17 | @synthesize window = _window; 18 | 19 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 20 | { 21 | // register a custom class for a tag 22 | [DTTextAttachment registerClass:[DTObjectTextAttachment class] forTagName:@"oliver"]; 23 | 24 | // preload font matching table 25 | [DTCoreTextFontDescriptor asyncPreloadFontLookupTable]; 26 | 27 | // for debugging, we make sure that UIView methods are only called on main thread 28 | [UIView toggleViewMainThreadChecking]; 29 | 30 | // Create window 31 | _window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 32 | 33 | // Create the view controller 34 | DemoSnippetsViewController *snippetsViewController = [[DemoSnippetsViewController alloc] init]; 35 | _navigationController = [[UINavigationController alloc] initWithRootViewController:snippetsViewController]; 36 | 37 | // Display the window 38 | _window.rootViewController = _navigationController; 39 | [_window makeKeyAndVisible]; 40 | 41 | return YES; 42 | } 43 | 44 | 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /Demo/Source/DemoAboutViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // DemoAboutViewController.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 3/4/13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DemoAboutViewController : UIViewController 12 | 13 | @property (nonatomic, DT_WEAK_PROPERTY) IBOutlet DTAttributedTextView *attributedTextView; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Demo/Source/DemoAboutViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // DemoAboutViewController.m 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 3/4/13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DemoAboutViewController.h" 10 | 11 | @interface DemoAboutViewController () 12 | 13 | @end 14 | 15 | @implementation DemoAboutViewController 16 | 17 | - (id)init 18 | { 19 | self = [super initWithNibName:@"DemoAboutViewController" bundle:nil]; 20 | if (self) 21 | { 22 | // Custom initialization 23 | self.navigationItem.title = @"About DTCoreText"; 24 | } 25 | return self; 26 | } 27 | 28 | - (void)viewDidLoad 29 | { 30 | [super viewDidLoad]; 31 | // Do any additional setup after loading the view from its nib. 32 | 33 | NSString *path = [[NSBundle mainBundle] pathForResource:@"About" ofType:@"html"]; 34 | NSData *data = [NSData dataWithContentsOfFile:path]; 35 | 36 | NSDictionary *options; 37 | 38 | if (@available(iOS 13.0, *)) { 39 | options = @{DTDefaultTextColor: [UIColor labelColor], DTUseiOS6Attributes: @(YES)}; 40 | } else { 41 | options = @{DTDefaultTextColor: [UIColor blackColor], DTUseiOS6Attributes: @(YES)}; 42 | } 43 | 44 | NSAttributedString *attributedString = [[NSAttributedString alloc] initWithHTMLData:data options:options documentAttributes:NULL]; 45 | 46 | self.attributedTextView.attributedString = attributedString; 47 | self.attributedTextView.contentInset = UIEdgeInsetsMake(10, 10, 10, 10); 48 | } 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /Demo/Source/DemoAboutViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Demo/Source/DemoSnippetsViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // DemoSnippetsViewController.h 3 | // DTCoreText 4 | // 5 | // Created by Sam Soffes on 1/14/11. 6 | // Copyright 2011 Drobnik.com. All rights reserved. 7 | // 8 | 9 | @interface DemoSnippetsViewController : UITableViewController { 10 | 11 | NSArray *_snippets; 12 | 13 | NSCache *cellCache; 14 | } 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Demo/Source/DemoTextViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // DemoTextViewController.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 1/9/11. 6 | // Copyright 2011 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTAttributedTextView.h" 10 | #import "DTLazyImageView.h" 11 | 12 | @interface DemoTextViewController : UIViewController 13 | 14 | @property (nonatomic, strong) NSString *fileName; 15 | 16 | @property (nonatomic, strong) NSURL *lastActionLink; 17 | 18 | @property (nonatomic, strong) NSURL *baseURL; 19 | 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /Demo/Source/DemoWebVideoView.h: -------------------------------------------------------------------------------- 1 | // 2 | // DemoWebVideoView.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 8/5/11. 6 | // Copyright 2011 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @class DemoWebVideoView; 13 | @class DTTextAttachment; 14 | 15 | /** 16 | Protocol for delegates of 17 | */ 18 | @protocol DemoWebVideoViewDelegate 19 | 20 | @optional 21 | 22 | /** 23 | Asks the delegate if an external URL may be opened 24 | @param videoView The web video view 25 | @param url The external URL that is asked to be opened 26 | @returns `YES` if the app may be left to open the external URL 27 | */ 28 | 29 | - (BOOL)videoView:(DemoWebVideoView *)videoView shouldOpenExternalURL:(NSURL *)url; 30 | 31 | @end 32 | 33 | 34 | /** 35 | The class represents a custom subview for use in to represent an embedded video. 36 | 37 | Embedded videos work by loading the video URL in a web view which iOS then replaces with the built-in media player view. The URL of the embed script depends on the service and needs to be added to the webView:shouldStartLoadWithRequest:navigationType:. You want to allow the URL for the embed script, but disallow all other requests which for example occur if a user taps on the YouTube logo. If you were to allow this type of navigation then the YouTube website would be loaded in the video view. For these scenarios there is the videoView:shouldOpenExternalURL: method in DemoWebVideoViewDelegate. If you respond with `YES` (which is default if the method is not implemented) then the URL will be opened in Safari. 38 | 39 | To add additional video services please add them in the mentioned location and submit a pull request for the addition. 40 | */ 41 | @interface DemoWebVideoView : UIView 42 | 43 | /** 44 | The delegate of the video view 45 | */ 46 | @property (nonatomic, DT_WEAK_PROPERTY) id delegate; 47 | 48 | /** 49 | The text attachment representing an embedded video. 50 | */ 51 | @property (nonatomic, strong) DTTextAttachment *attachment; 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /Demo/Source/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 1/9/11. 6 | // Copyright 2011 Drobnik.com. All rights reserved. 7 | // 8 | 9 | int main(int argc, char *argv[]) { 10 | 11 | @autoreleasepool { 12 | int retVal = UIApplicationMain(argc, argv, nil, @"CoreTextDemoAppDelegate"); 13 | return retVal; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Documentation/DTCoreText_Demo_App.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cocoanetics/DTCoreText/ccbf88514fdc01bc613fe983b1516fb396ab65f1/Documentation/DTCoreText_Demo_App.png -------------------------------------------------------------------------------- /Documentation/DTCoreText_Linker_Flags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cocoanetics/DTCoreText/ccbf88514fdc01bc613fe983b1516fb396ab65f1/Documentation/DTCoreText_Linker_Flags.png -------------------------------------------------------------------------------- /Documentation/DTCoreText_Reference.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cocoanetics/DTCoreText/ccbf88514fdc01bc613fe983b1516fb396ab65f1/Documentation/DTCoreText_Reference.png -------------------------------------------------------------------------------- /Documentation/DTCoreText_Search_Paths.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cocoanetics/DTCoreText/ccbf88514fdc01bc613fe983b1516fb396ab65f1/Documentation/DTCoreText_Search_Paths.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, Oliver Drobnik All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | - Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 9 | - Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 17 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 20 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.3 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "DTCoreText", 7 | platforms: [ 8 | .iOS(.v9), //.v8 - .v13 9 | .macOS(.v10_10), //.v10_10 - .v10_15 10 | .tvOS(.v9), //.v9 - .v13 11 | ], 12 | products: [ 13 | .library( 14 | name: "DTCoreText", 15 | // type: .dynamic, 16 | targets: ["DTCoreText"]) 17 | ], 18 | dependencies: [ 19 | .package(url: "https://github.com/Cocoanetics/DTFoundation.git", from: "1.7.15"), 20 | ], 21 | targets: [ 22 | .target( 23 | name: "DTCoreText", 24 | dependencies: [ 25 | .product(name: "DTFoundation", package: "DTFoundation"), 26 | ], 27 | path: "Core", 28 | exclude: ["DTCoreText-Info.plist", "DTCoreText-Prefix.pch"], 29 | resources: [ 30 | .copy("Source/default.css")] 31 | ), 32 | .testTarget( 33 | name: "DTCoreTextTests", 34 | dependencies: ["DTCoreText"], 35 | path: "Test/Source", 36 | resources: [ 37 | .copy("Resources/AppleConverted.html"), 38 | .copy("Resources/CSSCascading.html"), 39 | .copy("Resources/CSSCascading.plist"), 40 | .copy("Resources/CSSOOMCrash.html"), 41 | .copy("Resources/CSSOOMCrash.plist"), 42 | .copy("Resources/CustomFont.plist"), 43 | .copy("Resources/Emoji.html"), 44 | .copy("Resources/Empty_and_Unclosed_Paragraphs.html"), 45 | .copy("Resources/EmptyLinesAndFontAttribute.html"), 46 | .copy("Resources/KeepMeTogether.html"), 47 | .copy("Resources/ListItemBulletColorAndFont.html"), 48 | .copy("Resources/ListTest.plist"), 49 | .copy("Resources/MalformedURL.html"), 50 | .copy("Resources/NavTag.html"), 51 | .copy("Resources/NavTag.plist"), 52 | .copy("Resources/PreWhitespace.html"), 53 | .copy("Resources/PreWhitespace.plist"), 54 | .copy("Resources/RetinaDataURL.html"), 55 | .copy("Resources/RTL.html"), 56 | .copy("Resources/SpaceBetweenUnderlines.html"), 57 | .copy("Resources/Video.plist"), 58 | .copy("Resources/WarAndPeace.plist"), 59 | .copy("Resources/WhitespaceFollowingImagePromotedToParagraph.html"), 60 | .copy("Resources/Oliver.jpg"), 61 | .copy("Resources/Oliver@2x.jpg"), 62 | ] 63 | ) 64 | ] 65 | ) 66 | -------------------------------------------------------------------------------- /Readme.markdown: -------------------------------------------------------------------------------- 1 | DTCoreText 2 | ========== 3 | 4 | This project aims to duplicate the methods present on Mac OSX which allow creation of `NSAttributedString` from HTML code on iOS. 5 | 6 | The project covers two broad areas: 7 | 8 | 1. **Layouting** - Interfacing with CoreText, generating attributed strings from HTML code 9 | 2. **User Interface** - UI-related classes render these objects, specifically `DTAttributedTextView`, `DTAttributedLabel` and `DTAttributedTextCell`. 10 | 11 | This is useful for drawing simple rich text like any HTML document without having to use a web view. For text selection and highlighting (as you might need for an Editor or Reader) there is the commercial **DTRichTextEditor** component which can be purchased in the [Cocoanetics Parts Store](http://www.cocoanetics.com/parts/dtrichtexteditor/). 12 | 13 | Documentation 14 | ------------- 15 | 16 | Documentation can be [browsed online](https://docs.cocoanetics.com/DTCoreText) or installed in your Xcode Organizer via the [Atom Feed URL](https://docs.cocoanetics.com/DTCoreText/DTCoreText.atom). 17 | 18 | A [Q&A](http://www.cocoanetics.com/2011/08/nsattributedstringhtml-qa/) answers some frequently asked questions. 19 | 20 | Changelog: [GitHub Releases](https://github.com/Cocoanetics/DTCoreText/releases) 21 | 22 | There is also a [Programming Guide](Documentation/Programming%20Guide-template.markdown) with a set of solutions to common problems. 23 | 24 | Follow [@cocoanetics](http://twitter.com/cocoanetics) on Twitter or subscribe to the [Cocoanetics Blog](http://www.cocoanetics.com) for news and updates. 25 | 26 | License 27 | ------- 28 | 29 | It is open source and covered by a standard 2-clause BSD license. That means you have to mention *Cocoanetics* as the original author of this code and reproduce the LICENSE text inside your app. 30 | 31 | You can purchase a [Non-Attribution-License](https://www.cocoanetics.com/order/?product_id=DTCoreText) for 75 Euros for not having to include the LICENSE text. 32 | 33 | We also accept sponsorship for specific enhancements which you might need. Please [contact us via email](mailto:oliver@cocoanetics.com?subject=DTCoreText) for inquiries. 34 | -------------------------------------------------------------------------------- /Test/MacUnitTest-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Test/MacUnitTest-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'MacUnitTest' target in the 'MacUnitTest' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #import 8 | #import 9 | #import 10 | #endif 11 | 12 | #define CGSizeValue sizeValue 13 | #define valueWithCGSize valueWithSize 14 | -------------------------------------------------------------------------------- /Test/Resources/AppleConverted.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 14 |

many     spaces

15 | 16 | -------------------------------------------------------------------------------- /Test/Resources/CSSCascading.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 |
65 |
66 |
67 |
68 | me 69 | buzz owzers 70 |
71 | Meow 72 |

this is a test of by tag name styles targeted by class on an ancestor.

73 |

i'm gray text

74 |
75 |
76 |
77 | 78 | -------------------------------------------------------------------------------- /Test/Resources/CSSCascading.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SkipUnitTest 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Test/Resources/CSSOOMCrash.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SkipUnitTest 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Test/Resources/CustomFont.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IgnoreCase 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Test/Resources/Emoji.html: -------------------------------------------------------------------------------- 1 | 2 |

FYI emoji work just fine, simply encode them as hex strings. For 3 | example, 🍁 (&#x1F341;) correctly 4 | displays a maple leaf. Even double-character emoji like 5 | 🇰🇷 (&#x1F1F0; &#x1F1F7;) display 6 | correctly.

-------------------------------------------------------------------------------- /Test/Resources/EmptyLinesAndFontAttribute.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 14 |

a

15 |

16 |

17 | 18 | -------------------------------------------------------------------------------- /Test/Resources/Empty_and_Unclosed_Paragraphs.html: -------------------------------------------------------------------------------- 1 | 2 |

Next paragraph empty

3 |

4 |

Next paragraph missing closing (auto-closed, resulting in one empty paragraph)

5 |

Fin

-------------------------------------------------------------------------------- /Test/Resources/KeepMeTogether.html: -------------------------------------------------------------------------------- 1 | Keep me together -------------------------------------------------------------------------------- /Test/Resources/ListItemBulletColorAndFont.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 |
13 | 17 |
18 | 19 | -------------------------------------------------------------------------------- /Test/Resources/ListTest.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IgnoreNonAlphanumericCharacters 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Test/Resources/MalformedURL.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Forgot Password? -------------------------------------------------------------------------------- /Test/Resources/NavTag.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Test/Resources/NavTag.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SkipUnitTest 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Test/Resources/Oliver.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cocoanetics/DTCoreText/ccbf88514fdc01bc613fe983b1516fb396ab65f1/Test/Resources/Oliver.jpg -------------------------------------------------------------------------------- /Test/Resources/Oliver@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cocoanetics/DTCoreText/ccbf88514fdc01bc613fe983b1516fb396ab65f1/Test/Resources/Oliver@2x.jpg -------------------------------------------------------------------------------- /Test/Resources/PreWhitespace.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

some text

4 |
5 | 	
6 | 	source code     123
7 | 	123 123
8 | 
9 |

more text

-------------------------------------------------------------------------------- /Test/Resources/PreWhitespace.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IgnoreNonAlphanumericCharacters 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Test/Resources/RTL.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |

RTL via tag attribute

7 |

RTA via style attribute

8 | 9 | -------------------------------------------------------------------------------- /Test/Resources/SpaceBetweenUnderlines.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |

a b

7 | 8 | -------------------------------------------------------------------------------- /Test/Resources/Video.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SkipUnitTest 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Test/Resources/WarAndPeace.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SkipUnitTest 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Test/Resources/WhitespaceFollowingImagePromotedToParagraph.html: -------------------------------------------------------------------------------- 1 | 2 |

1

3 | 4 |

2

-------------------------------------------------------------------------------- /Test/Source/DTCSSListStyleTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // DTCSSListStyleTest.m 3 | // DTCoreText 4 | // 5 | // Created by Ryan Johnson on 2/19/14. 6 | // Copyright (c) 2014 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @import DTCoreText; 12 | 13 | @interface DTCSSListStyleTest : XCTestCase 14 | 15 | @end 16 | 17 | @implementation DTCSSListStyleTest 18 | 19 | - (void)testNSCodingEqual { 20 | NSDictionary *styles = @{@"list-style-type":@"none", @"list-style-position":@"inherit"}; 21 | DTCSSListStyle *listStyle = [[DTCSSListStyle alloc] initWithStyles:styles]; 22 | 23 | NSData *listStyleData = [NSKeyedArchiver archivedDataWithRootObject:listStyle]; 24 | DTCSSListStyle *unarchivedListStyle = [NSKeyedUnarchiver unarchiveObjectWithData:listStyleData]; 25 | 26 | XCTAssertTrue([listStyle isEqualToListStyle:unarchivedListStyle], @"Unarchived list styles should be equal to original"); 27 | } 28 | 29 | - (void)testNSCodingNotEqual { 30 | NSDictionary *styles1 = @{@"list-style-type":@"none", @"list-style-position":@"inherit"}; 31 | DTCSSListStyle *listStyle1 = [[DTCSSListStyle alloc] initWithStyles:styles1]; 32 | 33 | NSDictionary *styles2 = @{@"list-style-type":@"circle", @"list-style-position":@"inherit"}; 34 | DTCSSListStyle *listStyle2 = [[DTCSSListStyle alloc] initWithStyles:styles2]; 35 | 36 | XCTAssertFalse([listStyle1 isEqualToListStyle:listStyle2], @"Sanity check"); 37 | 38 | NSData *listStyle1Data = [NSKeyedArchiver archivedDataWithRootObject:listStyle1]; 39 | DTCSSListStyle *unarchivedListStyle1 = [NSKeyedUnarchiver unarchiveObjectWithData:listStyle1Data]; 40 | 41 | XCTAssertFalse([unarchivedListStyle1 isEqualToListStyle:listStyle2], @"Different list styles should remain different"); 42 | 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /Test/Source/DTCSSStylesheetTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTCSSStyleSheetTest.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 20.12.12. 6 | // Copyright (c) 2012 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DTCSSStyleSheetTest : XCTestCase 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Test/Source/DTCoreTextLayoutFrameTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // DTCoreTextLayoutFrameTest.m 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 14.11.13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTCoreTextTestCase.h" 10 | 11 | #import 12 | 13 | @import DTCoreText; 14 | 15 | @interface DTCoreTextLayoutFrameTest : DTCoreTextTestCase 16 | 17 | @end 18 | 19 | @implementation DTCoreTextLayoutFrameTest 20 | 21 | - (void)testVariableHeight 22 | { 23 | NSAttributedString *attributedString = [super attributedStringFromHTMLString:@"Some bold text" options:nil]; 24 | 25 | DTCoreTextLayouter *layouter = [[DTCoreTextLayouter alloc] initWithAttributedString:attributedString]; 26 | 27 | CGRect maxRect = CGRectMake(10, 20, 1024, CGFLOAT_HEIGHT_UNKNOWN); 28 | NSRange entireString = NSMakeRange(0, [attributedString length]); 29 | DTCoreTextLayoutFrame *layoutFrame = [layouter layoutFrameWithRect:maxRect range:entireString]; 30 | 31 | CGSize sizeNeeded = [layoutFrame frame].size; 32 | CGSize sizeExpected = CGSizeMake(1024, 16); 33 | 34 | XCTAssertEqual(sizeNeeded.height, sizeExpected.height, @"Size incorrect"); 35 | XCTAssertEqual(sizeNeeded.width, sizeExpected.width, @"Size incorrect"); 36 | } 37 | 38 | - (void)testVariableHeightAndWidth 39 | { 40 | NSAttributedString *attributedString = [super attributedStringFromHTMLString:@"Some bold text" options:nil]; 41 | 42 | DTCoreTextLayouter *layouter = [[DTCoreTextLayouter alloc] initWithAttributedString:attributedString]; 43 | 44 | CGRect maxRect = CGRectMake(10, 20, CGFLOAT_WIDTH_UNKNOWN, CGFLOAT_HEIGHT_UNKNOWN); 45 | NSRange entireString = NSMakeRange(0, [attributedString length]); 46 | DTCoreTextLayoutFrame *layoutFrame = [layouter layoutFrameWithRect:maxRect range:entireString]; 47 | 48 | CGSize sizeNeeded = [layoutFrame frame].size; 49 | CGSize sizeExpected = CGSizeMake(76, 16); 50 | 51 | XCTAssertEqual(sizeNeeded.height, sizeExpected.height, @"Size incorrect"); 52 | XCTAssertEqual(sizeNeeded.width, sizeExpected.width, @"Size incorrect"); 53 | } 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /Test/Source/DTCoreTextParagraphStyleTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTCoreTextParagraphStyleTest.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 2/25/13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @import DTCoreText; 12 | 13 | @interface DTCoreTextParagraphStyleTest : XCTestCase 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Test/Source/DTCoreTextTestCase.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTCoreTextTestCase.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 25.09.13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** 12 | Specialized test case class for testing DTCoreText issues 13 | */ 14 | @interface DTCoreTextTestCase : XCTestCase 15 | 16 | /** 17 | @name Utilities 18 | */ 19 | 20 | /** 21 | Parse the HTML in the file with the give name 22 | @param testFileName The name of the test file in the OCTest bundle 23 | @returns the attributed string, generated with DTCoreText 24 | */ 25 | - (NSAttributedString *)attributedStringFromTestFileName:(NSString *)testFileName; 26 | 27 | /** 28 | Parses the HTML in the given string with the optional options 29 | @param HTMLString The HTML string to parse with DTCoreText 30 | @param options The parsing options 31 | @returns the attributed string, generated with DTCoreText 32 | */ 33 | - (NSAttributedString *)attributedStringFromHTMLString:(NSString *)HTMLString options:(NSDictionary *)options; 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /Test/Source/DTCoreTextTestCase.m: -------------------------------------------------------------------------------- 1 | // 2 | // DTCoreTextTestCase.m 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 25.09.13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTCoreTextTestCase.h" 10 | #import 11 | 12 | @import DTCoreText; 13 | 14 | @implementation DTCoreTextTestCase 15 | 16 | - (NSBundle*) testBundle { 17 | #if SWIFT_PACKAGE 18 | return SWIFTPM_MODULE_BUNDLE; 19 | #else 20 | return [NSBundle bundleForClass:[self class]]; 21 | #endif 22 | } 23 | 24 | - (NSAttributedString *)attributedStringFromTestFileName:(NSString *)testFileName 25 | { 26 | NSString *path = [[self testBundle] pathForResource:testFileName ofType:@"html"]; 27 | NSData *data = [NSData dataWithContentsOfFile:path]; 28 | 29 | DTHTMLAttributedStringBuilder *builder = [[DTHTMLAttributedStringBuilder alloc] initWithHTML:data options:nil documentAttributes:NULL]; 30 | return [builder generatedAttributedString]; 31 | } 32 | 33 | - (NSAttributedString *)attributedStringFromHTMLString:(NSString *)HTMLString options:(NSDictionary *)options 34 | { 35 | NSData *data = [HTMLString dataUsingEncoding:NSUTF8StringEncoding]; 36 | 37 | // set the base URL so that resources are found in the resource bundle 38 | NSURL *baseURL = [[self testBundle] resourceURL]; 39 | 40 | NSMutableDictionary *mutableOptions = [[NSMutableDictionary alloc] initWithDictionary:options]; 41 | mutableOptions[NSBaseURLDocumentOption] = baseURL; 42 | 43 | // register a custom class for a tag 44 | [DTTextAttachment registerClass:[DTObjectTextAttachment class] forTagName:@"oliver"]; 45 | 46 | DTHTMLAttributedStringBuilder *builder = [[DTHTMLAttributedStringBuilder alloc] initWithHTML:data options:mutableOptions documentAttributes:NULL]; 47 | return [builder generatedAttributedString]; 48 | } 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /Test/Source/DTHTMLAttributedStringBuilderTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTHTMLAttributedStringBuilderTest.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 25.12.12. 6 | // Copyright (c) 2012 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTCoreTextTestCase.h" 10 | 11 | @interface DTHTMLAttributedStringBuilderTest : DTCoreTextTestCase 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Test/Source/DTHTMLElementTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTHTMLElementTest.h 3 | // DTCoreText 4 | // 5 | // Created by Hubert SARRET on 11/04/13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DTHTMLElementTest : XCTestCase 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Test/Source/DTHTMLWriterTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTHTMLWriterTest.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 11.07.13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTCoreTextTestCase.h" 10 | 11 | /** 12 | Unit tests related to DTHTMLWriter 13 | */ 14 | @interface DTHTMLWriterTest : DTCoreTextTestCase 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Test/Source/DTTextBlockTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTTextBlockTest.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 9/29/13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTCoreTextTestCase.h" 10 | 11 | @interface DTTextBlockTest : DTCoreTextTestCase 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Test/Source/MacUnitTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // MacUnitTest.h 3 | // MacUnitTest 4 | // 5 | // Created by Oliver Drobnik on 22.01.12. 6 | // Copyright (c) 2012 Drobnik KG. All rights reserved. 7 | // 8 | 9 | @import XCTest; 10 | 11 | @interface MacUnitTest : XCTestCase 12 | 13 | - (void)internalTestCaseWithURL:(NSURL *)URL withTempPath:(NSString *)tempPath; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Test/Source/NSAttributedStringDTCoreTextTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSAttributedStringDTCoreTextTest.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 30.09.13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "DTCoreTextTestCase.h" 10 | 11 | @interface NSAttributedStringDTCoreTextTest : DTCoreTextTestCase 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Test/Source/NSAttributedStringHTMLTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSAttributedStringHTMLTest.h 3 | // DTCoreText 4 | // 5 | // Created by Claus Broch on 11/01/11. 6 | // Copyright 2011 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSAttributedStringHTMLTest : XCTestCase { 12 | 13 | } 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Test/Source/NSMutableAttributedStringHTMLTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSMutableAttributedStringHTMLTest.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 6/25/13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSMutableAttributedStringHTMLTest : XCTestCase 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Test/Source/NSNumberRomanNumeralsTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSNumberRomanNumeralsTest.m 3 | // DTCoreText 4 | // 5 | // Created by Kai Maschke on 26.07.16. 6 | // Copyright © 2016 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface NSNumberRomanNumeralsTest : XCTestCase 13 | 14 | @end 15 | 16 | @implementation NSNumberRomanNumeralsTest 17 | 18 | - (void)testRomanNumeralConversion { 19 | XCTAssertEqualObjects([@(1) romanNumeral], @"I"); 20 | XCTAssertEqualObjects([@(5) romanNumeral], @"V"); 21 | XCTAssertEqualObjects([@(9) romanNumeral], @"IX"); 22 | XCTAssertEqualObjects([@(10) romanNumeral], @"X"); 23 | XCTAssertEqualObjects([@(11) romanNumeral], @"XI"); 24 | XCTAssertEqualObjects([@(49) romanNumeral], @"XLIX"); 25 | XCTAssertEqualObjects([@(880) romanNumeral], @"DCCCLXXX"); 26 | XCTAssertEqualObjects([@(3999) romanNumeral], @"MMMCMXCIX"); 27 | } 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /Test/Source/NSStringCSSTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSStringCSSTest.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 1/5/13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSStringCSSTest : XCTestCase 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Test/Source/NSStringHTMLTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSStringHTMLTest.h 3 | // DTCoreText 4 | // 5 | // Created by Claus Broch on 11/01/11. 6 | // Copyright 2011 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSStringHTMLTest : XCTestCase { 12 | 13 | } 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Test/Source/NSStringParagraphTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSStringParagraphTest.h 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 11.04.13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSStringParagraphTest : XCTestCase 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Test/Source/NSStringParagraphTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSStringParagraphTest.m 3 | // DTCoreText 4 | // 5 | // Created by Oliver Drobnik on 11.04.13. 6 | // Copyright (c) 2013 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "NSStringParagraphTest.h" 10 | 11 | @import DTCoreText; 12 | 13 | @implementation NSStringParagraphTest 14 | 15 | - (void)testParagraphFinding 16 | { 17 | NSString *string = @"abc\ndef\n\nghi"; 18 | 19 | NSRange range = NSMakeRange(3, 1); 20 | NSUInteger begIndex; 21 | NSUInteger endIndex; 22 | 23 | // range on NL character 24 | NSRange paragraphRange = [string rangeOfParagraphsContainingRange:range parBegIndex:&begIndex parEndIndex:&endIndex]; 25 | NSRange expectedRange = NSMakeRange(0, 4); 26 | XCTAssertTrue(NSEqualRanges(paragraphRange, expectedRange), @"First range"); 27 | XCTAssertEqual(begIndex, (NSUInteger)0, @"First range start index"); 28 | XCTAssertEqual(endIndex, (NSUInteger)4, @"First range end index"); 29 | 30 | // empty range 31 | range = NSMakeRange(3, 0); 32 | paragraphRange = [string rangeOfParagraphsContainingRange:range parBegIndex:&begIndex parEndIndex:&endIndex]; 33 | expectedRange = NSMakeRange(0, 4); 34 | XCTAssertTrue(NSEqualRanges(paragraphRange, expectedRange), @"Second range"); 35 | XCTAssertEqual(begIndex, (NSUInteger)0, @"Second range start index"); 36 | XCTAssertEqual(endIndex, (NSUInteger)4, @"Second range end index"); 37 | 38 | // test empty paragraph 39 | range = NSMakeRange(8, 1); 40 | paragraphRange = [string rangeOfParagraphsContainingRange:range parBegIndex:&begIndex parEndIndex:&endIndex]; 41 | expectedRange = NSMakeRange(8, 1); 42 | XCTAssertTrue(NSEqualRanges(paragraphRange, expectedRange), @"Second range"); 43 | XCTAssertEqual(begIndex, (NSUInteger)8, @"Second range start index"); 44 | XCTAssertEqual(endIndex, (NSUInteger)9, @"Second range end index"); 45 | 46 | // range at end of string 47 | range = NSMakeRange(9, 2); 48 | paragraphRange = [string rangeOfParagraphsContainingRange:range parBegIndex:&begIndex parEndIndex:&endIndex]; 49 | expectedRange = NSMakeRange(9, 3); 50 | XCTAssertTrue(NSEqualRanges(paragraphRange, expectedRange), @"Third range"); 51 | XCTAssertEqual(begIndex, (NSUInteger)9, @"Third range start index"); 52 | XCTAssertEqual(endIndex, (NSUInteger)12, @"Third range end index"); 53 | } 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /Test/Source/Resources: -------------------------------------------------------------------------------- 1 | ../Resources -------------------------------------------------------------------------------- /Test/Source/UIColorHTMLTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIColorHTMLTest.h 3 | // DTCoreText 4 | // 5 | // Created by Claus Broch on 11/01/11. 6 | // Copyright 2011 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIColorHTMLTest : XCTestCase { 12 | 13 | } 14 | 15 | - (void) testValidColorWithHexString; 16 | - (void) testColorHTMLHexString; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /Test/Source/UIColorHTMLTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIColorHTMLTest.m 3 | // DTCoreText 4 | // 5 | // Created by Claus Broch on 11/01/11. 6 | // Copyright 2011 Drobnik.com. All rights reserved. 7 | // 8 | 9 | #import "UIColorHTMLTest.h" 10 | 11 | @import DTCoreText; 12 | 13 | @implementation UIColorHTMLTest 14 | 15 | - (void)testValidColorWithHexString 16 | { 17 | DTColor *htmlColor; 18 | DTColor *namedColor; 19 | 20 | namedColor = [DTColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:1.0]; 21 | htmlColor = DTColorCreateWithHexString(@"000000"); 22 | XCTAssertNotNil(htmlColor, @"Failed to create black color"); 23 | XCTAssertEqualObjects(namedColor, htmlColor, @"Hmmm... black is not black"); 24 | 25 | namedColor = [DTColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0]; 26 | htmlColor = DTColorCreateWithHexString(@"FFFFFF"); 27 | XCTAssertNotNil(htmlColor, @"Failed to create white color"); 28 | XCTAssertEqualObjects(namedColor, htmlColor, @"Hmmm... white is not white"); 29 | 30 | namedColor = [DTColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:1.0]; 31 | htmlColor = DTColorCreateWithHexString(@"FF0000"); 32 | XCTAssertNotNil(htmlColor, @"Failed to create red color"); 33 | XCTAssertEqualObjects(namedColor, htmlColor, @"Hmmm... red is not red"); 34 | 35 | namedColor = [DTColor colorWithRed:0.0 green:1.0 blue:0.0 alpha:1.0]; 36 | htmlColor = DTColorCreateWithHexString(@"00FF00"); 37 | XCTAssertNotNil(htmlColor, @"Failed to create green color"); 38 | XCTAssertEqualObjects(namedColor, htmlColor, @"Hmmm... green is not green"); 39 | 40 | namedColor = [DTColor colorWithRed:0.0 green:0.0 blue:1.0 alpha:1.0]; 41 | htmlColor = DTColorCreateWithHexString(@"0000FF"); 42 | XCTAssertNotNil(htmlColor, @"Failed to create blue color"); 43 | XCTAssertEqualObjects(namedColor, htmlColor, @"Hmmm... blue is not blue"); 44 | 45 | namedColor = [DTColor colorWithRed:1.0 green:0.0 blue:1.0 alpha:1.0]; 46 | htmlColor = DTColorCreateWithHexString(@"F0F"); 47 | XCTAssertNotNil(htmlColor, @"Failed to create purple color"); 48 | XCTAssertEqualObjects(namedColor, htmlColor, @"Hmmm... purple is not purple"); 49 | } 50 | 51 | - (void)testColorHTMLHexString 52 | { 53 | DTColor *red = [DTColor redColor]; 54 | XCTAssertEqualObjects(DTHexStringFromDTColor(red), @"ff0000"); 55 | 56 | DTColor *green = [DTColor greenColor]; 57 | XCTAssertEqualObjects(DTHexStringFromDTColor(green), @"00ff00"); 58 | 59 | DTColor *blue = [DTColor blueColor]; 60 | XCTAssertEqualObjects(DTHexStringFromDTColor(blue), @"0000ff"); 61 | 62 | DTColor *white = [DTColor whiteColor]; 63 | XCTAssertEqualObjects(DTHexStringFromDTColor(white), @"ffffff"); 64 | } 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /Test/UnitTest-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleSignature 16 | ???? 17 | CFBundleVersion 18 | 1.0 19 | 20 | 21 | -------------------------------------------------------------------------------- /Test/UnitTest-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'UnitTest' target in the 'CoreTextExtensions' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #import 8 | #import 9 | #import "DTCoreText.h" 10 | #endif 11 | -------------------------------------------------------------------------------- /Tests/DTCoreTextTests/DTCoreTextTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import DTCoreText 3 | 4 | final class DTCoreTextTests: XCTestCase { 5 | func testExample() { 6 | // This is an example of a functional test case. 7 | // Use XCTAssert and related functions to verify your tests produce the correct 8 | // results. 9 | XCTAssertEqual(DTCoreText().text, "Hello, World!") 10 | } 11 | 12 | static var allTests = [ 13 | ("testExample", testExample), 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /Tests/DTCoreTextTests/XCTestManifests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | #if !canImport(ObjectiveC) 4 | public func allTests() -> [XCTestCaseEntry] { 5 | return [ 6 | testCase(DTCoreTextTests.allTests), 7 | ] 8 | } 9 | #endif 10 | -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | import DTCoreTextTests 4 | 5 | var tests = [XCTestCaseEntry]() 6 | tests += DTCoreTextTests.allTests() 7 | XCTMain(tests) 8 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | maven { 4 | url('http://openbakery.org/repository/') 5 | } 6 | mavenCentral() 7 | } 8 | dependencies { 9 | classpath group: 'org.openbakery', name: 'xcodePlugin', version: '0.9.+' 10 | } 11 | } 12 | apply plugin: 'xcode' 13 | 14 | 15 | xcodebuild { 16 | scheme = 'Static Library' 17 | target = 'Static Library' 18 | configuration = 'Debug' 19 | 20 | 21 | } 22 | 23 | 24 | // ---------- FTP Publish ---------- 25 | 26 | repositories { 27 | mavenCentral() 28 | } 29 | 30 | configurations { 31 | ftpAntTask 32 | } 33 | 34 | dependencies { 35 | ftpAntTask("org.apache.ant:ant-commons-net:1.9.+"); 36 | } 37 | 38 | 39 | ant.taskdef( 40 | name: 'ftp', 41 | classname: 'org.apache.tools.ant.taskdefs.optional.net.FTP', 42 | classpath: configurations.ftpAntTask.asPath 43 | ) 44 | 45 | task documentationUpload << { 46 | def uploadHost = 'docs.cocoanetics.com' 47 | if (project.ext.properties.containsKey("uploadHost")) { 48 | uploadHost = project.ext.uploadHost 49 | } 50 | 51 | def uploadUser = null 52 | if (project.ext.properties.containsKey("uploadUser")) { 53 | uploadUser = project.ext.uploadUser 54 | } else { 55 | uploadUser = System.console().readLine("\nPlease enter the upload user: ") 56 | } 57 | 58 | def uploadPassword = null 59 | if (project.ext.properties.containsKey("uploadPassword")) { 60 | uploadPassword = project.ext.uploadPassword 61 | } else { 62 | uploadPassword = "" + System.console().readPassword("\nPlease enter the upload server password: ") 63 | } 64 | 65 | 66 | // -------------- UPLOAD DIRECTORY ------------- 67 | 68 | def uploadDirectory = 'DTCoreText' 69 | if (project.ext.properties.containsKey("uploadDirectory")) { 70 | uploadDirectory = project.ext.uploadDirectory 71 | } 72 | 73 | 74 | ant.ftp( 75 | server: uploadHost, 76 | remotedir: uploadDirectory, 77 | userid: uploadUser, 78 | password: uploadPassword, 79 | depends: true, 80 | verbose: true, 81 | passive: true) { 82 | 83 | fileset(dir: 'build/documentation/html') { 84 | include(name: '**/**') 85 | } 86 | fileset(dir: 'build/documentation/publish') { 87 | include(name: '**/**') 88 | } 89 | } 90 | 91 | } 92 | 93 | 94 | // ---------- Unit Tests ---------- 95 | 96 | task continuous(dependsOn: 'test') 97 | 98 | gradle.taskGraph.whenReady { taskGraph -> 99 | 100 | if (taskGraph.hasTask(test)) { 101 | println "CONFIGURE CONTINUOUS" 102 | xcodebuild { 103 | 104 | destination { 105 | platform = 'iOS Simulator' 106 | name = 'iPad' 107 | os='7.1' 108 | } 109 | 110 | destination { 111 | platform = 'iOS Simulator' 112 | name = 'iPhone Retina (3.5-inch)' 113 | os='7.1' 114 | } 115 | 116 | destination { 117 | platform = 'iOS Simulator' 118 | name = 'iPhone Retina (4-inch)' 119 | os='7.1' 120 | } 121 | 122 | destination { 123 | platform = 'iOS Simulator' 124 | name = 'iPad Retina' 125 | os='7.1' 126 | } 127 | } 128 | } 129 | } 130 | --------------------------------------------------------------------------------