source: trunk/SSATagParsing.m.rl @ 460

Revision 460, 17.6 KB checked in by astrange, 8 years ago (diff)

SSA: \r shouldn't reset positioning

Line 
1/*
2 *  SSARenderCodec.m
3 *  Copyright (c) 2007 Perian Project
4 *
5 *  This program is free software; you can redistribute it and/or
6 *  modify it under the terms of the GNU Lesser General Public
7 *  License as published by the Free Software Foundation;
8 *  version 2.1 of the License.
9 *
10 *  This program is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 *  Lesser General Public License for more details.
14 *
15 *  You should have received a copy of the GNU Lesser General Public
16 *  License along with this program; if not, write to the Free Software
17 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18 *
19 */
20
21#import "SSATagParsing.h"
22#import "Categories.h"
23
24@implementation SSAStyleSpan
25-(void)dealloc
26{
27        ATSUDisposeStyle(astyle);
28        [super dealloc];
29}
30@end
31
32@implementation SSARenderEntity
33-(void)dealloc
34{
35        int i;
36        for (i=0; i < style_count; i++) [styles[i] release];
37        if (disposelayout) ATSUDisposeTextLayout(layout);
38        free(text);
39        free(styles);
40        [nstext release];
41        [super dealloc];
42}
43
44-(void)increasestyles
45{
46        style_count++;
47        styles = realloc(styles, sizeof(SSAStyleSpan*[style_count]));
48}
49@end
50
51%% machine SSAtag;
52%% write data;
53
54void SetATSUStyleFlag(ATSUStyle style, ATSUAttributeTag t, Boolean v)
55{
56        ATSUAttributeTag tags[] = {t};
57        ByteCount                sizes[] = {sizeof(v)};
58        ATSUAttributeValuePtr vals[] = {&v};
59       
60        ATSUSetAttributes(style,1,tags,sizes,vals);
61}
62
63void SetATSUStyleOther(ATSUStyle style, ATSUAttributeTag t, ByteCount s, const ATSUAttributeValuePtr v)
64{
65        ATSUAttributeTag tags[] = {t};
66        ByteCount                sizes[] = {s};
67        ATSUAttributeValuePtr vals[] = {v};
68       
69        ATSUSetAttributes(style,1,tags,sizes,vals);
70}
71
72void SetATSULayoutOther(ATSUTextLayout l, ATSUAttributeTag t, ByteCount s, const ATSUAttributeValuePtr v)
73{
74        ATSUAttributeTag tags[] = {t};
75        ByteCount                sizes[] = {s};
76        ATSUAttributeValuePtr vals[] = {v};
77       
78        ATSUSetLayoutControls(l,1,tags,sizes,vals);
79}
80
81static ATSURGBAlphaColor ParseColorTag(unsigned long c, float a)
82{
83        unsigned char r,g,b;
84        r = c & 0xff;
85        g = (c >> 8) & 0xff;
86        b = (c >> 16) & 0xff;
87       
88        return (ATSURGBAlphaColor){r/255.,g/255.,b/255.,a};
89}
90
91//not worth it
92/*
93static void PruneIdenticalStyleSpans(SSARenderEntity *re)
94{
95        SSAStyleSpan *styles_new[re->style_count];
96       
97        if (re->multipart_drawing || re->style_count <= 1) return;
98
99        size_t style_count_new = 1, remaining = re->style_count-1;
100        int i=1;
101       
102       
103        styles_new[0] = re->styles[0];
104       
105        while (remaining) {
106                ATSUStyleComparison asc;
107                ATSUCompareStyles(styles_new[style_count_new-1]->astyle,re->styles[i]->astyle,&asc);
108               
109                if (asc == kATSUStyleEquals) {
110            styles_new[style_count_new-1]->range.length += re->styles[i]->range.length;
111                        [re->styles[i] release];
112            re->styles[i] = nil;
113                } else {
114                        styles_new[style_count_new++] = re->styles[i];
115                }
116               
117                i++;
118                remaining--;
119        }
120       
121        if (style_count_new != re->style_count) {
122                re->styles = realloc(re->styles, sizeof(SSAStyleSpan*) * style_count_new);
123                memcpy(re->styles, styles_new, sizeof(SSAStyleSpan*) * style_count_new);
124               
125                re->style_count = style_count_new;
126        }
127}
128*/
129
130static void UpdateAlignment(int inum, int cur_posx, int *valign, int *halign, ATSUTextLayout cur_layout)
131{
132        int cur_halign, cur_valign;
133       
134        switch (inum)
135        {case 1: case 4: case 7: cur_halign = S_LeftAlign; break;
136        case 2: case 5: case 8: default: cur_halign = S_CenterAlign; break;
137        case 3: case 6: case 9: cur_halign = S_RightAlign;}
138       
139        switch (inum)
140        {case 1: case 2: case 3: default: cur_valign = S_BottomAlign; break;
141        case 4: case 5: case 6: cur_valign = S_MiddleAlign; break;
142        case 7: case 8: case 9: cur_valign = S_TopAlign;}
143       
144        *halign = cur_halign;
145        *valign = cur_valign;
146        Fract alignment;
147       
148        if (cur_posx != -1) {
149                switch(cur_halign) {
150                        case S_LeftAlign:
151                                alignment = FloatToFract(0.);
152                                break;
153                        case S_CenterAlign: default:
154                                alignment = kATSUCenterAlignment; 
155                                break;
156                        case S_RightAlign:
157                                alignment = FloatToFract(1.);
158                }
159                SetATSULayoutOther(cur_layout, kATSULineFlushFactorTag, sizeof(Fract), &alignment);
160        }
161}
162
163NSArray *ParseSubPacket(NSString *str, SSADocument *ssa, Boolean plaintext)
164{
165        NSArray *linea;
166        int i=0, j, pcount = 1; unsigned len;
167        NSMutableArray *rentities = [NSMutableArray array];
168       
169        if (plaintext) {
170                linea = [NSArray arrayWithObject:str];
171        } else {
172                linea =  [str componentsSeparatedByString:@"\n"];
173                pcount = [linea count];
174        }
175
176        for (; i < pcount; i ++) {
177                SSARenderEntity *re = [[[SSARenderEntity alloc] init] autorelease];
178                BOOL ldirty = NO;
179               
180                if (plaintext) {
181                        re->style = ssa->defaultstyle;
182                        re->layout = re->style->layout;
183                        re->layer = 0;
184                        re->marginl = re->style->marginl;
185                        re->marginr = re->style->marginl;
186                        re->marginv = re->style->marginl;
187                        re->usablewidth = re->style->usablewidth;
188                        re->halign = 1;
189                        re->valign = 0;
190                        re->nstext = [linea objectAtIndex:i];
191                        re->styles = NULL;
192                        re->disposelayout = NO;
193                } else {
194                        NSArray *ar = [[linea objectAtIndex:(ssa->collisiontype == NormalCollisions) ? i : (pcount - i - 1)]
195                                                   componentsSeparatedByString:@"," count:9];
196
197                        if ([ar count] < 9) continue;
198                       
199                        re->layer = [[ar objectAtIndex:1] intValue];
200                        NSString *sn = [ar objectAtIndex:2];
201                       
202                        re->style = ssa->defaultstyle;
203                       
204                        for (j=0; j < ssa->stylecount; j++) {
205                                if ([sn isEqualToString:ssa->styles[j].name])  {
206                                        re->style = &ssa->styles[j];
207                                        break;
208                                }
209                        }
210
211                        re->marginl = [[ar objectAtIndex:5] intValue];
212                        re->marginr = [[ar objectAtIndex:6] intValue];
213                        re->marginv = [[ar objectAtIndex:7] intValue];
214                       
215                        if (re->marginl == 0) re->marginl = re->style->marginl; else ldirty = TRUE;
216                        if (re->marginr == 0) re->marginr = re->style->marginr; else ldirty = TRUE;
217                        if (re->marginv == 0) re->marginv = re->style->marginv; else ldirty = TRUE;
218                       
219                        if (ldirty) {
220                                ATSUTextMeasurement width;
221                                ATSUAttributeTag tag[] = {kATSULineWidthTag};
222                                ByteCount                size[] = {sizeof(ATSUTextMeasurement)};
223                                ATSUAttributeValuePtr val[] = {&width};
224                               
225                                re->usablewidth = ssa->resX - re->marginl - re->marginr;
226                                ATSUCreateAndCopyTextLayout(re->style->layout,&re->layout);
227                                width = IntToFixed(re->usablewidth);
228                               
229                                ATSUSetLayoutControls(re->layout,1,tag,size,val);
230                                re->disposelayout = YES;
231                        } else {
232                                re->usablewidth = re->style->usablewidth;
233                                re->layout = re->style->layout;
234                                re->disposelayout = NO;
235                        }
236                       
237                        re->nstext = [ar objectAtIndex:8];
238                }
239                len = [re->nstext length];
240                re->text = malloc(sizeof(unichar[len]));
241               
242                [re->nstext getCharacters:re->text];
243                re->style_count = 0;
244                re->posx = re->posy = -1;
245                re->halign = re->style->halign;
246                re->valign = re->style->valign;
247                re->multipart_drawing=NO;
248                re->is_shape=NO;
249               
250#define end_re \
251                cur_range = (NSRange){strbegin - pb, p - strbegin};\
252                cur_range.location -= outputoffset;\
253                cur_range.length -= lengthreduce;\
254                if (cur_range.length) {[re increasestyles];\
255                re->styles[re->style_count-1] = [[SSAStyleSpan alloc] init];\
256                re->styles[re->style_count-1]->outline = cur_outline;\
257                re->styles[re->style_count-1]->shadow = cur_shadow;\
258                re->styles[re->style_count-1]->angle = cur_frz;\
259                re->styles[re->style_count-1]->astyle = cur_style;\
260                re->styles[re->style_count-1]->range = cur_range;\
261                re->styles[re->style_count-1]->outlineblur = cur_be;\
262                re->styles[re->style_count-1]->color = cur_color;}\
263                parsetmp = [NSString stringWithCharacters:skipbegin length:p-skipbegin];\
264                [output appendString:parsetmp]; \
265                re->nstext = dtmp = output;\
266                re->text = malloc(sizeof(unichar[[re->nstext length]]));\
267                [re->nstext getCharacters:re->text];\
268                [re->nstext retain];
269               
270                {
271                        NSRange cur_range = {0,0};
272                        ATSUStyle cur_style;
273                        ATSUTextLayout cur_layout;
274                        NSMutableString *output = [NSMutableString string], *dtmp;
275                        unichar *p = re->text, *pe = &re->text[len], *numbegin = p, *strbegin = p, *skipbegin = p, *intbegin = p, *pb = p, *posbegin=p, *strparambegin=p;
276                        float num, cur_outline = re->style->outline, cur_shadow = re->style->shadow, cur_scalex = re->style->scalex, cur_scaley = re->style->scaley, cur_frz=re->style->angle;
277                        NSString *parsetmp;
278                        int cs, cur_valign=re->valign, cur_halign=re->halign, cur_posx=-1, cur_posy=-1;
279                        ssacolors cur_color = re->style->color;
280                        CGAffineTransform matrix;
281                       
282                        unsigned long inum=0;
283                        unsigned outputoffset=0, lengthreduce=0;
284                        BOOL flag=0, newLayout=FALSE, cur_be = FALSE;
285                        Fixed fixv;
286                       
287                        ATSUCreateAndCopyStyle(re->style->atsustyle,&cur_style);
288                       
289                        %%{
290                                alphtype unsigned short;
291                               
292                                action bold {SetATSUStyleFlag(cur_style, kATSUQDBoldfaceTag, flag);}
293                               
294                                action italic {SetATSUStyleFlag(cur_style, kATSUQDItalicTag, flag);}
295                               
296                                action uline {SetATSUStyleFlag(cur_style, kATSUQDUnderlineTag, flag);}
297                               
298                                action strike {SetATSUStyleFlag(cur_style, kATSUStyleStrikeThroughTag, flag);}
299                               
300                                action bordersize {cur_outline = num; re->multipart_drawing = YES;}
301                               
302                                action shadowsize {cur_shadow = num; re->multipart_drawing = YES;}
303                               
304                                action bluredge {cur_be = flag;}
305                               
306                                action frot {cur_frz = num; re->multipart_drawing = YES;}
307                               
308                                action fsize {
309                                        num *= (72./96.); // scale from Windows 96dpi
310                                        fixv = FloatToFixed(num);
311                                        SetATSUStyleOther(cur_style, kATSUSizeTag, sizeof(fixv), &fixv);
312                                }
313                               
314                                action ftrack {
315                                        fixv = FloatToFixed(num);
316                                        SetATSUStyleOther(cur_style, kATSUTrackingTag, sizeof(fixv), &fixv);
317                                }
318                               
319                                action fscalex {
320                                        cur_scalex = num;
321                                        matrix = CGAffineTransformMakeScale(cur_scalex/100.,cur_scaley/100.);           
322                                        SetATSUStyleOther(cur_style, kATSUFontMatrixTag, sizeof(matrix), &matrix);
323                                }
324                               
325                                action fscaley {
326                                        cur_scaley = num;
327                                        matrix = CGAffineTransformMakeScale(cur_scalex/100.,cur_scaley/100.);   
328                                        SetATSUStyleOther(cur_style, kATSUFontMatrixTag, sizeof(matrix), &matrix);
329                                }
330                               
331                                action strp_begin {
332                                        strparambegin = p;
333                                }
334                               
335                                action fontname {
336                                        ATSUFontID      font;
337                                        font = FMGetFontFromATSFontRef(ATSFontFindFromName((CFStringRef)[NSString stringWithCharacters:strparambegin length:p-strparambegin],kATSOptionFlagsDefault));
338                                        SetATSUStyleOther(cur_style, kATSUFontTag, sizeof(ATSUFontID), &font);
339                                }
340                               
341                                action alignment {
342                                        if (!newLayout) {
343                                                newLayout = TRUE;
344                                                ATSUCreateAndCopyTextLayout(re->layout,&cur_layout);
345                                        }
346                                       
347                                        UpdateAlignment(inum, cur_posx, &cur_valign, &cur_halign, cur_layout);
348                                }
349
350                                action ssa_alignment {
351                                        if (!newLayout) {
352                                                newLayout = TRUE;
353                                                ATSUCreateAndCopyTextLayout(re->layout,&cur_layout);
354                                        }
355                                       
356                                        UpdateAlignment(SSA2ASSAlignment(inum), cur_posx, &cur_valign, &cur_halign, cur_layout);
357                                }
358                               
359                                action pos_begin {
360                                        posbegin=p;
361                                }
362                               
363                                action pos_end {
364                                        if (!newLayout) {
365                                                newLayout = TRUE;
366                                                ATSUCreateAndCopyTextLayout(re->layout,&cur_layout);
367                                        }
368                                        NSArray *coo = [[NSString stringWithCharacters:posbegin length:p-posbegin] componentsSeparatedByString:@","];
369                                        cur_posx = [[coo objectAtIndex:0] intValue];
370                                        cur_posy = [[coo objectAtIndex:1] intValue];
371                                }
372                               
373                                action primarycolor {
374                                        cur_color.primary = ParseColorTag(inum,cur_color.primary.alpha);
375                                        re->multipart_drawing = YES;
376                                }
377                               
378                                action secondarycolor {
379                                        cur_color.secondary = ParseColorTag(inum,cur_color.secondary.alpha);
380                                        re->multipart_drawing = YES;
381                                }
382                               
383                                action outlinecolor {
384                                        cur_color.outline = ParseColorTag(inum,cur_color.outline.alpha);
385                                        re->multipart_drawing = YES;
386                                }
387                               
388                                action shadowcolor {
389                                        cur_color.shadow = ParseColorTag(inum,cur_color.shadow.alpha);
390                                        re->multipart_drawing = YES;
391                                }
392                               
393                                action primaryalpha {
394                                        cur_color.primary.alpha = (255 - inum) / 255.f;
395                                        re->multipart_drawing = YES;
396                                }
397                               
398                                action secondaryalpha {
399                                        cur_color.secondary.alpha = (255 - inum) / 255.f;
400                                        re->multipart_drawing = YES;
401                                }
402                               
403                                action outlinealpha {
404                                        cur_color.outline.alpha = (255 - inum) / 255.f;
405                                        re->multipart_drawing = YES;
406                                }
407                               
408                                action shadowalpha {
409                                        cur_color.shadow.alpha = (255 - inum) / 255.f;
410                                        re->multipart_drawing = YES;
411                                }
412                               
413                                action nl_handler {
414                                        NSString *append = @"\n";
415                                        parsetmp = [NSString stringWithCharacters:skipbegin length:(p-2)-skipbegin];
416                                        [output appendString:parsetmp];
417                                       
418                                        skipbegin = p;
419
420                                        if (*(p - 1) == 'h') append = @" ";
421                   
422                                        [output appendString:append];
423                                       
424                                        lengthreduce++;
425                                }
426                               
427                                action enter_tag {
428                                        unsigned taglen = p - skipbegin;
429                                        parsetmp = [NSString stringWithCharacters:skipbegin length:taglen];
430                                        [output appendString:parsetmp];
431                                        skipbegin = p;
432                                       
433                                        cur_range = (NSRange){strbegin - pb, p - strbegin};
434                                        cur_range.location -= outputoffset;
435                                        cur_range.length -= lengthreduce;
436                                       
437                                        outputoffset += lengthreduce;
438                                        lengthreduce = 0;
439                   
440                    if (cur_range.length) {
441                        [re increasestyles];
442                        re->styles[re->style_count-1] = [[SSAStyleSpan alloc] init];
443                        re->styles[re->style_count-1]->outline = cur_outline;
444                        re->styles[re->style_count-1]->shadow = cur_shadow;
445                        re->styles[re->style_count-1]->angle = cur_frz;
446                        re->styles[re->style_count-1]->astyle = cur_style;
447                        re->styles[re->style_count-1]->range = cur_range;
448                        re->styles[re->style_count-1]->outlineblur = cur_be;
449                        re->styles[re->style_count-1]->color = cur_color;
450                        ATSUCreateAndCopyStyle(cur_style,&cur_style);
451                    }
452                                }
453                               
454                                action exit_tag {
455                                        // XXX exit_tag ideally should run one char later, so we just pretend it does
456                                        p++;
457                                        outputoffset += p - skipbegin;
458                                        skipbegin = p;
459                                        strbegin = p;
460
461                                        if (newLayout) {
462                                                newLayout = FALSE;
463                                                end_re;
464                       
465                                                if ([re->nstext length] != 0) [rentities addObject:re];
466                                               
467                                                SSARenderEntity *nre = [[[SSARenderEntity alloc] init] autorelease];
468                                                nre->layer = re->layer;
469                                                nre->style = re->style;
470                                                nre->marginl = re->marginl; nre->marginr = re->marginr; nre->marginv = re->marginv; nre->usablewidth = re->usablewidth;
471                                                nre->posx = cur_posx; nre->posy = cur_posy; nre->halign = cur_halign; nre->valign = cur_valign;
472                                                nre->nstext = nil;
473                                                nre->text = nil;
474                                                nre->layout = cur_layout;
475                                                nre->styles = malloc(0);
476                                                nre->style_count = 0;
477                                                nre->disposelayout = YES;
478                                                nre->multipart_drawing = NO;
479                                                nre->is_shape = re->is_shape;
480                                                re = nre;
481                                        }
482                                        p--;
483                                }
484                               
485                                action color_end {
486                                        NSString *hexn = [NSString stringWithCharacters:intbegin length:p-intbegin];
487                                        inum = strtoul([hexn UTF8String], NULL, 16);
488                                }
489                               
490                                action styleset {
491                                        re->multipart_drawing = YES;
492                                        ssastyleline *the_style = re->style;
493                                        NSString *searchsn = [NSString stringWithCharacters:strparambegin length:p-strparambegin];
494                                       
495                                        if ([searchsn length] > 0) {
496                                                for (j=0; j < ssa->stylecount; j++) {
497                                                        if ([searchsn isEqualToString:ssa->styles[j].name])  {
498                                                                the_style = &ssa->styles[j];
499                                                                break;
500                                                        }
501                                                }
502                                        }
503                                       
504                                        ATSUCopyAttributes(the_style->atsustyle,cur_style);
505                                        cur_color = the_style->color;
506                                        cur_outline = the_style->outline;
507                                        cur_shadow = the_style->shadow;
508                                        cur_frz = the_style->angle;
509                                        cur_scalex = cur_scaley = 1;
510                                }
511                               
512                                action skip_t_tag {
513                                        while (p != pe && *p != ')' && *p != '}') p++;
514                                        p++;
515                                }
516                               
517                                action draw_mode {
518                                        re->is_shape = inum != 0;
519                                }
520                               
521                                flag = ([01] % {unichar fl = *(p-1); if (fl == '0' || fl == '1') flag = fl - '0';})? > {flag = 0;};
522                                num_ = "-"? digit+ ('.' digit*)?;
523                                num = num_ > {numbegin = p;} % {num = [[NSString stringWithCharacters:numbegin length:p-numbegin] doubleValue];};
524                               
525                                intnum = "-"? (digit+) > {intbegin = p;} % {inum = [[NSString stringWithCharacters:intbegin length:p-intbegin] intValue];};
526                               
527                                color = ("H"|"&"){,2} (xdigit+) > {intbegin = p;} % color_end "&";
528
529                                cmd_specific = (("pos(" [^)]+ > pos_begin ")" % pos_end)
530                                                                |"bord" num %bordersize
531                                                                |"b" flag %bold
532                                                                |"be" flag %bluredge
533                                                                |"i" flag %italic
534                                                                |"u" flag %uline
535                                                                |"s" flag %strike
536                                                                |"fs" num %fsize
537                                                                |"fsp" num %ftrack
538                                                                |"fscx" num %fscalex
539                                                                |"fscy" num %fscaley
540                                                                |("fr" "z"? num %frot)
541                                                                |("fn" [^\\}]* > strp_begin %fontname)
542                                                                |"shad" num %shadowsize
543                                                                |"a" intnum %ssa_alignment
544                                                                |"an" intnum %alignment
545                                                                |"c" color %primarycolor
546                                                                |"1c" color %primarycolor
547                                                                |"2c" color %secondarycolor
548                                                                |"3c" color %outlinecolor
549                                                                |"4c" color %shadowcolor
550                                                                |"1a" color %primaryalpha
551                                                                |"2a" color %secondaryalpha
552                                                                |"3a" color %outlinealpha
553                                                                |"4a" color %shadowalpha
554                                                                |("r" [^\\}]* > strp_begin %styleset)
555                                                                |("fe"|"k"|"kf"|"K"|"ko"|"q"|"fr"|"fad"|"move"|"clip"|"o"|"frx"|"fry") [^\\}]*
556                                                                |"p" num %draw_mode
557                                                                #|"t" [^)}]* # enabling this crashes ragel
558                                                                |"t(" % skip_t_tag
559                                                                );
560                               
561                                cmd = ("\\" :> cmd_specific)+;
562                               
563                                plaintext = [^}]*;
564
565                                tag = "{" (cmd | plaintext) % exit_tag "}";
566                               
567                                nl = "\\" [Nnh];
568                               
569                                special = nl % nl_handler | (tag > enter_tag);
570                                                               
571                                text = any*;
572                                main := (text special?)*;
573                        }%%
574                               
575                        %%write init;
576                        %%write exec;
577                        %%write eof;
578                       
579                        if (pb[len-1] == '}') skipbegin = p; // make up for how exit_tag isn't called if the } is the last char in the line
580
581                        end_re;
582                        if (!cur_range.length) ATSUDisposeStyle(cur_style);
583            //PruneIdenticalStyleSpans(re);
584
585                        free(pb);
586                        if ([re->nstext length] != 0) [rentities addObject:re];
587                }
588               
589        }
590        return rentities;
591}
Note: See TracBrowser for help on using the repository browser.