| 1 |
// |
|---|
| 2 |
// SubContext.m |
|---|
| 3 |
// SSARender2 |
|---|
| 4 |
// |
|---|
| 5 |
// Created by Alexander Strange on 7/28/07. |
|---|
| 6 |
// Copyright 2007 __MyCompanyName__. All rights reserved. |
|---|
| 7 |
// |
|---|
| 8 |
|
|---|
| 9 |
#import "SubContext.h" |
|---|
| 10 |
#import "SubParsing.h" |
|---|
| 11 |
|
|---|
| 12 |
@implementation SubStyle |
|---|
| 13 |
|
|---|
| 14 |
SubRGBAColor ParseSSAColor(unsigned rgb) |
|---|
| 15 |
{ |
|---|
| 16 |
unsigned char r, g, b, a; |
|---|
| 17 |
|
|---|
| 18 |
a = (rgb >> 24) & 0xff; |
|---|
| 19 |
b = (rgb >> 16) & 0xff; |
|---|
| 20 |
g = (rgb >> 8) & 0xff; |
|---|
| 21 |
r = rgb & 0xff; |
|---|
| 22 |
|
|---|
| 23 |
a = 255-a; |
|---|
| 24 |
|
|---|
| 25 |
return (SubRGBAColor){r/255.,g/255.,b/255.,a/255.}; |
|---|
| 26 |
} |
|---|
| 27 |
|
|---|
| 28 |
static SubRGBAColor ParseSSAColorString(NSString *c) |
|---|
| 29 |
{ |
|---|
| 30 |
const char *c_ = [c UTF8String]; |
|---|
| 31 |
unsigned int rgb; |
|---|
| 32 |
|
|---|
| 33 |
if (c_[0] == '&') { |
|---|
| 34 |
rgb = strtoul(&c_[2],NULL,16); |
|---|
| 35 |
} else { |
|---|
| 36 |
rgb = strtol(c_,NULL,0); |
|---|
| 37 |
} |
|---|
| 38 |
|
|---|
| 39 |
return ParseSSAColor(rgb); |
|---|
| 40 |
} |
|---|
| 41 |
|
|---|
| 42 |
UInt8 SSA2ASSAlignment(UInt8 a) |
|---|
| 43 |
{ |
|---|
| 44 |
int h = 1, v = 0; |
|---|
| 45 |
if (a >= 9 && a <= 11) {v = kSubAlignmentMiddle; h = a-8;} |
|---|
| 46 |
if (a >= 5 && a <= 7) {v = kSubAlignmentTop; h = a-4;} |
|---|
| 47 |
if (a >= 1 && a <= 3) {v = kSubAlignmentBottom; h = a;} |
|---|
| 48 |
return v * 3 + h; |
|---|
| 49 |
} |
|---|
| 50 |
|
|---|
| 51 |
void ParseASSAlignment(UInt8 a, UInt8 *alignH, UInt8 *alignV) |
|---|
| 52 |
{ |
|---|
| 53 |
switch (a) { |
|---|
| 54 |
default: case 1 ... 3: *alignV = kSubAlignmentBottom; break; |
|---|
| 55 |
case 4 ... 6: *alignV = kSubAlignmentMiddle; break; |
|---|
| 56 |
case 7 ... 9: *alignV = kSubAlignmentTop; break; |
|---|
| 57 |
} |
|---|
| 58 |
|
|---|
| 59 |
switch (a) { |
|---|
| 60 |
case 1: case 4: case 7: *alignH = kSubAlignmentLeft; break; |
|---|
| 61 |
default: case 2: case 5: case 8: *alignH = kSubAlignmentCenter; break; |
|---|
| 62 |
case 3: case 6: case 9: *alignH = kSubAlignmentRight; break; |
|---|
| 63 |
} |
|---|
| 64 |
} |
|---|
| 65 |
|
|---|
| 66 |
BOOL ParseFontVerticality(NSString **fontname) |
|---|
| 67 |
{ |
|---|
| 68 |
if ([*fontname characterAtIndex:0] == '@') { |
|---|
| 69 |
*fontname = [*fontname substringFromIndex:1]; |
|---|
| 70 |
return YES; |
|---|
| 71 |
} |
|---|
| 72 |
return NO; |
|---|
| 73 |
} |
|---|
| 74 |
|
|---|
| 75 |
+(SubStyle*)defaultStyleWithDelegate:(SubRenderer*)delegate |
|---|
| 76 |
{ |
|---|
| 77 |
SubStyle *sty = [[[SubStyle alloc] init] autorelease]; |
|---|
| 78 |
|
|---|
| 79 |
sty->name = @"*Default"; |
|---|
| 80 |
sty->fontname = @"Helvetica"; |
|---|
| 81 |
sty->platformSizeScale = 1; |
|---|
| 82 |
sty->size = 32 * sqrt([delegate aspectRatio] / (4./3.)); |
|---|
| 83 |
sty->primaryColor = (SubRGBAColor){1,1,1,1}; |
|---|
| 84 |
sty->outlineColor = (SubRGBAColor){0,0,0,1}; |
|---|
| 85 |
sty->shadowColor = (SubRGBAColor){0,0,0,1}; |
|---|
| 86 |
sty->scaleX = sty->scaleY = 100; |
|---|
| 87 |
sty->tracking = sty->angle = 0; |
|---|
| 88 |
sty->outlineRadius = 1.5; |
|---|
| 89 |
sty->shadowDist = 2; |
|---|
| 90 |
sty->marginL = sty->marginR = sty->marginV = 20; |
|---|
| 91 |
sty->bold = YES; |
|---|
| 92 |
sty->italic = sty->underline = sty->strikeout = NO; |
|---|
| 93 |
sty->alignH = kSubAlignmentCenter; |
|---|
| 94 |
sty->alignV = kSubAlignmentBottom; |
|---|
| 95 |
sty->borderStyle = kSubBorderStyleNormal; |
|---|
| 96 |
sty->ex = [delegate completedStyleParsing:sty]; |
|---|
| 97 |
sty->delegate = delegate; |
|---|
| 98 |
return sty; |
|---|
| 99 |
} |
|---|
| 100 |
|
|---|
| 101 |
-(SubStyle*)initWithDictionary:(NSDictionary *)s scriptVersion:(UInt8)version delegate:(SubRenderer*)delegate_ |
|---|
| 102 |
{ |
|---|
| 103 |
if (self = [super init]) { |
|---|
| 104 |
NSString *tmp; |
|---|
| 105 |
delegate = delegate_; |
|---|
| 106 |
NSString *sv; |
|---|
| 107 |
|
|---|
| 108 |
#define sv(fn, n) fn = [[s objectForKey: @""#n] retain] |
|---|
| 109 |
#define fv(fn, n) sv = [s objectForKey:@""#n]; fn = sv ? [sv floatValue] : 0.; |
|---|
| 110 |
#define iv(fn, n) fn = [[s objectForKey:@""#n] intValue] |
|---|
| 111 |
#define bv(fn, n) fn = [[s objectForKey:@""#n] intValue] != 0 |
|---|
| 112 |
#define cv(fn, n) tmp = [s objectForKey:@""#n]; if (tmp) fn = ParseSSAColorString(tmp); |
|---|
| 113 |
|
|---|
| 114 |
sv(name, Name); |
|---|
| 115 |
sv(fontname, Fontname); |
|---|
| 116 |
fv(size, Fontsize); |
|---|
| 117 |
cv(primaryColor, PrimaryColour); |
|---|
| 118 |
cv(secondaryColor, SecondaryColour); |
|---|
| 119 |
tmp = [s objectForKey:@"BackColour"]; |
|---|
| 120 |
if (tmp) outlineColor = shadowColor = ParseSSAColorString(tmp); |
|---|
| 121 |
cv(outlineColor, OutlineColour); |
|---|
| 122 |
cv(shadowColor, ShadowColour); |
|---|
| 123 |
bv(bold, Bold); |
|---|
| 124 |
bv(italic, Italic); |
|---|
| 125 |
bv(underline, Underline); |
|---|
| 126 |
bv(strikeout, Strikeout); |
|---|
| 127 |
fv(scaleX, ScaleX); |
|---|
| 128 |
fv(scaleY, ScaleY); |
|---|
| 129 |
fv(tracking, Spacing); |
|---|
| 130 |
fv(angle, Angle); |
|---|
| 131 |
fv(outlineRadius, Outline); |
|---|
| 132 |
fv(shadowDist, Shadow); |
|---|
| 133 |
iv(marginL, MarginL); |
|---|
| 134 |
iv(marginR, MarginR); |
|---|
| 135 |
iv(marginV, MarginV); |
|---|
| 136 |
iv(borderStyle, BorderStyle); |
|---|
| 137 |
|
|---|
| 138 |
if (!scaleX) scaleX = 100; |
|---|
| 139 |
if (!scaleY) scaleY = 100; |
|---|
| 140 |
|
|---|
| 141 |
UInt8 align = [[s objectForKey:@"Alignment"] intValue]; |
|---|
| 142 |
if (version == kSubTypeSSA) align = SSA2ASSAlignment(align); |
|---|
| 143 |
|
|---|
| 144 |
ParseASSAlignment(align, &alignH, &alignV); |
|---|
| 145 |
|
|---|
| 146 |
platformSizeScale = 0; |
|---|
| 147 |
ex = [delegate completedStyleParsing:self]; |
|---|
| 148 |
} |
|---|
| 149 |
|
|---|
| 150 |
return self; |
|---|
| 151 |
} |
|---|
| 152 |
|
|---|
| 153 |
static NSString *yes(int i) {return i ? @"yes" : @"no";} |
|---|
| 154 |
|
|---|
| 155 |
static NSString *ColorString(SubRGBAColor *c) |
|---|
| 156 |
{ |
|---|
| 157 |
return [NSString stringWithFormat:@"{R: %d G: %d B: %d A: %d}", (int)(c->red * 255), |
|---|
| 158 |
(int)(c->green * 255), (int)(c->blue * 255), (int)(c->alpha * 255)]; |
|---|
| 159 |
} |
|---|
| 160 |
|
|---|
| 161 |
-(NSString *)description |
|---|
| 162 |
{ |
|---|
| 163 |
static const NSString *alignHStr[] = {@"left", @"center", @"right"}; |
|---|
| 164 |
static const NSString *alignVStr[] = {@"bottom", @"middle", @"top"}; |
|---|
| 165 |
static const NSString *bstyle[] = {@"normal", @"box"}; |
|---|
| 166 |
|
|---|
| 167 |
return [NSString stringWithFormat:@"" |
|---|
| 168 |
"SubStyle named \"%@\"\n" |
|---|
| 169 |
"-Font: %f pt %@\n" |
|---|
| 170 |
"-Primary color: %@\n" |
|---|
| 171 |
"-Secondary color: %@\n" |
|---|
| 172 |
"-Outline: %f px %@\n" |
|---|
| 173 |
"-Shadow: %f px %@\n" |
|---|
| 174 |
"-Margin: %d px left, %d px right, %d px vertical\n" |
|---|
| 175 |
"-Bold: %@ Italic: %@ Underline: %@ Strikeout: %@\n" |
|---|
| 176 |
"-Alignment: %@ %@\n" |
|---|
| 177 |
"-Border style: %@\n" |
|---|
| 178 |
"-Per-font scale: %f\n", |
|---|
| 179 |
name, size, fontname, ColorString(&primaryColor), |
|---|
| 180 |
ColorString(&secondaryColor), outlineRadius, ColorString(&outlineColor), |
|---|
| 181 |
shadowDist, ColorString(&shadowColor), marginL, marginR, marginV, |
|---|
| 182 |
yes(bold), yes(italic), yes(underline), yes(strikeout), alignHStr[alignH], |
|---|
| 183 |
alignVStr[alignV], bstyle[borderStyle], platformSizeScale]; |
|---|
| 184 |
} |
|---|
| 185 |
|
|---|
| 186 |
-(void)dealloc |
|---|
| 187 |
{ |
|---|
| 188 |
[name release]; |
|---|
| 189 |
[fontname release]; |
|---|
| 190 |
[delegate releaseStyleExtra:ex]; |
|---|
| 191 |
[super dealloc]; |
|---|
| 192 |
} |
|---|
| 193 |
|
|---|
| 194 |
-(void)finalize |
|---|
| 195 |
{ |
|---|
| 196 |
[delegate releaseStyleExtra:ex]; |
|---|
| 197 |
[super finalize]; |
|---|
| 198 |
} |
|---|
| 199 |
@end |
|---|
| 200 |
|
|---|
| 201 |
@implementation SubContext |
|---|
| 202 |
|
|---|
| 203 |
BOOL IsScriptASS(NSDictionary *headers) |
|---|
| 204 |
{ |
|---|
| 205 |
return [[[headers objectForKey:@"ScriptType"] lowercaseString] isEqualToString:@"v4.00+"]; |
|---|
| 206 |
} |
|---|
| 207 |
|
|---|
| 208 |
-(void)readHeaders |
|---|
| 209 |
{ |
|---|
| 210 |
scriptType = IsScriptASS(headers) ? kSubTypeASS : kSubTypeSSA; |
|---|
| 211 |
collisions = [[headers objectForKey:@"Collisions"] isEqualToString:@"Reverse"] ? kSubCollisionsReverse : kSubCollisionsNormal; |
|---|
| 212 |
wrapStyle = [[headers objectForKey:@"WrapStyle"] intValue]; |
|---|
| 213 |
|
|---|
| 214 |
NSString *resXS = [headers objectForKey:@"PlayResX"], *resYS = [headers objectForKey:@"PlayResY"]; |
|---|
| 215 |
|
|---|
| 216 |
if (resXS) resX = [resXS floatValue]; |
|---|
| 217 |
if (resYS) resY = [resYS floatValue]; |
|---|
| 218 |
|
|---|
| 219 |
// obscure res rules copied from VSFilter |
|---|
| 220 |
if ((!resXS && !resYS) || (!resX && !resY)) { |
|---|
| 221 |
resX = 384; resY = 288; |
|---|
| 222 |
} else if (!resYS) { |
|---|
| 223 |
resY = (resX == 1280) ? 1024 : (resX / (4./3.)); |
|---|
| 224 |
} else if (!resXS) { |
|---|
| 225 |
resX = (resY == 1024) ? 1280 : (resY * (4./3.)); |
|---|
| 226 |
} |
|---|
| 227 |
} |
|---|
| 228 |
|
|---|
| 229 |
-(SubContext*)initWithHeaders:(NSDictionary *)headers_ styles:(NSArray *)styles_ extraData:(NSString *)ed delegate:(SubRenderer*)delegate |
|---|
| 230 |
{ |
|---|
| 231 |
if (self = [super init]) { |
|---|
| 232 |
headertext = [ed retain]; |
|---|
| 233 |
headers = [headers_ retain]; |
|---|
| 234 |
[self readHeaders]; |
|---|
| 235 |
|
|---|
| 236 |
[delegate completedHeaderParsing:self]; |
|---|
| 237 |
|
|---|
| 238 |
styles = nil; |
|---|
| 239 |
if (styles_) { |
|---|
| 240 |
int i, nstyles = [styles_ count]; |
|---|
| 241 |
NSMutableDictionary *sdict = [[NSMutableDictionary alloc] initWithCapacity:nstyles]; |
|---|
| 242 |
|
|---|
| 243 |
for (i=0; i < nstyles; i++) { |
|---|
| 244 |
NSDictionary *style = [styles_ objectAtIndex:i]; |
|---|
| 245 |
[sdict setObject:[[[SubStyle alloc] initWithDictionary:style scriptVersion:scriptType delegate:delegate] autorelease] |
|---|
| 246 |
forKey:[style objectForKey:@"Name"]]; |
|---|
| 247 |
} |
|---|
| 248 |
|
|---|
| 249 |
styles = sdict; |
|---|
| 250 |
} |
|---|
| 251 |
|
|---|
| 252 |
defaultStyle = [styles objectForKey:@"Default"]; |
|---|
| 253 |
if (!defaultStyle) defaultStyle = [SubStyle defaultStyleWithDelegate:delegate]; |
|---|
| 254 |
[defaultStyle retain]; |
|---|
| 255 |
|
|---|
| 256 |
} |
|---|
| 257 |
|
|---|
| 258 |
return self; |
|---|
| 259 |
} |
|---|
| 260 |
|
|---|
| 261 |
-(SubContext*)initWithNonSSAType:(UInt8)type delegate:(SubRenderer*)delegate |
|---|
| 262 |
{ |
|---|
| 263 |
if (self = [super init]) { |
|---|
| 264 |
resX = 640; |
|---|
| 265 |
resY = 480; |
|---|
| 266 |
scriptType = type; |
|---|
| 267 |
collisions = kSubCollisionsNormal; |
|---|
| 268 |
wrapStyle = kSubLineWrapBottomWider; |
|---|
| 269 |
styles = headers = nil; |
|---|
| 270 |
headertext = nil; |
|---|
| 271 |
[delegate completedHeaderParsing:self]; |
|---|
| 272 |
|
|---|
| 273 |
defaultStyle = [[SubStyle defaultStyleWithDelegate:delegate] retain]; |
|---|
| 274 |
} |
|---|
| 275 |
|
|---|
| 276 |
return self; |
|---|
| 277 |
} |
|---|
| 278 |
|
|---|
| 279 |
-(void)dealloc |
|---|
| 280 |
{ |
|---|
| 281 |
[styles release]; |
|---|
| 282 |
[defaultStyle release]; |
|---|
| 283 |
[headers release]; |
|---|
| 284 |
[headertext release]; |
|---|
| 285 |
[super dealloc]; |
|---|
| 286 |
} |
|---|
| 287 |
|
|---|
| 288 |
-(SubStyle*)styleForName:(NSString *)name |
|---|
| 289 |
{ |
|---|
| 290 |
SubStyle *sty = [styles objectForKey:name]; |
|---|
| 291 |
return sty ? sty : defaultStyle; |
|---|
| 292 |
} |
|---|
| 293 |
@end |
|---|
| 294 |
|
|---|
| 295 |
@implementation SubRenderer |
|---|
| 296 |
-(void*)completedStyleParsing:(SubStyle*)s {return nil;} |
|---|
| 297 |
-(void)completedHeaderParsing:(SubContext*)sc {} |
|---|
| 298 |
-(void*)spanExtraFromRenderDiv:(SubRenderDiv*)div {return nil;} |
|---|
| 299 |
-(void*)cloneSpanExtra:(SubRenderSpan*)span {return span->ex;} |
|---|
| 300 |
-(void)spanChangedTag:(SSATagType)tag span:(SubRenderSpan*)span div:(SubRenderDiv*)div param:(void*)p {} |
|---|
| 301 |
-(void)releaseStyleExtra:(void*)ex {} |
|---|
| 302 |
-(void)releaseSpanExtra:(void*)ex {} |
|---|
| 303 |
-(float)aspectRatio {return 4./3.;} |
|---|
| 304 |
@end |
|---|