/* Format.c -- handles JACOsub style formatting for a line */ #include "Format.h" #include "Directives.h" #include "RunScript.h" #include #include #include struct FontStuff { SInt16 id; SInt16 size; SInt16 ascent; SInt16 descent; SInt16 leading; SInt16 widMax; SInt16 lineHeight; SInt16 italWidth; SInt16 method; }; typedef struct FontStuff FontStuff; FontStuff fonts[10]; // info on the fonts (0..9) RGBColor palet[10][16]; Rect lastBox; // bounding box of last subtitle for VA/VU //enum { // maxHeight = 640, // maxWidth = 480 //}; void DrawSubLine( SubLinePtr line, Boolean drawIt ) { Directive dir; // working directive for current line SInt16 x,y; SInt32 i,j,n,w; SInt32 nLines; char* lastWordEnd; SInt16 lastWordX; char c,*p; Rect r; Boolean inWord; SInt16 textHeight,lineHeight,lineAscent,widest; char* breaks[100]; SInt16 ascent[100]; SInt16 height[100]; SInt16 widths[100]; SInt16 margin,pass,passStartLine; char *passStart; CGrafPtr aScrnWindow = (CGrafPtr) scrnWindow; UInt32 ticks; ticks = TickCount(); dir = line -> dir; SetPort(scrnWindow); TextFace(0); r.top = dir.vpTop; r.left = dir.hlMargin; r.right = dir.hrMargin; r.bottom = dir.vBottom; TextFont(fonts[dir.fontNum].id); TextSize(fonts[dir.fontNum].size); TextFace(dir.txFace); p = line -> text; breaks[0] = p; nLines = 1; textHeight = 0; lineHeight = fonts[dir.fontNum].lineHeight; lineAscent = fonts[dir.fontNum].ascent; x = dir.hlMargin; lastWordX = x; lastWordEnd = nil; widest = 0; inWord = false; pass = 1; passStart = p; passStartLine = nLines; margin = dir.hrMargin; while ((c=*p++) != 0) { w = 0; if (c=='~') { w = CharWidth(' '); inWord = true; } else if (c=='`' && *p=='`') { p++; w = CharWidth('"'); } else if (c=='\\' && *p!=0) { c=*p++; switch(c) { case 'D': // insert date -- these should be handled during compile case 'T': // insert time break; case 'N': // text face normal dir.txFace = 0; TextFace(dir.txFace); break; case 'I': // text face italic on dir.txFace |= italic; TextFace(dir.txFace); break; case 'i': // text face italic off dir.txFace &= ~italic; TextFace(dir.txFace); break; case 'B': // text face bold on dir.txFace |= bold; TextFace(dir.txFace); break; case 'b': // text face bold off dir.txFace &= ~bold; TextFace(dir.txFace); break; case 'U': // text face underline on dir.txFace |= underline; TextFace(dir.txFace); break; case 'u': // text face underline off dir.txFace &= ~underline; TextFace(dir.txFace); break; case 'C': // text fore color if (isdigit(*p)) { dir.fgColor = *p++ - '0'; c = ' '; // signal a word break } break; case 'F': // text font number if (*p!=0) *p++; break; case 'n': // newline if (inWord) { lastWordX = x; lastWordEnd = p; } while (*p==' ') p++; // eat leading blanks of next line if (dir.txFace & italic) // trailing italics adjust { lastWordX = lastWordX + fonts[dir.fontNum].italWidth; } breaks[nLines] = p; ascent[nLines] = lineAscent; height[nLines] = lineHeight; widths[nLines] = lastWordX - dir.hlMargin; if (pass==2 || dir.wrapType!=wrapSmart) { if (widths[nLines]>widest) widest = widths[nLines]; textHeight = textHeight + lineHeight + 1; } nLines++; x = dir.hlMargin; lastWordX = x; lastWordEnd = nil; inWord = false; if (pass==1 && dir.wrapType==wrapSmart) { margin = 0; for (i=passStartLine; i= dir.hrMargin && dir.wrapType!=wrapNone) // test for right margin || (x-dir.hlMargin+w > margin && dir.wrapType==wrapSmart && !inWord )) { if (lastWordEnd) p = lastWordEnd; // back up to last end of word while (*p==' ') p++; // skip white space if (*p) // ignore last white-only line when auto-wrapping { while (*p==' ') p++; // eat leading blanks of next line if (dir.txFace & italic) // trailing italics adjust { lastWordX = lastWordX + fonts[dir.fontNum].italWidth; } breaks[nLines] = p; ascent[nLines] = lineAscent; height[nLines] = lineHeight; widths[nLines] = lastWordX - dir.hlMargin; if (pass==2 || dir.wrapType!=wrapSmart) { if (widths[nLines]>widest) widest = widths[nLines]; textHeight = textHeight + lineHeight + 1; } nLines++; x = dir.hlMargin; lastWordX = x; lastWordEnd = nil; inWord = false; } else x = x + w; } else x = x + w; if (*p==0) { if (inWord) // test for end of word { lastWordX = x; lastWordEnd = p; } if (dir.txFace & italic) // trailing italics adjust { lastWordX = lastWordX + fonts[dir.fontNum].italWidth; } breaks[nLines] = p; ascent[nLines] = lineAscent; height[nLines] = lineHeight; widths[nLines] = lastWordX - dir.hlMargin; if (pass==2 || dir.wrapType!=wrapSmart) { if (widths[nLines]>widest) widest = widths[nLines]; textHeight = textHeight + lineHeight + 1; } if (pass==1 && dir.wrapType==wrapSmart) { nLines++; x = dir.hlMargin; lastWordX = x; lastWordEnd = nil; inWord = false; margin = 0; for (i=passStartLine; i=1 && widths[nLines]==0) { nLines--; r.bottom = r.bottom - lineHeight - 1; } InsetRect(& r, -2, -2); // add in space for the shadows r.right = r.right + 3; line -> box = r; lastBox = r; // now that we know how big it is, we can start drawing it... if (drawIt) { Str255 s; // output buffer SInt16 wordX; dir = line -> dir; TextFont(fonts[dir.fontNum].id); TextSize(fonts[dir.fontNum].size); TextFace(dir.txFace); p = line -> text; y = r.top + 2; //FrameRect( & r ); for (n=1; n<=nLines; n++) { y = y + ascent[n]; s[0] = 0; switch(dir.justify) // this is the place to handle justification { case justFull: // full justify not supported case justLeft: x = r.left + 2; break; case justRight: x = r.right - widths[n] - 2; break; case justCenter: x = (r.left + r.right - widths[n]) / 2; break; } wordX = x; while (p=breaks[n]) && s[0] != 0) // faster but doesn't work with PS fonts { // ForeColor( blackColor ); // TextFace( outline + condense ); // MoveTo(wordX,y); // DrawString(s); // // ForeColor( yellowColor ); // TextFace( 0 ); // MoveTo(wordX,y); // DrawString(s); if (TickCount() > ticks + 5*60) { SysBeep(8); Debugger(); return; } // ForeColor( blackColor ); RGBForeColor( &palet[dir.paletNum][2] ); // should be black // TextFace( txFace ); // TextFace( qd.thePort->txFace ); switch (fonts[dir.fontNum].method) { case 0: // 8-point 2 pixels thick (for bigger thicker fonts) for (i=-2; i<=2; i=i+2) for (j=-2; j<=2; j=j+2) if (i!=0 || j!=0) { MoveTo(wordX+i,y+j); DrawString(s); } break; case 1: // 24-point 2 pixels thick (for smaller pointier fonts) for (i=-2; i<=2; i++) for (j=-2; j<=2; j++) if (i!=0 || j!=0) { MoveTo(wordX+i,y+j); DrawString(s); } break; case 2: // 12-point 2 pixels thick (for smaller thicker fonts) for (i=-2; i<=2; i++) for (j=-2; j<=2; j++) if (i^j & 1) { MoveTo(wordX+i,y+j); DrawString(s); } break; } // ForeColor( yellowColor ); RGBForeColor( &palet[dir.paletNum][dir.fgColor] ); // TextFace( txFace ); MoveTo(wordX,y); DrawString(s); s[0] = 0; } TextFace(dir.txFace); x = x + w; } y = y + height[n] - ascent[n]; } // FrameRect( & line -> box ); } } void FormatInit( void ) { SInt16 i; FontInfo fntInfo; // set up default font info SetPort(scrnWindow); TextFont(kFontIDGeneva); TextFont(kFontIDHelvetica); i = 0; // GetFNum("\pArial Black", & i); // GetFNum("\pArial", & i); if (i) TextFont(i); for (i=0; i<=9; i++) { switch(i) { case 0: TextSize(36); break; case 1: TextSize(24); break; case 3: TextSize(18); break; case 7: TextSize(48); break; case 9: TextSize(20); break; default: TextSize(24); } GetFontInfo(&fntInfo); fonts[i].id = scrnWindow->txFont; fonts[i].size = scrnWindow->txSize; fonts[i].ascent = fntInfo.ascent; fonts[i].descent = fntInfo.descent; fonts[i].leading = /*fntInfo.leading +*/ 0; fonts[i].widMax = fntInfo.widMax; fonts[i].lineHeight = fonts[i].ascent + fonts[i].descent + fonts[i].leading; fonts[i].method = 0; // if (fonts[i].size<24) fonts[i].method = 1; if (fonts[i].size<24) fonts[i].method = 2; // I have no formula for italic overhang width, but these will work for now. fonts[i].italWidth = fntInfo.ascent / 6; switch (fonts[i].size) { case 9: case 10: case 14: case 18: case 20: case 24: fonts[i].italWidth = fntInfo.ascent / 2; break; case 36: fonts[i].italWidth = fntInfo.ascent / 4; } } ResetFormatCompile( ); } void ResetFormatCompile( void ) { UInt16 i; RGBColor defpalet[16] = { // 0x9999, 0xAAAA, 0xBBBB, // 0 background (transparent when genlocked) 0xFFFF, 0xFFFF, 0xFFFF, // 0 background (transparent when genlocked) 0x0000, 0xCCCC, 0x6666, // 1 alternate font color (usually green) 0x0000, 0x0000, 0x0000, // 2 font outline/shadow color (should be dark) 0xFFFF, 0xFFFF, 0x0000, // 3 primary font face color (usually yellow) 0xDDDD, 0x0000, 0x0000, // 4 red - remaining settings are arbitrary 0xFFFF, 0x8888, 0x0000, // 5 orange 0xDDDD, 0x8888, 0xDDDD, // 6 light magenta / hot pink 0x0000, 0xDDDD, 0xEEEE, // 7 cyan 0xBBBB, 0x7777, 0x3333, // 8 brown 0xDDDD, 0xBBBB, 0x9999, // 9 light beige 0x5555, 0xAAAA, 0xEEEE, // 10 deep sky blue 0x3333, 0x3333, 0x3333, // 11 gray shades... 0x6666, 0x6666, 0x6666, // 12 0x8888, 0x8888, 0x8888, // 13 0xBBBB, 0xBBBB, 0xBBBB, // 14 0xDDDD, 0xDDDD, 0xDDDD // 15 }; for (i=0; i<=9; i++) memcpy(&palet[i],&defpalet,sizeof(defpalet)); } void FormatFinal( void ) { } /* this was the old way to draw text... x = line -> origin.h; y = line -> origin.v; n = GetPtrSize( line -> text ) - 1; // TextMode( srcOr ); TextFont(fonts[fontNum].id); TextSize(fonts[fontNum].size); TextFace(txFace); ForeColor( blackColor ); // MoveTo( x-2, y-2 ); // DrawText( line->text, 0, n); // MoveTo( x+2, y-2 ); // DrawText( line->text, 0, n); // MoveTo( x-2, y+2 ); // DrawText( line->text, 0, n); // MoveTo( x+2, y+2 ); // DrawText( line->text, 0, n); // TextFace( shadow + condense ); TextFace( outline + condense ); MoveTo( x, y ); DrawText( line->text, 0, n); TextFace( 0 ); ForeColor( yellowColor ); MoveTo( x, y ); DrawText( line->text, 0, n); */