Permalink
Browse files

Restructured and unified attachment handling for img, video, iframe, …

…object; implemented YouTube video support in IFRAME
  • Loading branch information...
1 parent 4a9554e commit 170bbfb5b4d96a364d72fab80223d682260c82c6 @odrobnik odrobnik committed Aug 5, 2011
@@ -57,7 +57,7 @@ - (void)layoutSubviews
[super layoutSubviews];
// after the first call here the content view size is correct
- _attributedTextContextView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
+ _attributedTextContextView.frame = self.contentView.bounds;
}
#pragma mark Properties
@@ -399,7 +399,9 @@ - (void)relayoutText
// set frame to fit text preserving origin
// call super to avoid endless loop
+ [self willChangeValueForKey:@"frame"];
super.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, neededSize.width, neededSize.height);
+ [self didChangeValueForKey:@"frame"];
}
[self setNeedsDisplay];
@@ -179,9 +179,9 @@ - (void)setBackgroundView:(UIView *)newBackgroundView
- (void)setAttributedString:(NSAttributedString *)string
{
self.contentView.attributedString = string;
-
- // contentView resizes itself after layout
- // self.contentSize is updated through KVO
+
+ // adjust content size right away
+ self.contentSize = self.contentView.frame.size;
}
- (NSAttributedString *)attributedString
View
@@ -94,7 +94,8 @@ typedef enum
NSInteger _listDepth;
NSInteger _listCounter;
- NSMutableArray *children;
+ NSMutableArray *_children;
+ NSDictionary *_attributes; // contains all attributes from parsing
}
@property (nonatomic, assign) DTHTMLElement *parent;
@@ -121,9 +122,9 @@ typedef enum
@property (nonatomic, assign) DTHTMLElementListStyle listStyle;
@property (nonatomic, assign) CGFloat textScale;
@property (nonatomic, assign) CGSize size;
-@property (nonatomic, readonly) NSArray *children;
@property (nonatomic, readonly) NSInteger listDepth;
@property (nonatomic) NSInteger listCounter;
+@property (nonatomic, retain) NSDictionary *attributes;
- (NSAttributedString *)attributedString;
@@ -135,6 +136,8 @@ typedef enum
- (NSString *)path;
+- (NSString *)attributeForKey:(NSString *)key;
+
- (void)addChild:(DTHTMLElement *)child;
- (void)removeChild:(DTHTMLElement *)child;
View
@@ -15,10 +15,12 @@
#import "NSCharacterSet+HTML.h"
#import "DTTextAttachment.h"
#import "NSAttributedString+HTML.h"
+#import "NSMutableAttributedString+HTML.h"
@interface DTHTMLElement ()
@property (nonatomic, retain) NSMutableDictionary *fontCache;
+@property (nonatomic, retain) NSMutableArray *children;
@end
@@ -34,7 +36,6 @@ - (id)init
_isMeta = -1;
_listDepth = -1;
_listCounter = NSIntegerMin;
- children = [NSMutableArray array];
}
return self;
@@ -61,6 +62,9 @@ - (void)dealloc
[_fontCache release];
[_additionalAttributes release];
+ [_attributes release];
+ [_children release];
+
[super dealloc];
}
@@ -200,7 +204,24 @@ - (NSAttributedString *)attributedString
if (textAttachment)
{
// ignore text, use unicode object placeholder
- return [[[NSAttributedString alloc] initWithString:UNICODE_OBJECT_PLACEHOLDER attributes:attributes] autorelease];
+ NSMutableAttributedString *tmpString = [[[NSMutableAttributedString alloc] initWithString:UNICODE_OBJECT_PLACEHOLDER attributes:attributes] autorelease];
+
+ BOOL needsNewLineAfter = ![self isContainedInBlockElement];
+
+#if ALLOW_IPHONE_SPECIAL_CASES
+ // workaround, make float images blocks because we have no float
+ if (floatStyle || textAttachment.displaySize.height > 2.0 * fontDescriptor.pointSize)
+ {
+ needsNewLineAfter = YES;
+ }
+#endif
+
+ if (needsNewLineAfter)
+ {
+ [tmpString appendNakedString:@"\n"];
+ }
+
+ return tmpString;
}
else
{
@@ -678,12 +699,12 @@ - (void)addAdditionalAttribute:(id)attribute forKey:(id)key
- (void)addChild:(DTHTMLElement *)child
{
child.parent = self;
- [children addObject:child];
+ [self.children addObject:child];
}
- (void)removeChild:(DTHTMLElement *)child
{
- [children removeObject:child];
+ [self.children removeObject:child];
}
- (DTHTMLElement *)parentWithTagName:(NSString *)name
@@ -711,6 +732,10 @@ - (BOOL)isContainedInBlockElement
return YES;
}
+- (NSString *)attributeForKey:(NSString *)key
+{
+ return [_attributes objectForKey:key];
+}
#pragma mark Copying
@@ -912,6 +937,29 @@ - (void)setListCounter:(NSInteger)count
_listCounter = count;
}
+- (NSMutableArray *)children
+{
+ if (!_children)
+ {
+ _children = [[NSMutableArray alloc] init];
+ }
+
+ return _children;
+}
+
+- (void)setAttributes:(NSDictionary *)attributes
+{
+ if (_attributes != attributes)
+ {
+ [_attributes release];
+ _attributes = [attributes retain];
+
+ // decode size contained in attributes, might be overridden later by CSS size
+ size = CGSizeMake([[self attributeForKey:@"width"] floatValue], [[self attributeForKey:@"height"] floatValue]);
+ }
+}
+
+
@synthesize parent;
@synthesize fontDescriptor;
@synthesize paragraphStyle;
@@ -937,7 +985,8 @@ - (void)setListCounter:(NSInteger)count
@synthesize size;
@synthesize fontCache = _fontCache;
-@synthesize children;
+@synthesize children = _children;
+@synthesize attributes = _attributes;
@@ -8,12 +8,14 @@
#import <Foundation/Foundation.h>
+@class DTHTMLElement;
typedef enum
{
DTTextAttachmentTypeImage,
DTTextAttachmentTypeVideoURL,
-
+ DTTextAttachmentTypeIframe,
+ DTTextAttachmentTypeObject
} DTTextAttachmentType;
@@ -38,4 +40,7 @@ typedef enum
@property (nonatomic, retain) NSURL *hyperLinkURL;
@property (nonatomic, retain) NSDictionary *attributes;
+
++ (DTTextAttachment *)textAttachmentWithElement:(DTHTMLElement *)element options:(NSDictionary *)options;
+
@end
View
@@ -7,10 +7,175 @@
//
#import "DTTextAttachment.h"
-
+#import "DTHTMLElement.h"
+#import "CGUtils.h"
+#import "NSAttributedString+HTML.h"
+#import "NSData+Base64.h"
@implementation DTTextAttachment
+
+
+
++ (DTTextAttachment *)textAttachmentWithElement:(DTHTMLElement *)element options:(NSDictionary *)options
+{
+ // determine type
+ DTTextAttachmentType attachmentType;
+
+ if ([element.tagName isEqualToString:@"img"])
+ {
+ attachmentType = DTTextAttachmentTypeImage;
+ }
+ else if ([element.tagName isEqualToString:@"video"])
+ {
+ attachmentType = DTTextAttachmentTypeVideoURL;
+ }
+ else if ([element.tagName isEqualToString:@"iframe"])
+ {
+ attachmentType = DTTextAttachmentTypeIframe;
+ }
+ else if ([element.tagName isEqualToString:@"object"])
+ {
+ attachmentType = DTTextAttachmentTypeObject;
+ }
+ else
+ {
+ return nil;
+ }
+
+ // determine if there is a display size restriction
+ CGSize maxImageSize = CGSizeZero;
+
+ NSValue *maxImageSizeValue =[options objectForKey:DTMaxImageSize];
+ if (maxImageSizeValue)
+ {
+ maxImageSize = [maxImageSizeValue CGSizeValue];
+ }
+
+ // width, height from tag
+ CGSize displaySize = element.size; // width/height from attributes or CSS style
+ CGSize originalSize = CGSizeZero;
+
+ // get base URL
+ NSURL *baseURL = [options objectForKey:NSBaseURLDocumentOption];
+
+ // decode URL
+ NSString *src = [element attributeForKey:@"src"];
+
+ NSURL *contentURL = nil;
+ UIImage *decodedImage = nil;
+
+
+ // decode content URL
+ if ([src hasPrefix:@"data:"])
+ {
+ NSRange range = [src rangeOfString:@"base64,"];
+
+ if (range.length)
+ {
+ NSString *encodedData = [src substringFromIndex:range.location + range.length];
+ NSData *decodedData = [NSData dataFromBase64String:encodedData];
+
+ decodedImage = [UIImage imageWithData:decodedData];
+ originalSize = decodedImage.size;
+
+ if (!displaySize.width || !displaySize.height)
+ {
+ displaySize = originalSize;
+ }
+ }
+ }
+ else // normal URL
+ {
+ contentURL = [NSURL URLWithString:src];
+
+ if (![contentURL scheme])
+ {
+ // possibly a relative url
+ if (baseURL)
+ {
+ contentURL = [NSURL URLWithString:src relativeToURL:baseURL];
+ }
+ else
+ {
+ // file in app bundle
+ NSString *path = [[NSBundle mainBundle] pathForResource:src ofType:nil];
+ if (path) {
+ // Prevent a crash if path turns up nil.
+ contentURL = [NSURL fileURLWithPath:path];
+ }
+ }
+ }
+ }
+
+ DTTextAttachment *attachment = [[DTTextAttachment alloc] init];
+
+ // for local images we can get their size by inspecting them
+ if (attachmentType == DTTextAttachmentTypeImage)
+ {
+ // if it's a local file we need to inspect it to get it's dimensions
+ if (!displaySize.width || !displaySize.height)
+ {
+ // inspect local file
+ if ([contentURL isFileURL])
+ {
+ UIImage *image = [UIImage imageWithContentsOfFile:[contentURL path]];
+ originalSize = image.size;
+
+ if (!displaySize.width || !displaySize.height)
+ {
+ displaySize = originalSize;
+ }
+ }
+ else
+ {
+ // remote image, we have to relayout once this size is known
+ displaySize = CGSizeMake(1, 1); // one pixel so that loading is triggered
+ }
+ }
+
+ // we copy the link because we might need for it making the custom view
+ if (element.link)
+ {
+ attachment.hyperLinkURL = element.link;
+ }
+ }
+
+
+ // if you have no display size we assume original size
+ if (CGSizeEqualToSize(displaySize, CGSizeZero))
+ {
+ displaySize = originalSize;
+ }
+
+ // adjust the display size if there is a restriction and it's too large
+ CGSize adjustedSize = displaySize;
+
+ if (maxImageSize.width>0 && maxImageSize.height>0)
+ {
+ if (maxImageSize.width < displaySize.width || maxImageSize.height < displaySize.height)
+ {
+ adjustedSize = sizeThatFitsKeepingAspectRatio(displaySize, maxImageSize);
+ }
+
+ // still no display size? use max size
+ if (CGSizeEqualToSize(displaySize, CGSizeZero))
+ {
+ adjustedSize = maxImageSize;
+ }
+ }
+
+ attachment.contentType = attachmentType;
+ attachment.contentURL = contentURL;
+ attachment.contents = decodedImage;
+ attachment.originalSize = originalSize;
+ attachment.displaySize = adjustedSize;
+ attachment.attributes = element.attributes;
+
+ return [attachment autorelease];
+}
+
+
- (void) dealloc
{
[contents release];
Oops, something went wrong.

0 comments on commit 170bbfb

Please sign in to comment.