Changeset 314

Show
Ignore:
Timestamp:
01/29/07 22:17:45 (2 years ago)
Author:
astrange
Message:

Mark TextSubCodec? as thread-safe. (refs #95)
Delete all the SRT code, fold into new SSA renderer.
Misc. rendering bugfixes.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/SSADocument.h

    r313 r314  
    4747        int stylecount; 
    4848        ssastyleline *styles; 
     49        ssastyleline *defaultstyle; 
    4950         
    5051        float resX, resY; 
     
    5253        enum {Normal, Reverse} collisiontype; 
    5354        enum {S_ASS, S_SSA} version; 
     55        Boolean disposedefaultstyle; 
    5456} 
    5557-(NSString *)header; 
     
    5759-(void) loadHeader:(NSString*)path; 
    5860-(unsigned)packetCount; 
     61-(void)loadDefaultsWithWidth:(float)width height:(float)height; 
    5962@end 
    6063 
  • trunk/SSADocument.m

    r313 r314  
    2020 
    2121@implementation SSADocument 
     22 
     23static ssastyleline SSA_DefaultStyle = (ssastyleline){ 
     24        @"Default",@"Helvetica", 
     25        32 * (96./72.), 
     26{{1,1,1,1},{1,1,1,1},{0,0,0,1},{0,0,0,1}}, // white on black 
     27        1,0,0,0, 
     28        100,100,0,0, 
     29        0,1.5,1.5, 
     30        2,1,0, 
     31        10,10,10, 
     32        NULL, NULL 
     33}; 
     34 
     35-(void)dealloc 
     36{ 
     37        int i; 
     38        if (disposedefaultstyle) free(defaultstyle); 
     39        for (i=0; i < stylecount; i++) {ATSUDisposeStyle(styles[i].atsustyle); ATSUDisposeTextLayout(styles[i].layout);} 
     40         
     41        [_lines release]; 
     42        [header release]; 
     43        [super dealloc]; 
     44} 
    2245 
    2346static ATSURGBAlphaColor SSAParseColor(NSString *c) 
     
    147170-(void)setupStyles:(NSDictionary*)sDict 
    148171{ 
     172        defaultstyle = NULL; 
     173 
    149174        if ([sDict count] > 0) { 
    150175                NSEnumerator *sEnum = [sDict objectEnumerator]; 
     
    188213                         
    189214                        styles[i] = s; 
     215                        if (!defaultstyle && [styles[i].name isEqualToString:@"Default"]) {defaultstyle = &styles[i]; disposedefaultstyle = NO;} 
    190216                        i++; 
    191217                } 
     218        } 
     219         
     220        if (!defaultstyle) { 
     221                disposedefaultstyle = YES; 
     222                defaultstyle = malloc(sizeof(ssastyleline)); 
     223                *defaultstyle = SSA_DefaultStyle; 
     224                [self makeATSUStylesForSSAStyle:defaultstyle]; 
    192225        } 
    193226} 
     
    215248{ 
    216249        return [NSString stringWithFormat:@"%d,%d,%@,%@,%0.4d,%0.4d,%0.4d,%@,%@\n", 
    217                 [s objectForKey:@"ReadOrder"], 
     250                [[s objectForKey:@"ReadOrder"] intValue], 
    218251                [[s objectForKey:@"Layer"] intValue], 
    219252                [s objectForKey:@"Style"], 
     
    255288        line_range lines[num]; 
    256289        unsigned i, j; 
    257         line_range li; 
    258290        NSMutableArray *outa = [[NSMutableArray alloc] init]; 
    259291         
     
    262294                NSString *s,*e; 
    263295                l = [linesa objectAtIndex:i]; 
     296                line_range li; 
    264297                 
    265298                s = [l objectForKey:@"Start"]; 
     
    269302                li.start = ParseSSATime(s); 
    270303                li.end = ParseSSATime(e); 
     304                 
     305                if (timescale != 1.) { 
     306                        li.start *= timescale; 
     307                        li.end *= timescale; 
     308                } 
    271309                 
    272310                times[i*2] = li.start; 
     
    295333                        SSAEvent *event = [[[SSAEvent alloc] init] autorelease]; 
    296334                         
    297                         if (timescale != 1.) { 
    298                                 double ds = start, de = end; 
    299                                 ds *= timescale; 
    300                                 de *= timescale; 
    301                                 start = ds; 
    302                                 end = de; 
    303                         } 
    304335                        event->begin_time = start; 
    305336                        event->end_time = end; 
     
    462493} 
    463494 
     495-(void)loadDefaultsWithWidth:(float)width height:(float)height 
     496{ 
     497        stylecount = 0; 
     498        styles = malloc(0); 
     499        defaultstyle = malloc(sizeof(ssastyleline)); 
     500        *defaultstyle = SSA_DefaultStyle; 
     501        disposedefaultstyle = YES; 
     502        resX = (width / height) * 480.; resY = 480; 
     503        timescale = 1; 
     504        collisiontype = Normal; 
     505        version = S_ASS; 
     506         
     507        [self makeATSUStylesForSSAStyle:defaultstyle]; 
     508} 
     509 
    464510-(NSString*)header 
    465511{ 
     
    486532        ImageDescriptionHandle textDesc; 
    487533        Rect movieBox; 
    488         static UInt8 path[PATH_MAX]; 
    489534        UInt32 emptyDataRefExtension[2]; 
     535        TimeScale movieTimeScale = GetMovieTimeScale(theMovie); 
     536        UInt8 *path = malloc(PATH_MAX); 
    490537 
    491538        FSRefMakePath(theDirectory, path, PATH_MAX); 
    492539         
    493540        [ssa loadFile:[[NSString stringWithUTF8String:(char*)path] stringByAppendingPathComponent:(NSString*)filename]]; 
     541         
     542        free(path); 
    494543         
    495544        packetCount = [ssa packetCount]; 
     
    540589                if (err != noErr) goto bail; 
    541590                 
    542                 ConvertTimeScale(&movieStartTime, GetMovieTimeScale(theMovie)); 
     591                ConvertTimeScale(&movieStartTime, movieTimeScale); 
    543592 
    544593                err = InsertMediaIntoTrack(theTrack, movieStartTime.value.lo, sampleTime, p->end_time - p->begin_time, fixed1); 
  • trunk/SSARenderCodec.h

    r313 r314  
    1414 
    1515extern SSARenderGlobalsPtr SSA_Init(const char *header, size_t size); 
    16 extern void SSA_RenderLine(SSARenderGlobalsPtr glob, CGContextRef c, const char *data, size_t size, float width, float height); 
     16extern SSARenderGlobalsPtr SSA_InitNonSSA(float width, float height); 
     17extern void SSA_RenderLine(SSARenderGlobalsPtr glob, CGContextRef c, CFStringRef str, float width, float height); 
    1718extern void SSA_Dispose(SSARenderGlobalsPtr glob); 
  • trunk/SSARenderCodec.m

    r313 r314  
    1414{ 
    1515        SSADocument *document; 
     16        Boolean plaintext; 
    1617} SSARenderGlobals; 
    1718 
     
    2122        NSString *hdr = [[NSString alloc] initWithBytesNoCopy:(void*)header length:size encoding:NSUTF8StringEncoding freeWhenDone:NO]; 
    2223        g->document = [[SSADocument alloc] init]; 
     24        g->plaintext = false; 
    2325        [g->document loadHeader:hdr]; 
    2426        [hdr release]; 
     27        return g; 
     28} 
     29 
     30SSARenderGlobalsPtr SSA_InitNonSSA(float width, float height) 
     31{ 
     32        SSARenderGlobalsPtr g = (SSARenderGlobalsPtr)NewPtr(sizeof(SSARenderGlobals)); 
     33        g->document = [[SSADocument alloc] init]; 
     34        g->plaintext = true; 
     35        [g->document loadDefaultsWithWidth:width height:height]; 
    2536        return g; 
    2637} 
     
    7788} 
    7889 
    79 void SSA_RenderLine(SSARenderGlobalsPtr glob, CGContextRef c, const char *data, size_t size, float cWidth, float cHeight) 
     90void SSA_RenderLine(SSARenderGlobalsPtr glob, CGContextRef c, CFStringRef cfSub, float cWidth, float cHeight) 
    8091{ 
    8192        ItemCount breakCount; 
     
    8697        SSADocument *ssa = glob->document; 
    8798        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    88         NSString *curSub = [[NSString alloc] initWithBytesNoCopy:(void*)data length:size encoding:NSUTF8StringEncoding freeWhenDone:NO]
    89         NSArray *rentities = ParseSubPacket(curSub,ssa); 
     99        NSString *curSub = (NSString*)cfSub
     100        NSArray *rentities = ParseSubPacket(curSub,ssa,glob->plaintext); 
    90101        OSStatus err; 
    91102         
     103        CGContextClearRect(c, CGRectMake(0,0,cWidth,cHeight)); 
    92104        CGContextScaleCTM(c, cWidth / ssa->resX, cHeight / ssa->resY); 
    93105        subcount = [rentities count]; 
     
    100112                 
    101113                size_t sublen = [re->nstext length]; 
    102                                  
     114                                                
    103115                err=ATSUSetTextPointerLocation(layout,re->text,kATSUFromTextBeginning,kATSUToTextEnd,sublen); 
    104116                 
     
    132144                                case S_BottomAlign: default: //bottom 
    133145                                        ATSUGetLineControl(layout, kATSUFromTextBeginning, kATSULineDescentTag, sizeof(ATSUTextMeasurement), &descent, NULL); 
    134                                         penY = (lastBottomPenY!=-1)?lastBottomPenY:(MAX(IntToFixed(re->marginv), descent)); direction = 1; 
     146                                        penY = (lastBottomPenY!=-1)?lastBottomPenY:(MAX(IntToFixed(re->marginv), descent) + FloatToFixed(shadow)); direction = 1; 
    135147                                        lstart = breakCount; lend = -1; lstep = -1; 
    136148                                        storePenY = &lastBottomPenY; 
     
    245257        } 
    246258         
    247         [curSub release]; 
    248259        [pool release]; 
    249         CGContextSynchronize(c);         
    250         CGContextRelease(c); 
    251260} 
    252261 
  • trunk/SSATagParsing.h

    r310 r314  
    3737@end 
    3838 
    39 extern NSArray *ParseSubPacket(NSString *str, SSADocument *ssa); 
     39extern NSArray *ParseSubPacket(NSString *str, SSADocument *ssa, Boolean plaintext); 
  • trunk/SSATagParsing.m.rl

    r313 r314  
    7070{ 
    7171        unsigned char r,g,b; 
     72        c = EndianU32_NtoB(c); 
    7273        r = c & 0xff; 
    7374        g = (c >> 8) & 0xff; 
     
    7677} 
    7778 
    78 NSArray *ParseSubPacket(NSString *str, SSADocument *ssa
     79NSArray *ParseSubPacket(NSString *str, SSADocument *ssa, Boolean plaintext
    7980{ 
    8081        NSArray *linea = [str componentsSeparatedByString:@"\n"]; 
    81         int i, pcount = [linea count]; unsigned len; 
     82        int i, j, pcount = [linea count]; unsigned len; 
    8283        NSMutableArray *rentities = [NSMutableArray array]; 
    8384         
    8485        for (i = 0; i < pcount; i++) { 
    85                 NSArray *ar = [[linea objectAtIndex:i] componentsSeparatedByString:@"," count:9]; 
    86                 SSARenderEntity *re; 
     86                SSARenderEntity *re = [[[SSARenderEntity alloc] init] autorelease]; 
    8787                BOOL ldirty = NO; 
    8888                 
    89                 if ([ar count] < 9) continue; 
    90                  
    91                 re = [[[SSARenderEntity alloc] init] autorelease]; 
    92                 re->layer = [[ar objectAtIndex:1] intValue]; 
    93                 NSString *sn = [ar objectAtIndex:2]; 
    94                 int j; 
    95  
    96                 for (j=0; j < ssa->stylecount; j++) { 
    97                         if ([sn isEqualToString:ssa->styles[j].name])  { 
    98                                 re->style = &ssa->styles[j];  
    99                                 break; 
     89                if (plaintext) { 
     90                        re->style = ssa->defaultstyle; 
     91                        re->layout = re->style->layout; 
     92                        re->layer = 0; 
     93                        re->marginl = re->style->marginl; 
     94                        re->marginr = re->style->marginl; 
     95                        re->marginv = re->style->marginl; 
     96                        re->usablewidth = re->style->usablewidth; 
     97                        re->halign = 1; 
     98                        re->valign = 0; 
     99                        re->nstext = [linea objectAtIndex:i]; 
     100                        re->styles = NULL; 
     101                        re->disposelayout = NO; 
     102                } else { 
     103                        NSArray *ar = [[linea objectAtIndex:i] componentsSeparatedByString:@"," count:9]; 
     104 
     105                        if ([ar count] < 9) continue; 
     106                         
     107                        re->layer = [[ar objectAtIndex:1] intValue]; 
     108                        NSString *sn = [ar objectAtIndex:2]; 
     109                         
     110                        re->style = NULL; 
     111                         
     112                        for (j=0; j < ssa->stylecount; j++) { 
     113                                if ([sn isEqualToString:ssa->styles[j].name])  { 
     114                                        re->style = &ssa->styles[j];  
     115                                        break; 
     116                                } 
    100117                        } 
     118                         
     119                        if (!re->style) {                        
     120                                re->style = ssa->defaultstyle; 
     121                        } 
     122                         
     123                        re->marginl = [[ar objectAtIndex:5] intValue]; 
     124                        re->marginr = [[ar objectAtIndex:6] intValue]; 
     125                        re->marginv = [[ar objectAtIndex:7] intValue]; 
     126                         
     127                        if (re->marginl == 0) re->marginl = re->style->marginl; else ldirty = TRUE; 
     128                        if (re->marginr == 0) re->marginr = re->style->marginr; else ldirty = TRUE; 
     129                        if (re->marginv == 0) re->marginv = re->style->marginv; else ldirty = TRUE; 
     130                         
     131                        if (ldirty) { 
     132                                ATSUTextMeasurement width; 
     133                                ATSUAttributeTag tag[] = {kATSULineWidthTag}; 
     134                                ByteCount                size[] = {sizeof(ATSUTextMeasurement)}; 
     135                                ATSUAttributeValuePtr val[] = {&width}; 
     136                                 
     137                                re->usablewidth = ssa->resX - re->marginl - re->marginr;  
     138                                ATSUCreateAndCopyTextLayout(re->style->layout,&re->layout); 
     139                                width = IntToFixed(re->usablewidth); 
     140                                 
     141                                ATSUSetLayoutControls(re->layout,1,tag,size,val); 
     142                                re->disposelayout = YES; 
     143                        } else { 
     144                                re->usablewidth = re->style->usablewidth; 
     145                                re->layout = re->style->layout; 
     146                                re->disposelayout = NO; 
     147                        } 
     148                         
     149                        re->nstext = [ar objectAtIndex:8]; 
    101150                } 
    102                  
    103                 re->marginl = [[ar objectAtIndex:5] intValue]; 
    104                 re->marginr = [[ar objectAtIndex:6] intValue]; 
    105                 re->marginv = [[ar objectAtIndex:7] intValue]; 
    106                  
    107                 if (re->marginl == 0) re->marginl = re->style->marginl; else ldirty = TRUE; 
    108                 if (re->marginr == 0) re->marginr = re->style->marginr; else ldirty = TRUE; 
    109                 if (re->marginv == 0) re->marginv = re->style->marginv; else ldirty = TRUE; 
    110                  
    111                 if (ldirty) { 
    112                         ATSUTextMeasurement width; 
    113                         ATSUAttributeTag tag[] = {kATSULineWidthTag}; 
    114                         ByteCount                size[] = {sizeof(ATSUTextMeasurement)}; 
    115                         ATSUAttributeValuePtr val[] = {&width}; 
    116                          
    117                         re->usablewidth = ssa->resX - re->marginl - re->marginr;  
    118                         ATSUCreateAndCopyTextLayout(re->style->layout,&re->layout); 
    119                         width = IntToFixed(re->usablewidth); 
    120                          
    121                         ATSUSetLayoutControls(re->layout,1,tag,size,val); 
    122                         re->disposelayout = YES; 
    123                 } else { 
    124                         re->usablewidth = re->style->usablewidth; 
    125                         re->layout = re->style->layout; 
    126                         re->disposelayout = NO; 
    127                 } 
    128                  
    129                 re->nstext = [ar objectAtIndex:8]; 
    130151                len = [re->nstext length]; 
    131152                re->text = malloc(sizeof(unichar[len])); 
     
    170191                        unsigned long inum; 
    171192                        unsigned outputoffset=0, lengthreduce=0; 
    172                         BOOL flag, newLayout=FALSE, cur_be
     193                        BOOL flag, newLayout=FALSE, cur_be = FALSE
    173194                        Fixed fixv; 
    174195                         
     
    353374                                } 
    354375                                 
    355                                 flag = [01] > {flag = *p - '0';}; 
     376                                flag = [01]? > {flag = 1;} % {flag = *(p-1) - '0';}; 
    356377                                num_ = digit+ ('.' digit*)?; 
    357378                                num = num_ > {numbegin = p;} % {num = [[NSString stringWithCharacters:numbegin length:p-numbegin] doubleValue];}; 
  • trunk/TextSubCodec.c

    r313 r314  
    3030         
    3131        CGColorSpaceRef         colorSpace; 
    32          
    33         ATSUStyle                               textStyle, italicStyle, boldStyle, biStyle; 
    34         ATSUTextLayout                  textLayout; 
    3532 
    3633        SSARenderGlobalsPtr             ssa; 
    37         Boolean                                 useSSA
     34        Boolean                                 translateSRT
    3835} TextSubGlobalsRecord, *TextSubGlobals; 
    3936 
     
    4946} TextSubDecompressRecord; 
    5047 
    51 static CFMutableStringRef CFStringCreateWithCStringMutable(CFAllocatorRef alloc, const char *cStr, CFStringEncoding encoding) { 
    52         CFStringRef                s1 = CFStringCreateWithCString(alloc,cStr,encoding); 
    53         if (!s1) return NULL; 
    54         CFMutableStringRef s2 = CFStringCreateMutableCopy(alloc,0,s1); 
    55         CFRelease(s1); 
    56         return s2; 
    57 } 
    58  
    59 static size_t ParseSrtStyles(TextSubGlobals glob, CFMutableStringRef cfsub, UniChar *uc, size_t sublen); 
    60 static inline int min(int a, int b) {return (a<=b)?a:b;} 
    61  
    6248// Setup required for ComponentDispatchHelper.c 
    6349#define IMAGECODEC_BASENAME()           TextSubCodec 
     
    8470#endif 
    8571         
     72static CFMutableStringRef CFStringCreateMutableWithBytes(CFAllocatorRef alloc, char *cStr, size_t size, CFStringEncoding encoding) { 
     73        CFStringRef                s1 = CFStringCreateWithBytes(alloc,(UInt8*)cStr,size,encoding,false); 
     74        if (!s1) return NULL; 
     75        CFMutableStringRef s2 = CFStringCreateMutableCopy(alloc,0,s1); 
     76        CFRelease(s1); 
     77        return s2; 
     78} 
     79 
    8680/* -- This Image Decompressor Uses the Base Image Decompressor Component -- 
    8781        The base image decompressor is an Apple-supplied component 
     
    109103        glob->drawBandUPP = NULL; 
    110104        glob->ssa = NULL; 
    111         glob->useSSA = false; 
    112105         
    113106        // Open and target an instance of the base decompressor as we delegate 
     
    139132                        CGColorSpaceRelease(glob->colorSpace); 
    140133                } 
    141                 if (glob->textStyle) { 
    142                         ATSUDisposeStyle(glob->textStyle); 
    143                 } 
    144                 if (glob->italicStyle) { 
    145                         ATSUDisposeStyle(glob->italicStyle); 
    146                 } 
    147                 if (glob->boldStyle) { 
    148                         ATSUDisposeStyle(glob->boldStyle); 
    149                 } 
    150                 if (glob->boldStyle) { 
    151                         ATSUDisposeStyle(glob->biStyle); 
    152                 } 
    153                 if (glob->textLayout) { 
    154                         ATSUDisposeTextLayout(glob->textLayout); 
    155                 } 
    156                 if (glob->useSSA) SSA_Dispose(glob->ssa); 
     134                if (glob->ssa) SSA_Dispose(glob->ssa); 
    157135                DisposePtr((Ptr)glob); 
    158136        } 
     
    285263    myDrp->dataSize = p->bufferSize; 
    286264         
    287         glob->useSSA = (**p->imageDescription).cType == kSubFormatSSA; 
    288         if (glob->useSSA) { 
     265        glob->translateSRT = true; 
     266         
     267        if ((**p->imageDescription).cType == kSubFormatSSA) { 
    289268                long count; 
     269                glob->translateSRT = false; 
     270 
    290271                CountImageDescriptionExtensionType(p->imageDescription,kSubFormatSSA,&count); 
    291272                if (count == 1) { 
     
    295276                        glob->ssa = SSA_Init(*ssaheader, GetHandleSize(ssaheader)); 
    296277                } 
    297         } 
     278        } else glob->ssa = SSA_InitNonSSA(myDrp->width,myDrp->height); 
    298279         
    299280        return noErr; 
     
    313294pascal ComponentResult TextSubCodecDrawBand(TextSubGlobals glob, ImageSubCodecDecompressRecord *drp) 
    314295{ 
    315         OSErr err = noErr; 
    316         int i; 
    317296        TextSubDecompressRecord *myDrp = (TextSubDecompressRecord *)drp->userDecompressRecord; 
    318         float diagonalLength = sqrtf(myDrp->width*myDrp->width+myDrp->height*myDrp->height); 
    319         ATSUTextMeasurement lineWidth = Long2Fix(myDrp->width), lineHeight = Long2Fix(25), ShadowDistFix = FloatToFixed(diagonalLength * ShadowDistance); 
    320 //      char *dataPtr = (char *)drp->codecData; 
    321 //      ICMDataProcRecordPtr dataProc = drp->dataProcRecord.dataProc ? &drp->dataProcRecord : NULL; 
    322297         
    323298    CGContextRef c = CGBitmapContextCreate(drp->baseAddr, myDrp->width, myDrp->height, 
     
    325300                                                                                   kCGImageAlphaPremultipliedFirst); 
    326301         
    327         if (glob->useSSA) { 
    328                 SSA_RenderLine(glob->ssa,c,drp->codecData,myDrp->dataSize,myDrp->width,myDrp->height); 
    329                 return noErr; 
     302        CFMutableStringRef buf; 
     303         
     304        if (glob->translateSRT) { 
     305                buf = CFStringCreateMutableWithBytes(NULL, drp->codecData, myDrp->dataSize, kCFStringEncodingUTF8); 
     306                if (!buf) return noErr; 
     307                CFStringFindAndReplace(buf, CFSTR("<i>"),  CFSTR("{\\i}"), CFRangeMake(0,CFStringGetLength(buf)), 0); 
     308                CFStringFindAndReplace(buf, CFSTR("<b>"),  CFSTR("{\\b}"), CFRangeMake(0,CFStringGetLength(buf)), 0); 
     309                CFStringFindAndReplace(buf, CFSTR("</i>"), CFSTR("{\\i0}"), CFRangeMake(0,CFStringGetLength(buf)), 0); 
     310                CFStringFindAndReplace(buf, CFSTR("</b>"), CFSTR("{\\b0}"), CFRangeMake(0,CFStringGetLength(buf)), 0); 
     311        } else { 
     312                buf = (CFMutableStringRef)CFStringCreateWithBytes(NULL, (UInt8*)drp->codecData, myDrp->dataSize, kCFStringEncodingUTF8, false); 
     313                if (!buf) return noErr; 
    330314        } 
    331315         
    332         if (!glob->textStyle) { //TODO: set language region based on track language... does that even matter? 
    333                 ATSUAttributeTag tags[] = {kATSUSizeTag, kATSUStyleRenderingOptionsTag, kATSUFontTag}; 
    334                 ByteCount                sizes[] = {sizeof(Fixed), sizeof(ATSStyleRenderingOptions), sizeof(ATSUFontID)}; 
    335                 Fixed                    size = X2Fix(diagonalLength * FontSizeRatio); 
    336                 Boolean                  trueval = TRUE; ATSUFontID fid; ATSStyleRenderingOptions rend = kATSStyleApplyAntiAliasing; 
    337                 ATSUAttributeValuePtr vals[] = {&size,&rend,&fid}; 
    338                 ATSUCreateStyle(&glob->textStyle); 
    339                 if (err = ATSUFindFontFromName(SubFontName,strlen(SubFontName),kFontFullName,kFontNoPlatform,kFontNoScript,kFontNoLanguage,&fid)) 
    340                         fprintf(stderr,"Perian: ATSUFindFontFromName error %d for font \"%s\"\n", err, SubFontName); 
    341                 ATSUSetAttributes(glob->textStyle,3, tags, sizes, vals); 
    342                  
    343                 ATSUAttributeTag ext[] = {kATSUQDItalicTag}; 
    344                 ByteCount                exs[] = {sizeof(Boolean)}; 
    345                 ATSUAttributeValuePtr exv[] = {&trueval}; 
    346                 ATSUCreateAndCopyStyle(glob->textStyle,&glob->italicStyle); 
    347                 ATSUSetAttributes(glob->italicStyle,1,ext,exs,exv); 
    348                  
    349                 ext[0] = kATSUQDBoldfaceTag; 
    350                 ATSUCreateAndCopyStyle(glob->textStyle,&glob->boldStyle); 
    351                 ATSUSetAttributes(glob->boldStyle,1,ext,exs,exv); 
    352                  
    353                 ATSUCreateAndCopyStyle(glob->italicStyle,&glob->biStyle); 
    354                 ATSUSetAttributes(glob->biStyle,1,ext,exs,exv); 
    355         } 
    356          
    357         if (!glob->textLayout) { 
    358                 ATSUAttributeTag tags[] = {kATSULineFlushFactorTag, kATSULineWidthTag}; 
    359                 ByteCount                sizes[] = {sizeof(Fract),sizeof(ATSUTextMeasurement)}; 
    360                 Fract                    lf = kATSUCenterAlignment; ATSUTextMeasurement w = Long2Fix(myDrp->width); 
    361                 ATSUAttributeValuePtr vals[] = {&lf, &w}; 
    362                 ATSUCreateTextLayout(&glob->textLayout); 
    363                 ATSUSetLayoutControls(glob->textLayout, 2, tags, sizes, vals); 
    364         } 
    365          
    366         // QuickTime doesn't like it if we complain too much 
    367     if (!c || !glob->textStyle) 
    368                 return noErr; 
    369  
    370         char textBuffer[myDrp->dataSize + 1]; 
    371          
    372         memcpy(textBuffer, drp->codecData, myDrp->dataSize); 
    373         textBuffer[myDrp->dataSize] = '\0'; 
    374  
    375         ATSUAttributeTag cgc[] = {kATSUCGContextTag}; 
    376         ByteCount cgc_s[] = {sizeof(CGContextRef)}; 
    377         ATSUAttributeValuePtr cgc_v[] = {&c}; 
    378          
    379         ATSUSetLayoutControls(glob->textLayout, 1, cgc, cgc_s, cgc_v); 
    380                  
    381         CFMutableStringRef cfsub = CFStringCreateWithCStringMutable(NULL, textBuffer, kCFStringEncodingUTF8); 
    382         if (cfsub == NULL) 
    383                 return noErr; 
    384          
    385         size_t sublen = CFStringGetLength(cfsub); 
    386          
    387         UniChar         uc[sublen]; 
    388          
    389         sublen = ParseSrtStyles(glob, cfsub, uc, sublen); 
    390          
    391         ItemCount       breakCount; 
    392  
    393         ATSUBatchBreakLines(glob->textLayout,kATSUFromTextBeginning,kATSUToTextEnd,lineWidth,&breakCount); // line wrapping 
    394         ATSUGetSoftLineBreaks(glob->textLayout,kATSUFromTextBeginning,kATSUToTextEnd,0,NULL,&breakCount); 
    395         UniCharArrayOffset breaks[breakCount+2]; // 0 = beginning, 1...n-1 automatic line breaks, n end of text 
    396         ATSUGetSoftLineBreaks(glob->textLayout,kATSUFromTextBeginning,kATSUToTextEnd,breakCount,&breaks[1],&breakCount); 
    397  
    398         breaks[0] = 0; 
    399         breaks[breakCount+1] = sublen; 
    400          
    401         CGContextSetLineJoin(c, kCGLineJoinRound); 
    402         CGContextSetLineCap(c, kCGLineCapRound); 
    403          
    404         CGContextClearRect(c, CGRectMake(0, 0, myDrp->width, myDrp->height)); 
    405         CGContextSetRGBFillColor(c, 0,0,0,1); 
    406         CGContextSetTextDrawingMode(c, kCGTextFill); 
    407  
    408         lineHeight -= ShadowDistFix; 
    409          
    410         /* Problem here: there can be "holes" between the shadow and the text from thin strokes, which is ugly. 
    411            I tried using CGContextSetShadow instead of this but it didn't seem to show up, 
    412            probably because I have to apply it to the stroke pass only... (so don't use Hoefler Text with a shadow) */ 
    413          
    414         for (i = breakCount; i >= 0; i--) { // render shadow by drawing black text at an offset 
    415                 int end = breaks[i+1]; 
    416  
    417                 ATSUDrawText(glob->textLayout, breaks[i], end-breaks[i], Long2Fix(0) + ShadowDistFix, lineHeight); 
    418                  
    419                 ATSUTextMeasurement ascent, descent; ByteCount unused; 
    420                 ATSUGetLineControl(glob->textLayout, breaks[i], kATSULineAscentTag, sizeof(ATSUTextMeasurement), &ascent, &unused); 
    421                 ATSUGetLineControl(glob->textLayout, breaks[i], kATSULineDescentTag, sizeof(ATSUTextMeasurement), &descent, &unused); 
    422  
    423                 lineHeight += ascent + descent; 
    424         } 
    425          
    426         lineHeight = Long2Fix(25); // XXX constant 
    427         CGContextSetRGBFillColor(c, 1,1,1,1); // fill white 
    428         CGContextSetRGBStrokeColor(c, 0,0,0,1); // stroke black 
    429         CGContextSetLineWidth(c, diagonalLength * BorderSizeRatio); 
    430          
    431         for (i = breakCount; i >= 0; i--) { 
    432                 int end = breaks[i+1]; 
    433                  
    434                 CGContextSetTextDrawingMode(c, kCGTextStroke); // render outline (ATSUI doesn't support outside stroke so we fake it) 
    435  
    436                 ATSUDrawText(glob->textLayout, breaks[i], end-breaks[i], Long2Fix(0), lineHeight); 
    437  
    438                 ATSUTextMeasurement ascent, descent; ByteCount unused; 
    439                 ATSUGetLineControl(glob->textLayout, breaks[i], kATSULineAscentTag, sizeof(ATSUTextMeasurement), &ascent, &unused); 
    440                 ATSUGetLineControl(glob->textLayout, breaks[i], kATSULineDescentTag, sizeof(ATSUTextMeasurement), &descent, &unused); 
    441                  
    442                 CGContextSetTextDrawingMode(c, kCGTextFill); // render filled text on top of stroke 
    443                  
    444                 ATSUDrawText(glob->textLayout, breaks[i], end-breaks[i], Long2Fix(0), lineHeight); 
    445                  
    446                 lineHeight += ascent + descent; 
    447         } 
    448  
    449         CFRelease(cfsub); 
     316        SSA_RenderLine(glob->ssa,c,buf,myDrp->width,myDrp->height); 
     317         
     318        CFRelease(buf); 
    450319        CGContextSynchronize(c); 
    451320        CGContextRelease(c); 
    452321         
    453         return err; 
     322        return noErr; 
    454323} 
    455324 
     
    534403        return err; 
    535404} 
    536  
    537 // XXX the below code is really bad, though it works; it is impossible to scale it to any more tags. needs a real parser 
    538  
    539 static CFRange *MakeStyleRanges(CFStringRef cfsub, CFStringRef open, CFStringRef close, size_t *rcount, size_t sublen) { 
    540         CFArrayRef begins, ends; size_t tagcount, tagoffset = 0, bs = CFStringGetLength(open), cs = CFStringGetLength(close), i, rcount_ = 0; 
    541         CFRange all = (CFRange){0,sublen}; 
    542         begins = CFStringCreateArrayWithFindResults(NULL,cfsub,open,all,0); 
    543         CFRange *ranges = NULL; 
    544         if (begins) { 
    545                 ends = CFStringCreateArrayWithFindResults(NULL,cfsub,close,all,0); 
    546                 if (ends && CFArrayGetCount(begins) == CFArrayGetCount(ends)) { 
    547                         tagcount = CFArrayGetCount(begins); 
    548                         ranges = (CFRange*)malloc(sizeof(CFRange[tagcount])); 
    549                         for (i = 0; i < tagcount; i++) { 
    550                                 CFRange *btag, *etag; 
    551                                 btag = (CFRange*)CFArrayGetValueAtIndex(begins,i); 
    552                                 etag = (CFRange*)CFArrayGetValueAtIndex(ends,i); 
    553                                 if (etag->location < btag->location) break; // something's messed up 
    554                                 ranges[i] = (CFRange){btag->location, etag->location}; 
    555                                 ranges[i].length -= ranges[i].location;  
    556                                 ranges[i].length -= bs; 
    557                                 ranges[i].location -= tagoffset;  
    558                                 rcount_++; 
    559                                 tagoffset += bs + cs; // tracks sizes of tags we've encountered so far, so the ranges will be valid after we strip them 
    560                         } 
    561                         CFRelease(ends); 
    562                 } 
    563                 CFRelease(begins);  
    564         } 
    565         *rcount = rcount_; 
    566         return ranges; 
    567 } 
    568  
    569 static size_t ParseSrtStyles(TextSubGlobals glob, CFMutableStringRef cfsub, UniChar *uc, size_t sublen) 
    570 { 
    571         int i; 
    572         size_t italiccount=0, boldcount=0; 
    573         CFRange *italics = NULL, *bolds = NULL; CFRange all = (CFRange){0,sublen}; 
    574         CFMutableStringRef cfsub_nob = CFStringCreateMutableCopy(NULL,0,cfsub); 
    575          
    576         /*  Because I try to predict what the ranges will be after stripping tags, makestyleranges won't work if other 
    577                 to-be-stripped tags are in its string, so we have to remove them... */ 
    578         CFStringFindAndReplace(cfsub_nob, CFSTR("<b>"),CFSTR(""),all,0); 
    579         CFStringFindAndReplace(cfsub_nob, CFSTR("</b>"),CFSTR(""),CFRangeMake(0,CFStringGetLength(cfsub_nob)),0); 
    580         italics = MakeStyleRanges(cfsub_nob, CFSTR("<i>"), CFSTR("</i>"), &italiccount, CFStringGetLength(cfsub_nob)); 
    581  
    582         if (italics) { 
    583                 CFStringFindAndReplace(cfsub, CFSTR("<i>"),CFSTR(""),all,0); 
    584                 all = (CFRange){0,CFStringGetLength(cfsub)}; 
    585                 CFStringFindAndReplace(cfsub, CFSTR("</i>"),CFSTR(""),all,0); 
    586                 sublen = CFStringGetLength(cfsub); 
    587                 all = (CFRange){0,sublen}; 
    588         } 
    589         bolds   = MakeStyleRanges(cfsub, CFSTR("<b>"), CFSTR("</b>"), &boldcount, sublen); 
    590  
    591         if (bolds) { 
    592                 CFStringFindAndReplace(cfsub, CFSTR("<b>"),CFSTR(""),all,0); 
    593                 all = (CFRange){0,CFStringGetLength(cfsub)}; 
    594                 CFStringFindAndReplace(cfsub, CFSTR("</b>"),CFSTR(""),all,0); 
    595                 sublen = CFStringGetLength(cfsub); 
    596                 all = (CFRange){0,sublen}; 
    597         } 
    598          
    599         CFStringGetCharacters(cfsub, all, uc); 
    600         ATSUSetTextPointerLocation(glob->textLayout,uc,kATSUFromTextBeginning,kATSUToTextEnd,sublen); 
    601         ATSUSetTransientFontMatching(glob->textLayout,TRUE); 
    602  
    603         ATSUSetRunStyle(glob->textLayout,glob->textStyle,kATSUFromTextBeginning,kATSUToTextEnd); 
    604         if (italics) { 
    605                 for (i = 0; i < italiccount; i++) ATSUSetRunStyle(glob->textLayout,glob->italicStyle,italics[i].location,italics[i].length); 
    606         } 
    607         if (bolds) { 
    608                 for (i = 0; i < boldcount; i++) ATSUSetRunStyle(glob->textLayout,glob->boldStyle,bolds[i].location,bolds[i].length); 
    609         } 
    610         if (italics && bolds) {  
    611                 // <i><b></b></i> 
    612                 for (i = 0; i < italiccount; i++) { 
    613                         CFRange ir = italics[i]; int j; 
    614                         for (j = 0; j < boldcount; j++) { 
    615                                 CFRange br = bolds[j]; 
    616                                 if (br.location > ir.location && br.location < (ir.location + ir.length)) { 
    617                                         ATSUSetRunStyle(glob->textLayout,glob->biStyle,br.location,min(br.length, ir.length - (br.location - ir.location))); 
    618                                 } 
    619                         } 
    620                 } 
    621                  
    622                 // <b><i></i></b> 
    623                 for (i = 0; i < boldcount; i++) { 
    624                         CFRange br = bolds[i]; int j; 
    625                         for (j = 0; j < italiccount; j++) { 
    626                                 CFRange ir = italics[j]; 
    627                                 if (ir.location > br.location && ir.location < (br.location + br.length)) { 
    628                                         ATSUSetRunStyle(glob->textLayout,glob->biStyle,ir.location,min(ir.length, br.length - (ir.location - br.location))); 
    629                                 } 
    630                         } 
    631                 }                
    632         } 
    633         if (italics) free(italics); 
    634         if (bolds) free(bolds); 
    635         CFRelease(cfsub_nob); 
    636         return sublen; 
    637 } 
  • trunk/TextSubCodec.r

    r313 r314  
    5959// These flags specify information about the capabilities of the component 
    6060// Works with 1-bit, 8-bit, 16-bit and 32-bit Pixel Maps 
    61 #define kTextSubDecoFlags ( codecInfoDoes32 | codecInfoDoes16 | codecInfoDoes8 | codecInfoDoes1 | codecInfoDoesSpool
     61#define kTextSubDecoFlags ( codecInfoDoes32 | codecInfoDoes16 | codecInfoDoes8 | codecInfoDoes1 | codecInfoDoesSpool | cmpThreadSafe
    6262 
    6363// These flags specify the possible format of compressed data produced by the component 
    6464// and the format of compressed files that the component can handle during decompression 
    6565// The component can decompress from files at 1-bit, 8-bit, 16-bit, 24-bit and 32-bit depths 
    66 #define kTextSubFormatFlags     ( codecInfoDepth32 | codecInfoDepth24 | codecInfoDepth16 | codecInfoDepth8 | codecInfoDepth1
     66#define kTextSubFormatFlags     ( codecInfoDepth32 | codecInfoDepth24 | codecInfoDepth16 | codecInfoDepth8 | codecInfoDepth1 | cmpThreadSafe
    6767 
    6868// Component Description