Skip to content
Browse files

Implemented simple text box support. block-level elements can have a …

…padding and background color, so far only 1 level deep supported.
  • Loading branch information...
1 parent e803b1b commit 8004a34f0595f8b76a255394020b17ecf6ab1e64 @odrobnik odrobnik committed Mar 4, 2012
View
15 Core/Source/DTAttributedTextContentView.h
@@ -15,6 +15,7 @@
@class DTAttributedTextContentView;
@class DTCoreTextLayoutFrame;
+@class DTTextBlock;
/**
Protocol to provide custom views for elements in an DTAttributedTextContentView. Also the delegate gets notified once the text view has been drawn.
@@ -39,6 +40,20 @@
/**
+ Called before the text belonging to a text block is drawn.
+
+ This gives the developer an opportunity to draw a custom background below a text block.
+
+ @param attributedTextContentView The content view that drew a layout frame
+ @param textBlock The text block
+ @param rect The frame within the content view's coordinate system that will be drawn into
+ @param context The graphics context that will be drawn into
+ @param layoutFrame The layout frame that will be drawn for
+ @param returns `YES` is the standard fill of the text block should be drawn, `NO` if it should not
+ */
+- (BOOL)attributedTextContentView:(DTAttributedTextContentView *)attributedTextContentView shouldDrawBackgroundForTextBlock:(DTTextBlock *)textBlock frame:(CGRect)frame context:(CGContextRef)context forLayoutFrame:(DTCoreTextLayoutFrame *)layoutFrame;
+
+/**
@name Providing Custom Views for Content
*/
View
17 Core/Source/DTAttributedTextContentView.m
@@ -51,6 +51,7 @@ @interface DTAttributedTextContentView ()
unsigned int delegateSupportsCustomViewsForLinks:1;
unsigned int delegateSupportsGenericCustomViews:1;
unsigned int delegateSupportsNotificationAfterDrawing:1;
+ unsigned int delegateSupportsNotificationBeforeTextBoxDrawing:1;
} _delegateFlags;
__unsafe_unretained id <DTAttributedTextContentViewDelegate> _delegate;
@@ -657,6 +658,21 @@ - (DTCoreTextLayoutFrame *)layoutFrame
rect.size.height = CGFLOAT_OPEN_HEIGHT; // necessary height set as soon as we know it.
_layoutFrame = [theLayouter layoutFrameWithRect:rect range:NSMakeRange(0, 0)];
+
+ if (_delegateFlags.delegateSupportsNotificationBeforeTextBoxDrawing)
+ {
+ DTAttributedTextContentView *weakself = self;
+
+ [_layoutFrame setTextBlockHandler:^(DTTextBlock *textBlock, CGRect frame, CGContextRef context, BOOL *shouldDrawDefaultBackground) {
+ BOOL result = [weakself->_delegate attributedTextContentView:weakself shouldDrawBackgroundForTextBlock:textBlock frame:frame context:context forLayoutFrame:weakself->_layoutFrame];
+
+ if (shouldDrawDefaultBackground)
+ {
+ *shouldDrawDefaultBackground = result;
+ }
+
+ }];
+ }
}
}
}
@@ -723,6 +739,7 @@ - (void)setDelegate:(id<DTAttributedTextContentViewDelegate>)delegate
_delegateFlags.delegateSupportsCustomViewsForLinks = [_delegate respondsToSelector:@selector(attributedTextContentView:viewForLink:identifier:frame:)];
_delegateFlags.delegateSupportsGenericCustomViews = [_delegate respondsToSelector:@selector(attributedTextContentView:viewForAttributedString:frame:)];
_delegateFlags.delegateSupportsNotificationAfterDrawing = [_delegate respondsToSelector:@selector(attributedTextContentView:didDrawLayoutFrame:inContext:)];
+ _delegateFlags.delegateSupportsNotificationBeforeTextBoxDrawing = [_delegate respondsToSelector:@selector(attributedTextContentView:shouldDrawBackgroundForTextBlock:frame:context:forLayoutFrame:)];
if (!_delegateFlags.delegateSupportsCustomViewsForLinks && !_delegateFlags.delegateSupportsGenericCustomViews)
{
View
23 Core/Source/DTCoreText.h
@@ -1,16 +1,31 @@
-
#if TARGET_OS_IPHONE
#import <CoreText/CoreText.h>
#endif
// global constants
#import "DTCoreTextConstants.h"
+// DTColor is UIColor on iOS, NSColor on Mac
+#import "DTColor+HTML.h"
+
+// DTImage is UIImage on iOS, NSImage on Mac
+#import "DTImage+HTML.h"
+
+// DTEdgeInsets is UIEdgeInsets on iOS, NSEdgeInsets on Mac
+#if TARGET_OS_IPHONE
+#define DTEdgeInsets UIEdgeInsets
+#define DTEdgeInsetsMake(a, b, c, d) UIEdgeInsetsMake(a, b, c, d)
+#else
+#define DTEdgeInsets NSEdgeInsets
+#define DTEdgeInsetsMake(a, b, c, d) NSEdgeInsetsMake(a, b, c, d)
+#endif
+
// common utilities
#import "CGUtils.h"
// common classes
#import "DTCSSListStyle.h"
+#import "DTTextBlock.h"
#import "DTCSSStylesheet.h"
#import "DTCoreText.h"
#import "DTCoreTextFontDescriptor.h"
@@ -19,6 +34,7 @@
#import "NSCharacterSet+HTML.h"
#import "NSData+DTBase64.h"
#import "NSScanner+HTML.h"
+#import "NSMutableString+HTML.h"
#import "NSString+CSS.h"
#import "NSString+HTML.h"
#import "NSString+Paragraphs.h"
@@ -28,11 +44,6 @@
#import "NSAttributedString+SmallCaps.h"
#import "NSAttributedString+DTCoreText.h"
-// DTColor is UIColor on iOS, NSColor on Mac
-#import "DTColor+HTML.h"
-
-// DTImage is UIImage on iOS, NSImage on Mac
-#import "DTImage+HTML.h"
// These classes only work with UIKit on iOS
#if TARGET_OS_IPHONE
View
2 Core/Source/DTCoreTextConstants.h
@@ -37,7 +37,7 @@ extern NSString *DTStrikeOutAttribute;
extern NSString *DTBackgroundColorAttribute;
extern NSString *DTShadowsAttribute;
extern NSString *DTHorizontalRuleStyleAttribute;
-extern NSString *DTPaddingAttribute;
+extern NSString *DTTextBlocksAttribute;
// macros
View
2 Core/Source/DTCoreTextConstants.m
@@ -34,4 +34,4 @@
NSString *DTBackgroundColorAttribute = @"DTBackgroundColor";
NSString *DTShadowsAttribute = @"DTShadows";
NSString *DTHorizontalRuleStyleAttribute = @"DTHorizontalRuleStyle";
-NSString *DTPaddingAttribute = @"DTPadding";
+NSString *DTTextBlocksAttribute = @"DTTextBlocks";
View
11 Core/Source/DTCoreTextLayoutFrame.h
@@ -10,11 +10,14 @@
#import <CoreText/CoreText.h>
@class DTCoreTextLayoutLine;
+@class DTTextBlock;
// the value to use if the height is unknown
#define CGFLOAT_OPEN_HEIGHT 16777215.0f
+typedef void (^DTCoreTextLayoutFrameTextBlockHandler)(DTTextBlock *textBlock, CGRect frame, CGContextRef context, BOOL *shouldDrawDefaultBackground);
+
@class DTCoreTextLayouter;
@@ -105,6 +108,14 @@
/**
+ Set a custom handler to be executed before text belonging to a text block is drawn.
+
+ @param handler A DTCoreTextLayoutFrameTextBlockHandler block.
+*/
+@property (nonatomic, copy) DTCoreTextLayoutFrameTextBlockHandler textBlockHandler;
+
+
+/**
@name Working with Glyphs
*/
View
168 Core/Source/DTCoreTextLayoutFrame.m
@@ -6,19 +6,21 @@
// Copyright 2011 Drobnik.com. All rights reserved.
//
-#import "DTCoreTextConstants.h"
-
+#import "DTCoreText.h"
#import "DTCoreTextLayoutFrame.h"
-#import "DTCoreTextLayouter.h"
-#import "DTCoreTextLayoutLine.h"
-#import "DTCoreTextGlyphRun.h"
-
-#import "DTTextAttachment.h"
-#import "UIDevice+DTVersion.h"
-
-#import "NSString+Paragraphs.h"
-#import "DTColor+HTML.h"
-#import "DTImage+HTML.h"
+//#import "DTCoreTextConstants.h"
+//
+//#import "DTCoreTextLayoutFrame.h"
+//#import "DTCoreTextLayouter.h"
+//#import "DTCoreTextLayoutLine.h"
+//#import "DTCoreTextGlyphRun.h"
+//
+//#import "DTTextAttachment.h"
+//#import "UIDevice+DTVersion.h"
+//
+//#import "NSString+Paragraphs.h"
+//#import "DTColor+HTML.h"
+//#import "DTImage+HTML.h"
// global flag that shows debug frames
@@ -36,12 +38,14 @@ - (void)_correctLineOrigins;
@implementation DTCoreTextLayoutFrame
{
CTFrameRef _textFrame;
- CTFramesetterRef _framesetter;
+ CTFramesetterRef _framesetter;
NSRange _requestedStringRange;
NSRange _stringRange;
-
- NSInteger tag;
+
+ NSInteger tag;
+
+ DTCoreTextLayoutFrameTextBlockHandler _textBlockHandler;
}
// makes a frame for a specific part of the attributed string of the layouter
@@ -159,11 +163,14 @@ - (void)_buildLinesWithTypesetter
UIEdgeInsets padding;
} paragraphMetrics;
+ paragraphMetrics currentParaMetrics;
+// paragraphMetrics previousParaMetrics;
+
lineMetrics currentLineMetrics;
lineMetrics previousLineMetrics;
- paragraphMetrics currentParaMetrics;
- paragraphMetrics previousParaMetrics;
+ DTTextBlock *currentTextBlock = nil;
+ DTTextBlock *previousTextBlock = nil;
do
{
@@ -182,35 +189,31 @@ - (void)_buildLinesWithTypesetter
// get the paragraph style at this index
CTParagraphStyleRef paragraphStyle = (__bridge CTParagraphStyleRef)[_attributedStringFragment attribute:(id)kCTParagraphStyleAttributeName atIndex:lineRange.location effectiveRange:NULL];
+ currentTextBlock = [[_attributedStringFragment attribute:DTTextBlocksAttribute atIndex:lineRange.location effectiveRange:NULL] lastObject];
+
+ if (previousTextBlock != currentTextBlock)
+ {
+ lineOrigin.y += previousTextBlock.padding.bottom;
+ lineOrigin.y += currentTextBlock.padding.top;
+
+ previousTextBlock = currentTextBlock;
+ }
+
if (isAtBeginOfParagraph)
{
- // save paragraph metrics
- previousParaMetrics = currentParaMetrics;
-
CTParagraphStyleGetValueForSpecifier(paragraphStyle, kCTParagraphStyleSpecifierFirstLineHeadIndent, sizeof(offset), &offset);
-
-
- NSValue *paddingValue = [_attributedStringFragment attribute:DTPaddingAttribute atIndex:lineRange.location effectiveRange:NULL];
- if (paddingValue)
- {
- currentParaMetrics.padding = [paddingValue UIEdgeInsetsValue];
- }
- else
- {
- currentParaMetrics.padding = UIEdgeInsetsMake(0, 0, 0, 0);
- }
}
else
{
CTParagraphStyleGetValueForSpecifier(paragraphStyle, kCTParagraphStyleSpecifierHeadIndent, sizeof(offset), &offset);
}
// add left padding to offset
- offset += currentParaMetrics.padding.left;
+ offset += currentTextBlock.padding.left;
lineOrigin.x = offset + _frame.origin.x;
- CGFloat availableSpace = _frame.size.width - offset - currentParaMetrics.padding.right;
+ CGFloat availableSpace = _frame.size.width - offset - currentTextBlock.padding.right;
// find how many characters we get into this line
lineRange.length = CTTypesetterSuggestLineBreak(typesetter, lineRange.location, availableSpace);
@@ -383,10 +386,10 @@ - (void)_buildLinesWithTypesetter
// baseline origin is rounded
lineOrigin.y = roundf(lineOrigin.y);
- if (isAtBeginOfParagraph)
- {
- lineOrigin.y += currentParaMetrics.padding.top + previousParaMetrics.padding.bottom;
- }
+// if (isAtBeginOfParagraph)
+// {
+// lineOrigin.y += currentParaMetrics.padding.top + previousParaMetrics.padding.bottom;
+// }
newLine.baselineOrigin = lineOrigin;
@@ -420,7 +423,9 @@ - (void)_buildLinesWithTypesetter
// actual frame is spanned between first and last lines
DTCoreTextLayoutLine *lastLine = [_lines lastObject];
- _frame.size.height = ceilf((CGRectGetMaxY(lastLine.frame) - _frame.origin.y + 1.5f));
+ _frame.size.height = ceilf((CGRectGetMaxY(lastLine.frame) - _frame.origin.y + 1.5f + currentTextBlock.padding.bottom));
+
+ // need to add bottom padding if in text block
}
}
@@ -603,6 +608,38 @@ - (void)_setShadowInContext:(CGContextRef)context fromDictionary:(NSDictionary *
CGContextSetShadowWithColor(context, offset, blur, color.CGColor);
}
+- (CGRect)_frameForTextBlock:(DTTextBlock *)textBlock atIndex:(NSUInteger)location
+{
+ NSRange blockRange = [_attributedStringFragment rangeOfTextBlock:textBlock atIndex:location];
+
+ DTCoreTextLayoutLine *firstBlockLine = [self lineContainingIndex:blockRange.location];
+ DTCoreTextLayoutLine *lastBlockLine = [self lineContainingIndex:NSMaxRange(blockRange)-1];
+
+ CGRect frame;
+ frame.origin = firstBlockLine.frame.origin;
+ frame.origin.x -= textBlock.padding.left;
+ frame.origin.y -= textBlock.padding.top;
+
+ CGFloat maxWidth = 0;
+
+ for (NSUInteger index = blockRange.location; index<NSMaxRange(blockRange);)
+ {
+ DTCoreTextLayoutLine *oneLine = [self lineContainingIndex:index];
+
+ if (maxWidth<oneLine.frame.size.width)
+ {
+ maxWidth = oneLine.frame.size.width;
+ }
+
+ index += oneLine.stringRange.length;
+ }
+
+ frame.size.width = _frame.size.width; // currently all blocks are 100% wide
+ frame.size.height = CGRectGetMaxY(lastBlockLine.frame) - frame.origin.y + textBlock.padding.bottom;
+
+ return frame;
+}
+
- (void)drawInContext:(CGContextRef)context drawImages:(BOOL)drawImages
{
CGContextSaveGState(context);
@@ -638,6 +675,59 @@ - (void)drawInContext:(CGContextRef)context drawImages:(BOOL)drawImages
NSArray *visibleLines = [self linesVisibleInRect:rect];
+ if (![visibleLines count])
+ {
+ return;
+ }
+
+ // text block handling
+ if (_textBlockHandler)
+ {
+// DTCoreTextLayoutLine *firstLine = [visibleLines objectAtIndex:0];
+// DTCoreTextLayoutLine *lastLine = [visibleLines lastObject];
+//
+// // find visible range
+// NSUInteger startIndex = firstLine.stringRange.location;
+// NSUInteger endIndex = NSMaxRange(lastLine.stringRange);
+// NSRange visibleRange = NSMakeRange(startIndex, endIndex - startIndex);
+
+ __block NSMutableSet *handledBlocks = [NSMutableSet set];
+
+ // enumerate all text blocks in this range
+ [_attributedStringFragment enumerateAttribute:DTTextBlocksAttribute inRange:_stringRange options:0
+ usingBlock:^(NSArray *blockArray, NSRange range, BOOL *stop) {
+ for (DTTextBlock *oneBlock in blockArray)
+ {
+ // make sure we only handle it once
+ if (![handledBlocks containsObject:oneBlock])
+ {
+ CGRect frame = [self _frameForTextBlock:oneBlock atIndex:range.location];
+
+ BOOL shouldDrawStandardBackground = YES;
+ if (_textBlockHandler)
+ {
+ _textBlockHandler(oneBlock, frame, context, &shouldDrawStandardBackground);
+ }
+
+ // draw standard background if necessary
+ if (shouldDrawStandardBackground)
+ {
+ if (oneBlock.backgroundColor)
+ {
+ CGColorRef color = [oneBlock.backgroundColor CGColor];
+ CGContextSetFillColorWithColor(context, color);
+ CGContextFillRect(context, frame);
+ }
+ }
+
+ [handledBlocks addObject:oneBlock];
+ }
+ }
+
+
+ }];
+ }
+
for (DTCoreTextLayoutLine *oneLine in visibleLines)
{
@@ -1193,6 +1283,6 @@ - (NSArray *)paragraphRanges
@synthesize frame = _frame;
@synthesize lines = _lines;
@synthesize paragraphRanges = _paragraphRanges;
-//@synthesize tag;
+@synthesize textBlockHandler = _textBlockHandler;
@end
View
12 Core/Source/DTCoreTextParagraphStyle.h
@@ -6,7 +6,6 @@
// Copyright 2011 Drobnik.com. All rights reserved.
//
-
/**
`DTCoreTextParagraphStyle` encapsulates the paragraph or ruler attributes used by the NSAttributedString classes on iOS. It is a replacement for `NSParagraphStyle` which is not implemented on iOS.
@@ -174,4 +173,15 @@
@property (nonatomic, assign) CGFloat listIndent;
+/**-------------------------------------------------------------------------------------
+ @name Setting Text Blocks
+ ---------------------------------------------------------------------------------------
+ */
+
+/**
+ Text lists containing the paragraph, nested from outermost to innermost, to array.
+ */
+@property (nonatomic, copy) NSArray *textBlocks;
+
+
@end
View
42 Core/Source/DTCoreTextParagraphStyle.m
@@ -21,20 +21,20 @@
@implementation DTCoreTextParagraphStyle
{
- CGFloat firstLineHeadIndent;
+ CGFloat firstLineHeadIndent;
CGFloat defaultTabInterval;
- CGFloat paragraphSpacingBefore;
- CGFloat paragraphSpacing;
- CGFloat headIndent;
- CGFloat listIndent;
- CGFloat lineHeightMultiple;
- CGFloat minimumLineHeight;
- CGFloat maximumLineHeight;
-
- CTTextAlignment _alignment;
- CTWritingDirection baseWritingDirection;
-
- NSMutableArray *_tabStops;
+ CGFloat paragraphSpacingBefore;
+ CGFloat paragraphSpacing;
+ CGFloat headIndent;
+ CGFloat listIndent;
+ CGFloat lineHeightMultiple;
+ CGFloat minimumLineHeight;
+ CGFloat maximumLineHeight;
+
+ CTTextAlignment _alignment;
+ CTWritingDirection baseWritingDirection;
+
+ NSMutableArray *_tabStops;
}
+ (DTCoreTextParagraphStyle *)defaultParagraphStyle
@@ -46,15 +46,15 @@ + (DTCoreTextParagraphStyle *)paragraphStyleWithCTParagraphStyle:(CTParagraphSty
{
DTCoreTextParagraphStyle *returnParagraphStyle = NULL;
static dispatch_once_t predicate;
-
+
dispatch_once(&predicate, ^{
_paragraphStyleCache = [[NSCache alloc] init];
selfLock = dispatch_semaphore_create(1);
});
-
+
// synchronize class-wide
-
+
dispatch_semaphore_wait(selfLock, DISPATCH_TIME_FOREVER);
{
@@ -101,7 +101,7 @@ - (id)initWithCTParagraphStyle:(CTParagraphStyleRef)ctParagraphStyle
CTParagraphStyleGetValueForSpecifier(ctParagraphStyle, kCTParagraphStyleSpecifierAlignment,sizeof(_alignment), &_alignment);
CTParagraphStyleGetValueForSpecifier(ctParagraphStyle, kCTParagraphStyleSpecifierFirstLineHeadIndent, sizeof(firstLineHeadIndent), &firstLineHeadIndent);
CTParagraphStyleGetValueForSpecifier(ctParagraphStyle, kCTParagraphStyleSpecifierDefaultTabInterval, sizeof(defaultTabInterval), &defaultTabInterval);
-
+
__unsafe_unretained NSArray *stops; // Could use a CFArray too, leave as a reminder how to do this in the future
if (CTParagraphStyleGetValueForSpecifier(ctParagraphStyle, kCTParagraphStyleSpecifierTabStops, sizeof(stops), &stops))
@@ -152,7 +152,7 @@ - (CTParagraphStyleRef)createCTParagraphStyle
// This just makes it that much easier to track down memory issues with tabstops
CFArrayRef stops = _tabStops ? CFArrayCreateCopy (NULL, (__bridge CFArrayRef)_tabStops) : NULL;
-
+
CTParagraphStyleSetting settings[] =
{
{kCTParagraphStyleSpecifierAlignment, sizeof(_alignment), &_alignment},
@@ -174,7 +174,7 @@ - (CTParagraphStyleRef)createCTParagraphStyle
CTParagraphStyleRef ret = CTParagraphStyleCreate(settings, 11);
if (stops) CFRelease(stops);
-
+
return ret;
}
@@ -222,7 +222,7 @@ - (NSString *)cssStyleRepresentation
{
[retString appendFormat:@"line-height:%.2fem;", lineHeightMultiple];
}
-
+
switch (baseWritingDirection)
{
case kCTWritingDirectionRightToLeft:
@@ -266,6 +266,7 @@ - (id)copyWithZone:(NSZone *)zone
newObject.baseWritingDirection = self.baseWritingDirection;
newObject.tabStops = self.tabStops; // copy
newObject.textLists = self.textLists; //copy
+ newObject.textBlocks = self.textBlocks; //copy
return newObject;
}
@@ -291,6 +292,7 @@ - (void)setTabStops:(NSArray *)tabStops
@synthesize listIndent;
@synthesize alignment = _alignment;
@synthesize textLists;
+@synthesize textBlocks;
@synthesize baseWritingDirection;
@synthesize tabStops = _tabStops;
View
16 Core/Source/DTHTMLAttributedStringBuilder.m
@@ -6,20 +6,12 @@
// Copyright (c) 2012 Drobnik.com. All rights reserved.
//
+#import "DTCoreText.h"
#import "DTHTMLAttributedStringBuilder.h"
-#import "DTCoreTextConstants.h"
-#import "DTCSSStylesheet.h"
-#import "DTCoreTextFontDescriptor.h"
-#import "DTCoreTextParagraphStyle.h"
-#import "DTTextAttachment.h"
-
-#import "DTColor+HTML.h"
-#import "DTImage+HTML.h"
-
-#import "NSString+HTML.h"
-#import "NSString+CSS.h"
-#import "NSMutableString+HTML.h"
+//#import "NSString+HTML.h"
+//#import "NSString+CSS.h"
+//#import "NSMutableString+HTML.h"
@interface DTHTMLAttributedStringBuilder ()
View
7 Core/Source/DTHTMLElement.h
@@ -6,14 +6,11 @@
// Copyright 2011 Drobnik.com. All rights reserved.
//
-#import "DTCoreText.h"
-#import "DTColor+HTML.h"
-
@class DTCoreTextParagraphStyle;
@class DTCoreTextFontDescriptor;
@class DTTextAttachment;
@class DTCSSListStyle;
-
+@class DTColor;
typedef enum
{
@@ -62,8 +59,6 @@ typedef enum
@property (nonatomic, assign) CGFloat textScale;
@property (nonatomic, assign) CGSize size;
@property (nonatomic, strong) NSDictionary *attributes;
-@property (nonatomic, assign) UIEdgeInsets padding;
-
- (NSAttributedString *)attributedString;
- (NSAttributedString *)prefixForListItemWithCounter:(NSUInteger)listCounter;
View
57 Core/Source/DTHTMLElement.m
@@ -6,25 +6,8 @@
// Copyright 2011 Drobnik.com. All rights reserved.
//
+#import "DTCoreText.h"
#import "DTHTMLElement.h"
-#import "DTCoreTextParagraphStyle.h"
-#import "DTCoreTextFontDescriptor.h"
-#import "NSString+HTML.h"
-#import "DTColor+HTML.h"
-#import "NSCharacterSet+HTML.h"
-#import "DTTextAttachment.h"
-#import "NSAttributedString+HTML.h"
-#import "NSMutableAttributedString+HTML.h"
-
-#import "DTCSSListStyle.h"
-
-#import "DTCoreTextConstants.h"
-#import "DTImage+HTML.h"
-#import "DTColor+HTML.h"
-
-#if TARGET_OS_IPHONE
-#import "NSAttributedStringRunDelegates.h"
-#endif
@interface DTHTMLElement ()
@@ -49,8 +32,6 @@ @implementation DTHTMLElement
DTColor *_textColor;
DTColor *backgroundColor;
- UIEdgeInsets _padding;
-
CTUnderlineStyle underlineStyle;
NSString *tagName;
@@ -224,13 +205,11 @@ - (NSDictionary *)attributesDictionary
{
[tmpDict setObject:paragraphStyle.textLists forKey:DTTextListsAttribute];
}
-
- if (_padding.left!=0 || _padding.top!=0 || _padding.right!=0 || _padding.bottom!=0)
+
+ if (paragraphStyle.textBlocks)
{
- NSValue *paddingValue = [NSValue valueWithUIEdgeInsets:_padding];
- [tmpDict setObject:paddingValue forKey:DTPaddingAttribute];
+ [tmpDict setObject:paragraphStyle.textBlocks forKey:DTTextBlocksAttribute];
}
-
return tmpDict;
}
@@ -771,11 +750,28 @@ - (void)applyStyleDictionary:(NSDictionary *)styles
}
}
- NSString *paddingString = [styles objectForKey:@"padding"];
- if (paddingString)
+ if (_displayStyle == DTHTMLElementDisplayStyleBlock)
{
- CGFloat padding = [paddingString pixelSizeOfCSSMeasureRelativeToCurrentTextSize:self.fontDescriptor.pointSize];
- _padding = UIEdgeInsetsMake(padding, padding, padding, padding);
+ NSString *paddingString = [styles objectForKey:@"padding"];
+
+ if (paddingString || backgroundColor)
+ {
+ // need a block
+ DTTextBlock *newBlock = [[DTTextBlock alloc] init];
+
+ if (paddingString)
+ {
+ CGFloat padding = [paddingString pixelSizeOfCSSMeasureRelativeToCurrentTextSize:self.fontDescriptor.pointSize];
+
+ newBlock.padding = DTEdgeInsetsMake(padding, padding, padding, padding);
+ }
+
+ // transfer background color to block
+ newBlock.backgroundColor = backgroundColor;
+ backgroundColor = nil;
+
+ self.paragraphStyle.textBlocks = [NSArray arrayWithObject:newBlock];
+ }
}
}
@@ -1028,15 +1024,12 @@ - (void)setTextAttachment:(DTTextAttachment *)textAttachment
@synthesize preserveNewlines;
@synthesize displayStyle = _displayStyle;
@synthesize fontVariant;
-//@synthesize listStyle = _listStyle;
@synthesize textScale;
@synthesize size;
@synthesize fontCache = _fontCache;
@synthesize children = _children;
@synthesize attributes = _attributes;
-@synthesize padding = _padding;
-
@end
View
28 Core/Source/DTTextBlock.h
@@ -0,0 +1,28 @@
+//
+// DTTextBlock.h
+// DTCoreText
+//
+// Created by Oliver Drobnik on 04.03.12.
+// Copyright (c) 2012 Drobnik.com. All rights reserved.
+//
+
+#import "DTCoreText.h"
+
+/**
+ Class that represents a block of text with attributes like padding or a background color.
+ */
+@interface DTTextBlock : NSObject
+
+/**
+ The space to be applied between the layouted text and the edges of the receiver
+ */
+@property (nonatomic, assign) DTEdgeInsets padding;
+
+
+/**
+ The background color to paint behind the text in the receiver
+ */
+@property (nonatomic, strong) DTColor *backgroundColor;
+
+
+@end
View
22 Core/Source/DTTextBlock.m
@@ -0,0 +1,22 @@
+//
+// DTTextBlock.m
+// DTCoreText
+//
+// Created by Oliver Drobnik on 04.03.12.
+// Copyright (c) 2012 Drobnik.com. All rights reserved.
+//
+
+#import "DTTextBlock.h"
+
+@implementation DTTextBlock
+{
+ DTEdgeInsets _padding;
+ DTColor *_backgroundColor;
+}
+
+#pragma mark Properties
+
+@synthesize padding = _padding;
+@synthesize backgroundColor = _backgroundColor;
+
+@end
View
10 Core/Source/NSAttributedString+DTCoreText.h
@@ -7,6 +7,7 @@
//
@class DTCSSListStyle;
+@class DTTextBlock;
/**
Convenience Methods that mimick similar methods available on Mac
@@ -55,6 +56,15 @@
/**
+ Returns the range of the given text block that contains the given location.
+
+ @param list The text block.
+ @param location The location in the text.
+ @returns The range of the given text block containing the location.
+ */
+- (NSRange)rangeOfTextBlock:(DTTextBlock *)textBlock atIndex:(NSUInteger)location;
+
+/**
@name Converting to Other Representations
*/
View
37 Core/Source/NSAttributedString+DTCoreText.m
@@ -6,21 +6,9 @@
// Copyright (c) 2012 Drobnik.com. All rights reserved.
//
+#import "DTCoreText.h"
#import "NSAttributedString+DTCoreText.h"
-#import "DTCoreTextConstants.h"
-
-#import "DTColor+HTML.h"
-#import "NSString+HTML.h"
-#import "DTTextAttachment.h"
-#import "DTCoreTextParagraphStyle.h"
-#import "DTCoreTextFontDescriptor.h"
-#import "DTCSSListStyle.h"
-
-#if TARGET_OS_IPHONE
-#import "NSAttributedString+HTML.h"
-#endif
-
@implementation NSAttributedString (DTCoreText)
#pragma mark Text Attachments
@@ -124,11 +112,12 @@ - (NSInteger)itemNumberInTextList:(DTCSSListStyle *)list atIndex:(NSUInteger)loc
return [currentCounterNum integerValue];
}
-- (NSRange)rangeOfTextList:(DTCSSListStyle *)list atIndex:(NSUInteger)location
+
+- (NSRange)_rangeOfObject:(id)object inArrayBehindAttribute:(NSString *)attribute atIndex:(NSUInteger)location
{
NSInteger searchIndex = location;
- NSArray *textListsAtIndex;
+ NSArray *arrayAtIndex;
NSInteger minFoundIndex = NSIntegerMax;
NSInteger maxFoundIndex = 0;
@@ -137,9 +126,9 @@ - (NSRange)rangeOfTextList:(DTCSSListStyle *)list atIndex:(NSUInteger)location
do
{
NSRange effectiveRange;
- textListsAtIndex = [self attribute:DTTextListsAttribute atIndex:searchIndex effectiveRange:&effectiveRange];
+ arrayAtIndex = [self attribute:attribute atIndex:searchIndex effectiveRange:&effectiveRange];
- if([textListsAtIndex containsObject:list])
+ if([arrayAtIndex containsObject:object])
{
foundList = YES;
@@ -172,9 +161,9 @@ - (NSRange)rangeOfTextList:(DTCSSListStyle *)list atIndex:(NSUInteger)location
while (searchIndex < [self length])
{
NSRange effectiveRange;
- textListsAtIndex = [self attribute:DTTextListsAttribute atIndex:searchIndex effectiveRange:&effectiveRange];
+ arrayAtIndex = [self attribute:attribute atIndex:searchIndex effectiveRange:&effectiveRange];
- foundList = [textListsAtIndex containsObject:list];
+ foundList = [arrayAtIndex containsObject:object];
if (!foundList)
{
@@ -190,6 +179,16 @@ - (NSRange)rangeOfTextList:(DTCSSListStyle *)list atIndex:(NSUInteger)location
return NSMakeRange(minFoundIndex, maxFoundIndex-minFoundIndex);
}
+- (NSRange)rangeOfTextList:(DTCSSListStyle *)list atIndex:(NSUInteger)location
+{
+ return [self _rangeOfObject:list inArrayBehindAttribute:DTTextListsAttribute atIndex:location];
+}
+
+- (NSRange)rangeOfTextBlock:(DTTextBlock *)textBlock atIndex:(NSUInteger)location
+{
+ return [self _rangeOfObject:textBlock inArrayBehindAttribute:DTTextBlocksAttribute atIndex:location];
+}
+
#pragma mark HTML Encoding
View
4 Core/Source/NSScanner+HTML.h
@@ -6,7 +6,9 @@
// Copyright 2011 Drobnik.com. All rights reserved.
//
-#import "DTColor+HTML.h"
+//#import "DTColor+HTML.h"
+
+@class DTColor;
@interface NSScanner (HTML)
View
1 Core/Source/NSScanner+HTML.m
@@ -6,6 +6,7 @@
// Copyright 2011 Drobnik.com. All rights reserved.
//
+#import "DTCoreText.h"
#import "NSScanner+HTML.h"
#import "NSCharacterSet+HTML.h"
#import "NSString+HTML.h"
View
3 Core/Source/NSString+CSS.h
@@ -6,8 +6,7 @@
// Copyright (c) 2012 Drobnik.com. All rights reserved.
//
-#import "DTCoreText.h"
-#import "DTColor+HTML.h"
+@class DTColor;
/**
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.
View
3 Core/Source/NSString+CSS.m
@@ -6,10 +6,9 @@
// Copyright (c) 2012 Drobnik.com. All rights reserved.
//
+#import "DTCoreText.h"
#import "NSString+CSS.h"
-#import "DTColor+HTML.h"
-
@implementation NSString (CSS)
#pragma mark CSS
View
16 DTCoreText.xcodeproj/project.pbxproj
@@ -25,6 +25,12 @@
1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; };
288765A50DF7441C002DB57D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288765A40DF7441C002DB57D /* CoreGraphics.framework */; };
A704C93A13901FDB0045CFC6 /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A704C93913901FDB0045CFC6 /* ImageIO.framework */; };
+ A7081EA315036460002987F1 /* DTTextBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = A7081EA11503645F002987F1 /* DTTextBlock.h */; };
+ A7081EA415036460002987F1 /* DTTextBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = A7081EA11503645F002987F1 /* DTTextBlock.h */; };
+ A7081EA515036460002987F1 /* DTTextBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = A7081EA215036460002987F1 /* DTTextBlock.m */; };
+ A7081EA615036460002987F1 /* DTTextBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = A7081EA215036460002987F1 /* DTTextBlock.m */; };
+ A7081EA715036460002987F1 /* DTTextBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = A7081EA215036460002987F1 /* DTTextBlock.m */; };
+ A7081EA815036460002987F1 /* DTTextBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = A7081EA215036460002987F1 /* DTTextBlock.m */; };
A70A737A14FBC9060043E932 /* NSString+Paragraphs.m in Sources */ = {isa = PBXBuildFile; fileRef = A788C94B14863E8700E1AFD9 /* NSString+Paragraphs.m */; };
A70B4C9F1486558200873A4A /* DTCoreText.h in Headers */ = {isa = PBXBuildFile; fileRef = A70B4C9E1486558200873A4A /* DTCoreText.h */; settings = {ATTRIBUTES = (Public, ); }; };
A70B4CA01486558200873A4A /* DTCoreText.h in Headers */ = {isa = PBXBuildFile; fileRef = A70B4C9E1486558200873A4A /* DTCoreText.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -378,6 +384,8 @@
1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
288765A40DF7441C002DB57D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
A704C93913901FDB0045CFC6 /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = System/Library/Frameworks/ImageIO.framework; sourceTree = SDKROOT; };
+ A7081EA11503645F002987F1 /* DTTextBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTTextBlock.h; sourceTree = "<group>"; };
+ A7081EA215036460002987F1 /* DTTextBlock.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DTTextBlock.m; sourceTree = "<group>"; };
A70B4C9C1486525200873A4A /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
A70B4C9D1486525200873A4A /* Readme.markdown */ = {isa = PBXFileReference; lastKnownFileType = text; path = Readme.markdown; sourceTree = "<group>"; };
A70B4C9E1486558200873A4A /* DTCoreText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = DTCoreText.h; path = Core/Source/DTCoreText.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
@@ -675,6 +683,8 @@
A788C94914863E8700E1AFD9 /* NSString+HTML.m */,
A7C7ACD314D924B1005A9C69 /* NSMutableString+HTML.h */,
A7C7ACD414D924B1005A9C69 /* NSMutableString+HTML.m */,
+ A7081EA11503645F002987F1 /* DTTextBlock.h */,
+ A7081EA215036460002987F1 /* DTTextBlock.m */,
);
name = Layouting;
sourceTree = "<group>";
@@ -951,6 +961,7 @@
A7C7ACD514D924B1005A9C69 /* NSMutableString+HTML.h in Headers */,
A7B0B56814D9921F0091C2C9 /* NSAttributedString+DTCoreText.h in Headers */,
A760F54114F56E9000AD1B0E /* DTImage+HTML.h in Headers */,
+ A7081EA315036460002987F1 /* DTTextBlock.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -995,6 +1006,7 @@
A788CA0314863E8700E1AFD9 /* DTColor+HTML.h in Headers */,
A70B4CA01486558200873A4A /* DTCoreText.h in Headers */,
A760F54014F56E8E00AD1B0E /* DTImage+HTML.h in Headers */,
+ A7081EA415036460002987F1 /* DTTextBlock.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1330,6 +1342,7 @@
A7F5672914D8506C00D1F167 /* NSAttributedString+SmallCaps.m in Sources */,
A7C7ACD714D924B1005A9C69 /* NSMutableString+HTML.m in Sources */,
A7B0B56A14D9921F0091C2C9 /* NSAttributedString+DTCoreText.m in Sources */,
+ A7081EA515036460002987F1 /* DTTextBlock.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1375,6 +1388,7 @@
A7F5672A14D8506C00D1F167 /* NSAttributedString+SmallCaps.m in Sources */,
A7C7ACD814D924B1005A9C69 /* NSMutableString+HTML.m in Sources */,
A7B0B56B14D9921F0091C2C9 /* NSAttributedString+DTCoreText.m in Sources */,
+ A7081EA615036460002987F1 /* DTTextBlock.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1423,6 +1437,7 @@
A7C7AD0F14DA7C2D005A9C69 /* NSAttributedStringHTMLTest.m in Sources */,
A7C7AD1014DA7C2D005A9C69 /* NSStringHTMLTest.m in Sources */,
A7C7AD1114DA7C2D005A9C69 /* UIColorHTMLTest.m in Sources */,
+ A7081EA715036460002987F1 /* DTTextBlock.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1456,6 +1471,7 @@
A7C7AD0114DA6955005A9C69 /* NSString+SlashEscaping.m in Sources */,
A7C7AD0814DA7C17005A9C69 /* MacUnitTest.m in Sources */,
A70A737A14FBC9060043E932 /* NSString+Paragraphs.m in Sources */,
+ A7081EA815036460002987F1 /* DTTextBlock.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
View
9 Demo/Resources/CurrentTest.html
@@ -1,7 +1,10 @@
-<p style="background-color:#1122FF;padding:15px;">
-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.
+<div style="background-color:#1122FF">
+<p>
+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.</p>
+<p> 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.
</p>
+ </div>
-<p style="background-color:#1122FF;">
+<p style="background-color:yellow;padding: 20px;">
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.
</p>
View
19 Demo/Source/DemoTextViewController.m
@@ -362,6 +362,25 @@ - (UIView *)attributedTextContentView:(DTAttributedTextContentView *)attributedT
return nil;
}
+- (BOOL)attributedTextContentView:(DTAttributedTextContentView *)attributedTextContentView shouldDrawBackgroundForTextBlock:(DTTextBlock *)textBlock frame:(CGRect)frame context:(CGContextRef)context forLayoutFrame:(DTCoreTextLayoutFrame *)layoutFrame
+{
+ UIBezierPath *roundedRect = [UIBezierPath bezierPathWithRoundedRect:frame cornerRadius:10];
+
+ CGColorRef color = [textBlock.backgroundColor CGColor];
+ if (color)
+ {
+ CGContextSetFillColorWithColor(context, color);
+ }
+ CGContextAddPath(context, [roundedRect CGPath]);
+ CGContextFillPath(context);
+
+ CGContextAddPath(context, [roundedRect CGPath]);
+ CGContextSetRGBStrokeColor(context, 0, 0, 0, 1);
+ CGContextStrokePath(context);
+
+ return NO; // draw standard background
+}
+
#pragma mark Actions

0 comments on commit 8004a34

Please sign in to comment.
Something went wrong with that request. Please try again.