2007-07-09 20:33:44 +02:00
/*
* Copyright ( C ) 2003 - 2006 Gabest
* http : //www.gabest.org
*
* This Program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 , or ( at your option )
* any later version .
*
* This Program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with GNU Make ; see the file COPYING . If not , write to
* the Free Software Foundation , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
* http : //www.gnu.org/copyleft/gpl.html
*
*/
# include "stdafx.h"
# include <math.h>
# include <time.h>
# include "RTS.h"
// WARNING: this isn't very thread safe, use only one RTS a time.
static HDC g_hDC ;
static int g_hDC_refcnt = 0 ;
static long revcolor ( long c )
{
return ( ( c & 0xff0000 ) > > 16 ) + ( c & 0xff00 ) + ( ( c & 0xff ) < < 16 ) ;
}
//////////////////////////////////////////////////////////////////////////////////////////////
// CMyFont
CMyFont : : CMyFont ( STSStyle & style )
{
LOGFONT lf ;
memset ( & lf , 0 , sizeof ( lf ) ) ;
lf < < = style ;
//lf.lfHeight = (LONG)(style.fontSize+0.5);
lf . lfOutPrecision = OUT_TT_PRECIS ;
lf . lfClipPrecision = CLIP_DEFAULT_PRECIS ;
lf . lfQuality = ANTIALIASED_QUALITY ;
lf . lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE ;
if ( ! CreateFontIndirect ( & lf ) )
{
_tcscpy ( lf . lfFaceName , _T ( " Arial " ) ) ;
CreateFontIndirect ( & lf ) ;
}
HFONT hOldFont = SelectFont ( g_hDC , * this ) ;
TEXTMETRIC tm ;
GetTextMetrics ( g_hDC , & tm ) ;
m_ascent = ( ( tm . tmAscent + 4 ) > > 3 ) ;
m_descent = ( ( tm . tmDescent + 4 ) > > 3 ) ;
SelectFont ( g_hDC , hOldFont ) ;
}
// CWord
CWord : : CWord ( STSStyle & style , CStringW str , int ktype , int kstart , int kend )
: m_style ( style ) , m_str ( str )
, m_width ( 0 ) , m_ascent ( 0 ) , m_descent ( 0 )
, m_ktype ( ktype ) , m_kstart ( kstart ) , m_kend ( kend )
, m_fDrawn ( false ) , m_p ( INT_MAX , INT_MAX )
, m_fLineBreak ( false ) , m_fWhiteSpaceChar ( false )
, m_pOpaqueBox ( NULL )
{
if ( str . IsEmpty ( ) )
{
m_fWhiteSpaceChar = m_fLineBreak = true ;
}
CMyFont font ( m_style ) ;
m_ascent = ( int ) ( m_style . fontScaleY / 100 * font . m_ascent ) ;
m_descent = ( int ) ( m_style . fontScaleY / 100 * font . m_descent ) ;
m_width = 0 ;
}
CWord : : ~ CWord ( )
{
if ( m_pOpaqueBox ) delete m_pOpaqueBox ;
}
bool CWord : : Append ( CWord * w )
{
if ( ! ( m_style = = w - > m_style )
| | m_fLineBreak | | w - > m_fLineBreak
| | w - > m_kstart ! = w - > m_kend | | m_ktype ! = w - > m_ktype ) return ( false ) ;
m_fWhiteSpaceChar = m_fWhiteSpaceChar & & w - > m_fWhiteSpaceChar ;
m_str + = w - > m_str ;
m_width + = w - > m_width ;
m_fDrawn = false ;
m_p = CPoint ( INT_MAX , INT_MAX ) ;
return ( true ) ;
}
void CWord : : Paint ( CPoint p , CPoint org )
{
if ( ! m_str ) return ;
if ( ! m_fDrawn )
{
if ( ! CreatePath ( ) ) return ;
Transform ( CPoint ( ( org . x - p . x ) * 8 , ( org . y - p . y ) * 8 ) ) ;
if ( ! ScanConvert ( ) ) return ;
if ( m_style . borderStyle = = 0 & & m_style . outlineWidth > 0 )
{
if ( ! CreateWidenedRegion ( ( int ) ( m_style . outlineWidth + 0.5 ) ) ) return ;
}
else if ( m_style . borderStyle = = 1 )
{
if ( ! CreateOpaqueBox ( ) ) return ;
}
m_fDrawn = true ;
if ( ! Rasterize ( p . x & 7 , p . y & 7 , m_style . fBlur ) ) return ;
}
else if ( ( m_p . x & 7 ) ! = ( p . x & 7 ) | | ( m_p . y & 7 ) ! = ( p . y & 7 ) )
{
Rasterize ( p . x & 7 , p . y & 7 , m_style . fBlur ) ;
}
m_p = p ;
if ( m_pOpaqueBox )
m_pOpaqueBox - > Paint ( p , org ) ;
}
void CWord : : Transform ( CPoint org )
{
double scalex = m_style . fontScaleX / 100 ;
double scaley = m_style . fontScaleY / 100 ;
double caz = cos ( ( 3.1415 / 180 ) * m_style . fontAngleZ ) ;
double saz = sin ( ( 3.1415 / 180 ) * m_style . fontAngleZ ) ;
double cax = cos ( ( 3.1415 / 180 ) * m_style . fontAngleX ) ;
double sax = sin ( ( 3.1415 / 180 ) * m_style . fontAngleX ) ;
double cay = cos ( ( 3.1415 / 180 ) * m_style . fontAngleY ) ;
double say = sin ( ( 3.1415 / 180 ) * m_style . fontAngleY ) ;
for ( int i = 0 ; i < mPathPoints ; i + + )
{
double x , y , z , xx , yy , zz ;
x = scalex * ( mpPathPoints [ i ] . x + m_style . fontShiftX * mpPathPoints [ i ] . y ) - org . x ;
y = scaley * ( mpPathPoints [ i ] . y + m_style . fontShiftY * mpPathPoints [ i ] . x ) - org . y ;
z = 0 ;
xx = x * caz + y * saz ;
yy = - ( x * saz - y * caz ) ;
zz = z ;
x = xx ;
y = yy * cax + zz * sax ;
z = yy * sax - zz * cax ;
xx = x * cay + z * say ;
yy = y ;
zz = x * say - z * cay ;
zz = max ( zz , - 19000 ) ;
x = ( xx * 20000 ) / ( zz + 20000 ) ;
y = ( yy * 20000 ) / ( zz + 20000 ) ;
mpPathPoints [ i ] . x = ( LONG ) ( x + org . x + 0.5 ) ;
mpPathPoints [ i ] . y = ( LONG ) ( y + org . y + 0.5 ) ;
}
}
bool CWord : : CreateOpaqueBox ( )
{
if ( m_pOpaqueBox ) return ( true ) ;
STSStyle style = m_style ;
style . borderStyle = 0 ;
style . outlineWidth = 0 ;
style . colors [ 0 ] = m_style . colors [ 2 ] ;
style . alpha [ 0 ] = m_style . alpha [ 2 ] ;
int w = ( int ) ( m_style . outlineWidth + 0.5 ) ;
CStringW str ;
str . Format ( L " m %d %d l %d %d %d %d %d %d " ,
- w , - w ,
m_width + w , - w ,
m_width + w , m_ascent + m_descent + w ,
- w , m_ascent + m_descent + w ) ;
m_pOpaqueBox = new CPolygon ( style , str , 0 , 0 , 0 , 1.0 / 8 , 1.0 / 8 , 0 ) ;
return ( ! ! m_pOpaqueBox ) ;
}
// CText
CText : : CText ( STSStyle & style , CStringW str , int ktype , int kstart , int kend )
: CWord ( style , str , ktype , kstart , kend )
{
if ( m_str = = L " " )
{
m_fWhiteSpaceChar = true ;
}
CMyFont font ( m_style ) ;
HFONT hOldFont = SelectFont ( g_hDC , font ) ;
if ( m_style . fontSpacing | | ( long ) GetVersion ( ) < 0 )
{
bool bFirstPath = true ;
for ( LPCWSTR s = m_str ; * s ; s + + )
{
CSize extent ;
if ( ! GetTextExtentPoint32W ( g_hDC , s , 1 , & extent ) ) { SelectFont ( g_hDC , hOldFont ) ; ASSERT ( 0 ) ; return ; }
m_width + = extent . cx + ( int ) m_style . fontSpacing ;
}
// m_width -= (int)m_style.fontSpacing; // TODO: subtract only at the end of the line
}
else
{
CSize extent ;
if ( ! GetTextExtentPoint32W ( g_hDC , m_str , wcslen ( str ) , & extent ) ) { SelectFont ( g_hDC , hOldFont ) ; ASSERT ( 0 ) ; return ; }
m_width + = extent . cx ;
}
m_width = ( int ) ( m_style . fontScaleX / 100 * m_width + 4 ) > > 3 ;
SelectFont ( g_hDC , hOldFont ) ;
}
CWord * CText : : Copy ( )
{
return ( new CText ( m_style , m_str , m_ktype , m_kstart , m_kend ) ) ;
}
bool CText : : Append ( CWord * w )
{
return ( dynamic_cast < CText * > ( w ) & & CWord : : Append ( w ) ) ;
}
bool CText : : CreatePath ( )
{
CMyFont font ( m_style ) ;
HFONT hOldFont = SelectFont ( g_hDC , font ) ;
int width = 0 ;
if ( m_style . fontSpacing | | ( long ) GetVersion ( ) < 0 )
{
bool bFirstPath = true ;
for ( LPCWSTR s = m_str ; * s ; s + + )
{
CSize extent ;
if ( ! GetTextExtentPoint32W ( g_hDC , s , 1 , & extent ) ) { SelectFont ( g_hDC , hOldFont ) ; ASSERT ( 0 ) ; return ( false ) ; }
PartialBeginPath ( g_hDC , bFirstPath ) ; bFirstPath = false ;
TextOutW ( g_hDC , 0 , 0 , s , 1 ) ;
PartialEndPath ( g_hDC , width , 0 ) ;
width + = extent . cx + ( int ) m_style . fontSpacing ;
}
}
else
{
CSize extent ;
if ( ! GetTextExtentPoint32W ( g_hDC , m_str , m_str . GetLength ( ) , & extent ) ) { SelectFont ( g_hDC , hOldFont ) ; ASSERT ( 0 ) ; return ( false ) ; }
BeginPath ( g_hDC ) ;
TextOutW ( g_hDC , 0 , 0 , m_str , m_str . GetLength ( ) ) ;
EndPath ( g_hDC ) ;
}
SelectFont ( g_hDC , hOldFont ) ;
return ( true ) ;
}
// CPolygon
CPolygon : : CPolygon ( STSStyle & style , CStringW str , int ktype , int kstart , int kend , double scalex , double scaley , int baseline )
: CWord ( style , str , ktype , kstart , kend )
, m_scalex ( scalex ) , m_scaley ( scaley ) , m_baseline ( baseline )
{
ParseStr ( ) ;
}
CPolygon : : ~ CPolygon ( )
{
}
CWord * CPolygon : : Copy ( )
{
return ( new CPolygon ( m_style , m_str , m_ktype , m_kstart , m_kend , m_scalex , m_scaley , m_baseline ) ) ;
}
bool CPolygon : : Append ( CWord * w )
{
int width = m_width ;
CPolygon * p = dynamic_cast < CPolygon * > ( w ) ;
if ( ! p ) return ( false ) ;
// TODO
return ( false ) ;
return ( true ) ;
}
bool CPolygon : : GetLONG ( CStringW & str , LONG & ret )
{
LPWSTR s = ( LPWSTR ) ( LPCWSTR ) str , e = s ;
ret = wcstol ( str , & e , 10 ) ;
str = str . Mid ( e - s ) ;
return ( e > s ) ;
}
bool CPolygon : : GetPOINT ( CStringW & str , POINT & ret )
{
return ( GetLONG ( str , ret . x ) & & GetLONG ( str , ret . y ) ) ;
}
bool CPolygon : : ParseStr ( )
{
if ( m_pathTypesOrg . GetCount ( ) > 0 ) return ( true ) ;
CPoint p ;
int i , j , lastsplinestart = - 1 , firstmoveto = - 1 , lastmoveto = - 1 ;
CStringW str = m_str ;
str . SpanIncluding ( L " mnlbspc 0123456789 " ) ;
str . Replace ( L " m " , L " *m " ) ;
str . Replace ( L " n " , L " *n " ) ;
str . Replace ( L " l " , L " *l " ) ;
str . Replace ( L " b " , L " *b " ) ;
str . Replace ( L " s " , L " *s " ) ;
str . Replace ( L " p " , L " *p " ) ;
str . Replace ( L " c " , L " *c " ) ;
int k = 0 ;
for ( CStringW s = str . Tokenize ( L " * " , k ) ; ! s . IsEmpty ( ) ; s = str . Tokenize ( L " * " , k ) )
{
WCHAR c = s [ 0 ] ;
s . TrimLeft ( L " mnlbspc " ) ;
switch ( c )
{
case ' m ' :
lastmoveto = m_pathTypesOrg . GetCount ( ) ;
if ( firstmoveto = = - 1 ) firstmoveto = lastmoveto ;
while ( GetPOINT ( s , p ) ) { m_pathTypesOrg . Add ( PT_MOVETO ) ; m_pathPointsOrg . Add ( p ) ; }
break ;
case ' n ' :
while ( GetPOINT ( s , p ) ) { m_pathTypesOrg . Add ( PT_MOVETONC ) ; m_pathPointsOrg . Add ( p ) ; }
break ;
case ' l ' :
while ( GetPOINT ( s , p ) ) { m_pathTypesOrg . Add ( PT_LINETO ) ; m_pathPointsOrg . Add ( p ) ; }
break ;
case ' b ' :
j = m_pathTypesOrg . GetCount ( ) ;
while ( GetPOINT ( s , p ) ) { m_pathTypesOrg . Add ( PT_BEZIERTO ) ; m_pathPointsOrg . Add ( p ) ; j + + ; }
j = m_pathTypesOrg . GetCount ( ) - ( ( m_pathTypesOrg . GetCount ( ) - j ) % 3 ) ;
m_pathTypesOrg . SetCount ( j ) ; m_pathPointsOrg . SetCount ( j ) ;
break ;
case ' s ' :
j = lastsplinestart = m_pathTypesOrg . GetCount ( ) ;
i = 3 ;
while ( i - - & & GetPOINT ( s , p ) ) { m_pathTypesOrg . Add ( PT_BSPLINETO ) ; m_pathPointsOrg . Add ( p ) ; j + + ; }
if ( m_pathTypesOrg . GetCount ( ) - lastsplinestart < 3 ) { m_pathTypesOrg . SetCount ( lastsplinestart ) ; m_pathPointsOrg . SetCount ( lastsplinestart ) ; lastsplinestart = - 1 ; }
// no break here
case ' p ' :
while ( GetPOINT ( s , p ) ) { m_pathTypesOrg . Add ( PT_BSPLINEPATCHTO ) ; m_pathPointsOrg . Add ( p ) ; j + + ; }
break ;
case ' c ' :
if ( lastsplinestart > 0 )
{
m_pathTypesOrg . Add ( PT_BSPLINEPATCHTO ) ;
m_pathTypesOrg . Add ( PT_BSPLINEPATCHTO ) ;
m_pathTypesOrg . Add ( PT_BSPLINEPATCHTO ) ;
p = m_pathPointsOrg [ lastsplinestart - 1 ] ; // we need p for temp storage, because operator [] will return a reference to CPoint and Add() may reallocate its internal buffer (this is true for MFC 7.0 but not for 6.0, hehe)
m_pathPointsOrg . Add ( p ) ;
p = m_pathPointsOrg [ lastsplinestart ] ;
m_pathPointsOrg . Add ( p ) ;
p = m_pathPointsOrg [ lastsplinestart + 1 ] ;
m_pathPointsOrg . Add ( p ) ;
lastsplinestart = - 1 ;
}
break ;
default :
break ;
}
}
/*
LPCWSTR str = m_str ;
while ( * str )
{
while ( * str & & * str ! = ' m ' & & * str ! = ' n ' & & * str ! = ' l ' & & * str ! = ' b ' & & * str ! = ' s ' & & * str ! = ' p ' & & * str ! = ' c ' ) str + + ;
if ( ! * str ) break ;
switch ( * str + + )
{
case ' m ' :
lastmoveto = m_pathTypesOrg . GetCount ( ) ;
if ( firstmoveto = = - 1 ) firstmoveto = lastmoveto ;
while ( GetPOINT ( str , p ) ) { m_pathTypesOrg . Add ( PT_MOVETO ) ; m_pathPointsOrg . Add ( p ) ; }
break ;
case ' n ' :
while ( GetPOINT ( str , p ) ) { m_pathTypesOrg . Add ( PT_MOVETONC ) ; m_pathPointsOrg . Add ( p ) ; }
break ;
case ' l ' :
while ( GetPOINT ( str , p ) ) { m_pathTypesOrg . Add ( PT_LINETO ) ; m_pathPointsOrg . Add ( p ) ; }
break ;
case ' b ' :
j = m_pathTypesOrg . GetCount ( ) ;
while ( GetPOINT ( str , p ) ) { m_pathTypesOrg . Add ( PT_BEZIERTO ) ; m_pathPointsOrg . Add ( p ) ; j + + ; }
j = m_pathTypesOrg . GetCount ( ) - ( ( m_pathTypesOrg . GetCount ( ) - j ) % 3 ) ;
m_pathTypesOrg . SetCount ( j ) ; m_pathPointsOrg . SetCount ( j ) ;
break ;
case ' s ' :
j = lastsplinestart = m_pathTypesOrg . GetCount ( ) ;
i = 3 ;
while ( i - - & & GetPOINT ( str , p ) ) { m_pathTypesOrg . Add ( PT_BSPLINETO ) ; m_pathPointsOrg . Add ( p ) ; j + + ; }
if ( m_pathTypesOrg . GetCount ( ) - lastsplinestart < 3 ) { m_pathTypesOrg . SetCount ( lastsplinestart ) ; m_pathPointsOrg . SetCount ( lastsplinestart ) ; lastsplinestart = - 1 ; }
// no break here
case ' p ' :
while ( GetPOINT ( str , p ) ) { m_pathTypesOrg . Add ( PT_BSPLINEPATCHTO ) ; m_pathPointsOrg . Add ( p ) ; j + + ; }
break ;
case ' c ' :
if ( lastsplinestart > 0 )
{
m_pathTypesOrg . Add ( PT_BSPLINEPATCHTO ) ;
m_pathTypesOrg . Add ( PT_BSPLINEPATCHTO ) ;
m_pathTypesOrg . Add ( PT_BSPLINEPATCHTO ) ;
p = m_pathPointsOrg [ lastsplinestart - 1 ] ; // we need p for temp storage, because operator [] will return a reference to CPoint and Add() may reallocate its internal buffer (this is true for MFC 7.0 but not for 6.0, hehe)
m_pathPointsOrg . Add ( p ) ;
p = m_pathPointsOrg [ lastsplinestart ] ;
m_pathPointsOrg . Add ( p ) ;
p = m_pathPointsOrg [ lastsplinestart + 1 ] ;
m_pathPointsOrg . Add ( p ) ;
lastsplinestart = - 1 ;
}
break ;
default :
break ;
}
if ( firstmoveto > 0 ) break ;
}
*/
if ( lastmoveto = = - 1 | | firstmoveto > 0 )
{
m_pathTypesOrg . RemoveAll ( ) ;
m_pathPointsOrg . RemoveAll ( ) ;
return ( false ) ;
}
int minx = INT_MAX , miny = INT_MAX , maxx = - INT_MAX , maxy = - INT_MAX ;
for ( i = 0 ; i < m_pathTypesOrg . GetCount ( ) ; i + + )
{
m_pathPointsOrg [ i ] . x = ( int ) ( 64 * m_scalex * m_pathPointsOrg [ i ] . x ) ;
m_pathPointsOrg [ i ] . y = ( int ) ( 64 * m_scaley * m_pathPointsOrg [ i ] . y ) ;
if ( minx > m_pathPointsOrg [ i ] . x ) minx = m_pathPointsOrg [ i ] . x ;
if ( miny > m_pathPointsOrg [ i ] . y ) miny = m_pathPointsOrg [ i ] . y ;
if ( maxx < m_pathPointsOrg [ i ] . x ) maxx = m_pathPointsOrg [ i ] . x ;
if ( maxy < m_pathPointsOrg [ i ] . y ) maxy = m_pathPointsOrg [ i ] . y ;
}
m_width = max ( maxx - minx , 0 ) ;
m_ascent = max ( maxy - miny , 0 ) ;
int baseline = ( int ) ( 64 * m_scaley * m_baseline ) ;
m_descent = baseline ;
m_ascent - = baseline ;
m_width = ( ( int ) ( m_style . fontScaleX / 100 * m_width ) + 4 ) > > 3 ;
m_ascent = ( ( int ) ( m_style . fontScaleY / 100 * m_ascent ) + 4 ) > > 3 ;
m_descent = ( ( int ) ( m_style . fontScaleY / 100 * m_descent ) + 4 ) > > 3 ;
return ( true ) ;
}
bool CPolygon : : CreatePath ( )
{
int len = m_pathTypesOrg . GetCount ( ) ;
if ( len = = 0 ) return ( false ) ;
if ( mPathPoints ! = len )
{
mpPathTypes = ( BYTE * ) realloc ( mpPathTypes , len * sizeof ( BYTE ) ) ;
mpPathPoints = ( POINT * ) realloc ( mpPathPoints , len * sizeof ( POINT ) ) ;
if ( ! mpPathTypes | | ! mpPathPoints ) return ( false ) ;
mPathPoints = len ;
}
memcpy ( mpPathTypes , m_pathTypesOrg . GetData ( ) , len * sizeof ( BYTE ) ) ;
memcpy ( mpPathPoints , m_pathPointsOrg . GetData ( ) , len * sizeof ( POINT ) ) ;
return ( true ) ;
}
// CClipper
CClipper : : CClipper ( CStringW str , CSize size , double scalex , double scaley )
: CPolygon ( STSStyle ( ) , str , 0 , 0 , 0 , scalex , scaley , 0 )
{
m_size . cx = m_size . cy = 0 ;
m_pAlphaMask = NULL ;
if ( size . cx < 0 | | size . cy < 0 | | ! ( m_pAlphaMask = new BYTE [ size . cx * size . cy ] ) ) return ;
m_size = size ;
memset ( m_pAlphaMask , 0 , size . cx * size . cy ) ;
Paint ( CPoint ( 0 , 0 ) , CPoint ( 0 , 0 ) ) ;
int w = mOverlayWidth , h = mOverlayHeight ;
int x = ( mOffsetX + 4 ) > > 3 , y = ( mOffsetY + 4 ) > > 3 ;
int xo = 0 , yo = 0 ;
if ( x < 0 ) { xo = - x ; w - = - x ; x = 0 ; }
if ( y < 0 ) { yo = - y ; h - = - y ; y = 0 ; }
if ( x + w > m_size . cx ) w = m_size . cx - x ;
if ( y + h > m_size . cy ) h = m_size . cy - y ;
if ( w < = 0 | | h < = 0 ) return ;
const BYTE * src = mpOverlayBuffer + 2 * ( mOverlayWidth * yo + xo ) ;
BYTE * dst = m_pAlphaMask + m_size . cx * y + x ;
while ( h - - )
{
for ( int wt = 0 ; wt < w ; + + wt )
dst [ wt ] = src [ wt * 2 ] ;
src + = 2 * mOverlayWidth ;
dst + = m_size . cx ;
}
}
CClipper : : ~ CClipper ( )
{
if ( m_pAlphaMask ) delete [ ] m_pAlphaMask ;
m_pAlphaMask = NULL ;
}
CWord * CClipper : : Copy ( )
{
return ( new CClipper ( m_str , m_size , m_scalex , m_scaley ) ) ;
}
bool CClipper : : Append ( CWord * w )
{
return ( false ) ;
}
// CLine
CLine : : ~ CLine ( )
{
POSITION pos = GetHeadPosition ( ) ;
while ( pos ) delete GetNext ( pos ) ;
}
void CLine : : Compact ( )
{
POSITION pos = GetHeadPosition ( ) ;
while ( pos )
{
CWord * w = GetNext ( pos ) ;
if ( ! w - > m_fWhiteSpaceChar ) break ;
m_width - = w - > m_width ;
delete w ;
RemoveHead ( ) ;
}
pos = GetTailPosition ( ) ;
while ( pos )
{
CWord * w = GetPrev ( pos ) ;
if ( ! w - > m_fWhiteSpaceChar ) break ;
m_width - = w - > m_width ;
delete w ;
RemoveTail ( ) ;
}
if ( IsEmpty ( ) ) return ;
CLine l ;
l . AddTailList ( this ) ;
RemoveAll ( ) ;
CWord * last = NULL ;
pos = l . GetHeadPosition ( ) ;
while ( pos )
{
CWord * w = l . GetNext ( pos ) ;
if ( ! last | | ! last - > Append ( w ) )
AddTail ( last = w - > Copy ( ) ) ;
}
m_ascent = m_descent = m_border = 0 ;
pos = GetHeadPosition ( ) ;
while ( pos )
{
CWord * w = GetNext ( pos ) ;
if ( m_ascent < w - > m_ascent ) m_ascent = w - > m_ascent ;
if ( m_descent < w - > m_descent ) m_descent = w - > m_descent ;
if ( m_border < w - > m_style . outlineWidth ) m_border = ( int ) ( w - > m_style . outlineWidth + 0.5 ) ;
}
}
CRect CLine : : PaintShadow ( SubPicDesc & spd , CRect & clipRect , BYTE * pAlphaMask , CPoint p , CPoint org , int time , int alpha )
{
CRect bbox ( 0 , 0 , 0 , 0 ) ;
POSITION pos = GetHeadPosition ( ) ;
while ( pos )
{
CWord * w = GetNext ( pos ) ;
if ( w - > m_fLineBreak ) return ( bbox ) ; // should not happen since this class is just a line of text without any breaks
if ( w - > m_style . shadowDepth > 0 )
{
int x = p . x + ( int ) ( w - > m_style . shadowDepth + 0.5 ) ;
int y = p . y + m_ascent - w - > m_ascent + ( int ) ( w - > m_style . shadowDepth + 0.5 ) ;
DWORD a = 0xff - w - > m_style . alpha [ 3 ] ;
if ( alpha > 0 ) a = MulDiv ( a , 0xff - alpha , 0xff ) ;
COLORREF shadow = revcolor ( w - > m_style . colors [ 3 ] ) | ( a < < 24 ) ;
long sw [ 6 ] = { shadow , - 1 } ;
w - > Paint ( CPoint ( x , y ) , org ) ;
if ( w - > m_style . borderStyle = = 0 )
{
bbox | = w - > Draw ( spd , clipRect , pAlphaMask , x , y , sw ,
w - > m_ktype > 0 | | w - > m_style . alpha [ 0 ] < 0xff ,
w - > m_style . outlineWidth > 0 & & ! ( w - > m_ktype = = 2 & & time < w - > m_kstart ) ) ;
}
else if ( w - > m_style . borderStyle = = 1 & & w - > m_pOpaqueBox )
{
bbox | = w - > m_pOpaqueBox - > Draw ( spd , clipRect , pAlphaMask , x , y , sw , true , false ) ;
}
}
p . x + = w - > m_width ;
}
return ( bbox ) ;
}
CRect CLine : : PaintOutline ( SubPicDesc & spd , CRect & clipRect , BYTE * pAlphaMask , CPoint p , CPoint org , int time , int alpha )
{
CRect bbox ( 0 , 0 , 0 , 0 ) ;
POSITION pos = GetHeadPosition ( ) ;
while ( pos )
{
CWord * w = GetNext ( pos ) ;
if ( w - > m_fLineBreak ) return ( bbox ) ; // should not happen since this class is just a line of text without any breaks
// if((w->m_style.outlineWidth > 0 || w->m_style.borderStyle == 1 && w->m_style.outlineWidth == 0) && !(w->m_ktype == 2 && time < w->m_kstart))
if ( w - > m_style . outlineWidth > 0 & & ! ( w - > m_ktype = = 2 & & time < w - > m_kstart ) )
{
int x = p . x ;
int y = p . y + m_ascent - w - > m_ascent ;
DWORD aoutline = w - > m_style . alpha [ 2 ] ;
if ( alpha > 0 ) aoutline + = MulDiv ( alpha , 0xff - w - > m_style . alpha [ 2 ] , 0xff ) ;
COLORREF outline = revcolor ( w - > m_style . colors [ 2 ] ) | ( ( 0xff - aoutline ) < < 24 ) ;
long sw [ 6 ] = { outline , - 1 } ;
w - > Paint ( CPoint ( x , y ) , org ) ;
if ( w - > m_style . borderStyle = = 0 )
{
bbox | = w - > Draw ( spd , clipRect , pAlphaMask , x , y , sw , ! w - > m_style . alpha [ 0 ] & & ! w - > m_style . alpha [ 1 ] , true ) ;
}
else if ( w - > m_style . borderStyle = = 1 & & w - > m_pOpaqueBox )
{
bbox | = w - > m_pOpaqueBox - > Draw ( spd , clipRect , pAlphaMask , x , y , sw , true /*!w->m_style.alpha[0] && !w->m_style.alpha[1]*/ , false ) ;
}
}
p . x + = w - > m_width ;
}
return ( bbox ) ;
}
CRect CLine : : PaintBody ( SubPicDesc & spd , CRect & clipRect , BYTE * pAlphaMask , CPoint p , CPoint org , int time , int alpha )
{
CRect bbox ( 0 , 0 , 0 , 0 ) ;
POSITION pos = GetHeadPosition ( ) ;
while ( pos )
{
CWord * w = GetNext ( pos ) ;
if ( w - > m_fLineBreak ) return ( bbox ) ; // should not happen since this class is just a line of text without any breaks
int x = p . x ;
int y = p . y + m_ascent - w - > m_ascent ;
// colors
DWORD aprimary = w - > m_style . alpha [ 0 ] ;
if ( alpha > 0 ) aprimary + = MulDiv ( alpha , 0xff - w - > m_style . alpha [ 0 ] , 0xff ) ;
COLORREF primary = revcolor ( w - > m_style . colors [ 0 ] ) | ( ( 0xff - aprimary ) < < 24 ) ;
DWORD asecondary = w - > m_style . alpha [ 1 ] ;
if ( alpha > 0 ) asecondary + = MulDiv ( alpha , 0xff - w - > m_style . alpha [ 1 ] , 0xff ) ;
COLORREF secondary = revcolor ( w - > m_style . colors [ 1 ] ) | ( ( 0xff - asecondary ) < < 24 ) ;
long sw [ 6 ] = { primary , 0 , secondary } ;
// karaoke
double t ;
if ( w - > m_ktype = = 0 | | w - > m_ktype = = 2 )
{
t = time < w - > m_kstart ? 0 : 1 ;
}
else if ( w - > m_ktype = = 1 )
{
if ( time < w - > m_kstart ) t = 0 ;
else if ( time < w - > m_kend )
{
t = 1.0 * ( time - w - > m_kstart ) / ( w - > m_kend - w - > m_kstart ) ;
double angle = fmod ( w - > m_style . fontAngleZ , 360.0 ) ;
if ( angle > 90 & & angle < 270 )
{
t = 1 - t ;
COLORREF tmp = sw [ 0 ] ; sw [ 0 ] = sw [ 2 ] ; sw [ 2 ] = tmp ;
}
}
else t = 1.0 ;
}
if ( t > = 1 )
{
sw [ 1 ] = 0xffffffff ;
}
sw [ 3 ] = ( int ) ( w - > m_style . outlineWidth + t * w - > m_width ) > > 3 ;
sw [ 4 ] = sw [ 2 ] ;
sw [ 5 ] = 0x00ffffff ;
w - > Paint ( CPoint ( x , y ) , org ) ;
bbox | = w - > Draw ( spd , clipRect , pAlphaMask , x , y , sw , true , false ) ;
p . x + = w - > m_width ;
}
return ( bbox ) ;
}
// CSubtitle
CSubtitle : : CSubtitle ( )
{
memset ( m_effects , 0 , sizeof ( Effect * ) * EF_NUMBEROFEFFECTS ) ;
m_pClipper = NULL ;
m_scalex = m_scaley = 1 ;
}
CSubtitle : : ~ CSubtitle ( )
{
Empty ( ) ;
}
void CSubtitle : : Empty ( )
{
POSITION pos = GetHeadPosition ( ) ;
while ( pos ) delete GetNext ( pos ) ;
pos = m_words . GetHeadPosition ( ) ;
while ( pos ) delete m_words . GetNext ( pos ) ;
for ( int i = 0 ; i < EF_NUMBEROFEFFECTS ; i + + ) { if ( m_effects [ i ] ) delete m_effects [ i ] ; }
memset ( m_effects , 0 , sizeof ( Effect * ) * EF_NUMBEROFEFFECTS ) ;
if ( m_pClipper ) delete m_pClipper ;
m_pClipper = NULL ;
}
int CSubtitle : : GetFullWidth ( )
{
int width = 0 ;
POSITION pos = m_words . GetHeadPosition ( ) ;
while ( pos ) width + = m_words . GetNext ( pos ) - > m_width ;
return ( width ) ;
}
int CSubtitle : : GetFullLineWidth ( POSITION pos )
{
int width = 0 ;
while ( pos )
{
CWord * w = m_words . GetNext ( pos ) ;
if ( w - > m_fLineBreak ) break ;
width + = w - > m_width ;
}
return ( width ) ;
}
int CSubtitle : : GetWrapWidth ( POSITION pos , int maxwidth )
{
if ( m_wrapStyle = = 0 | | m_wrapStyle = = 3 )
{
if ( maxwidth > 0 )
{
// int fullwidth = GetFullWidth();
int fullwidth = GetFullLineWidth ( pos ) ;
int minwidth = fullwidth / ( ( abs ( fullwidth ) / maxwidth ) + 1 ) ;
int width = 0 , wordwidth = 0 ;
while ( pos & & width < minwidth )
{
CWord * w = m_words . GetNext ( pos ) ;
wordwidth = w - > m_width ;
if ( abs ( width + wordwidth ) < abs ( maxwidth ) ) width + = wordwidth ;
}
maxwidth = width ;
if ( m_wrapStyle = = 3 & & pos ) maxwidth - = wordwidth ;
}
}
else if ( m_wrapStyle = = 1 )
{
// maxwidth = maxwidth;
}
else if ( m_wrapStyle = = 2 )
{
maxwidth = INT_MAX ;
}
return ( maxwidth ) ;
}
CLine * CSubtitle : : GetNextLine ( POSITION & pos , int maxwidth )
{
if ( pos = = NULL ) return ( NULL ) ;
CLine * ret = new CLine ( ) ;
if ( ! ret ) return ( NULL ) ;
ret - > m_width = ret - > m_ascent = ret - > m_descent = ret - > m_border = 0 ;
maxwidth = GetWrapWidth ( pos , maxwidth ) ;
bool fEmptyLine = true ;
while ( pos )
{
CWord * w = m_words . GetNext ( pos ) ;
if ( ret - > m_ascent < w - > m_ascent ) ret - > m_ascent = w - > m_ascent ;
if ( ret - > m_descent < w - > m_descent ) ret - > m_descent = w - > m_descent ;
if ( ret - > m_border < w - > m_style . outlineWidth ) ret - > m_border = ( int ) ( w - > m_style . outlineWidth + 0.5 ) ;
if ( w - > m_fLineBreak )
{
if ( fEmptyLine ) { ret - > m_ascent / = 2 ; ret - > m_descent / = 2 ; ret - > m_border = 0 ; }
ret - > Compact ( ) ;
return ( ret ) ;
}
fEmptyLine = false ;
bool fWSC = w - > m_fWhiteSpaceChar ;
int width = w - > m_width ;
POSITION pos2 = pos ;
while ( pos2 )
{
if ( m_words . GetAt ( pos2 ) - > m_fWhiteSpaceChar ! = fWSC
| | m_words . GetAt ( pos2 ) - > m_fLineBreak ) break ;
CWord * w2 = m_words . GetNext ( pos2 ) ;
width + = w2 - > m_width ;
}
if ( ( ret - > m_width + = width ) < = maxwidth | | ret - > IsEmpty ( ) )
{
ret - > AddTail ( w - > Copy ( ) ) ;
while ( pos ! = pos2 )
{
ret - > AddTail ( m_words . GetNext ( pos ) - > Copy ( ) ) ;
}
pos = pos2 ;
}
else
{
if ( pos ) m_words . GetPrev ( pos ) ;
else pos = m_words . GetTailPosition ( ) ;
ret - > m_width - = width ;
break ;
}
}
ret - > Compact ( ) ;
return ( ret ) ;
}
void CSubtitle : : CreateClippers ( CSize size )
{
size . cx > > = 3 ;
size . cy > > = 3 ;
if ( m_effects [ EF_BANNER ] & & m_effects [ EF_BANNER ] - > param [ 2 ] )
{
int width = m_effects [ EF_BANNER ] - > param [ 2 ] ;
int w = size . cx , h = size . cy ;
if ( ! m_pClipper )
{
CStringW str ;
str . Format ( L " m %d %d l %d %d %d %d %d %d " , 0 , 0 , w , 0 , w , h , 0 , h ) ;
m_pClipper = new CClipper ( str , size , 1 , 1 ) ;
if ( ! m_pClipper ) return ;
}
int da = ( 64 < < 8 ) / width ;
BYTE * am = m_pClipper - > m_pAlphaMask ;
for ( int j = 0 ; j < h ; j + + , am + = w )
{
int a = 0 ;
int k = min ( width , w ) ;
for ( int i = 0 ; i < k ; i + + , a + = da )
am [ i ] = ( am [ i ] * a ) > > 14 ;
a = 0x40 < < 8 ;
k = w - width ;
if ( k < 0 ) { a - = - k * da ; k = 0 ; }
for ( int i = k ; i < w ; i + + , a - = da )
am [ i ] = ( am [ i ] * a ) > > 14 ;
}
}
else if ( m_effects [ EF_SCROLL ] & & m_effects [ EF_SCROLL ] - > param [ 4 ] )
{
int height = m_effects [ EF_SCROLL ] - > param [ 4 ] ;
int w = size . cx , h = size . cy ;
if ( ! m_pClipper )
{
CStringW str ;
str . Format ( L " m %d %d l %d %d %d %d %d %d " , 0 , 0 , w , 0 , w , h , 0 , h ) ;
m_pClipper = new CClipper ( str , size , 1 , 1 ) ;
if ( ! m_pClipper ) return ;
}
int da = ( 64 < < 8 ) / height ;
int a = 0 ;
int k = m_effects [ EF_SCROLL ] - > param [ 0 ] > > 3 ;
int l = k + height ;
if ( k < 0 ) { a + = - k * da ; k = 0 ; }
if ( l > h ) { l = h ; }
if ( k < h )
{
BYTE * am = & m_pClipper - > m_pAlphaMask [ k * w ] ;
memset ( m_pClipper - > m_pAlphaMask , 0 , am - m_pClipper - > m_pAlphaMask ) ;
for ( int j = k ; j < l ; j + + , a + = da )
{
for ( int i = 0 ; i < w ; i + + , am + + )
* am = ( ( * am ) * a ) > > 14 ;
}
}
da = - ( 64 < < 8 ) / height ;
a = 0x40 < < 8 ;
l = m_effects [ EF_SCROLL ] - > param [ 1 ] > > 3 ;
k = l - height ;
if ( k < 0 ) { a + = - k * da ; k = 0 ; }
if ( l > h ) { l = h ; }
if ( k < h )
{
BYTE * am = & m_pClipper - > m_pAlphaMask [ k * w ] ;
int j = k ;
for ( ; j < l ; j + + , a + = da )
{
for ( int i = 0 ; i < w ; i + + , am + + )
* am = ( ( * am ) * a ) > > 14 ;
}
memset ( am , 0 , ( h - j ) * w ) ;
}
}
}
void CSubtitle : : MakeLines ( CSize size , CRect marginRect )
{
CSize spaceNeeded ( 0 , 0 ) ;
bool fFirstLine = true ;
m_topborder = m_bottomborder = 0 ;
CLine * l = NULL ;
POSITION pos = m_words . GetHeadPosition ( ) ;
while ( pos )
{
l = GetNextLine ( pos , size . cx - marginRect . left - marginRect . right ) ;
if ( ! l ) break ;
if ( fFirstLine ) { m_topborder = l - > m_border ; fFirstLine = false ; }
spaceNeeded . cx = max ( l - > m_width , spaceNeeded . cx ) ;
spaceNeeded . cy + = l - > m_ascent + l - > m_descent ;
AddTail ( l ) ;
}
if ( l ) m_bottomborder = l - > m_border ;
m_rect = CRect (
CPoint ( ( m_scrAlignment % 3 ) = = 1 ? marginRect . left
: ( m_scrAlignment % 3 ) = = 2 ? ( marginRect . left + ( size . cx - marginRect . right ) - spaceNeeded . cx + 1 ) / 2
: ( size . cx - marginRect . right - spaceNeeded . cx ) ,
m_scrAlignment < = 3 ? ( size . cy - marginRect . bottom - spaceNeeded . cy )
: m_scrAlignment < = 6 ? ( marginRect . top + ( size . cy - marginRect . bottom ) - spaceNeeded . cy + 1 ) / 2
: marginRect . top ) ,
spaceNeeded ) ;
}
// CScreenLayoutAllocator
void CScreenLayoutAllocator : : Empty ( )
{
m_subrects . RemoveAll ( ) ;
}
void CScreenLayoutAllocator : : AdvanceToSegment ( int segment , const CAtlArray < int > & sa )
{
POSITION pos = m_subrects . GetHeadPosition ( ) ;
while ( pos )
{
POSITION prev = pos ;
SubRect & sr = m_subrects . GetNext ( pos ) ;
bool fFound = false ;
if ( abs ( sr . segment - segment ) < = 1 ) // using abs() makes it possible to play the subs backwards, too :)
{
for ( int i = 0 ; i < sa . GetCount ( ) & & ! fFound ; i + + )
{
if ( sa [ i ] = = sr . entry )
{
sr . segment = segment ;
fFound = true ;
}
}
}
if ( ! fFound ) m_subrects . RemoveAt ( prev ) ;
}
}
CRect CScreenLayoutAllocator : : AllocRect ( CSubtitle * s , int segment , int entry , int layer , int collisions )
{
// TODO: handle collisions == 1 (reversed collisions)
POSITION pos = m_subrects . GetHeadPosition ( ) ;
while ( pos )
{
SubRect & sr = m_subrects . GetNext ( pos ) ;
if ( sr . segment = = segment & & sr . entry = = entry )
{
return ( sr . r + CRect ( 0 , - s - > m_topborder , 0 , - s - > m_bottomborder ) ) ;
}
}
CRect r = s - > m_rect + CRect ( 0 , s - > m_topborder , 0 , s - > m_bottomborder ) ;
bool fSearchDown = s - > m_scrAlignment > 3 ;
bool fOK ;
do
{
fOK = true ;
pos = m_subrects . GetHeadPosition ( ) ;
while ( pos )
{
SubRect & sr = m_subrects . GetNext ( pos ) ;
if ( layer = = sr . layer & & ! ( r & sr . r ) . IsRectEmpty ( ) )
{
if ( fSearchDown )
{
r . bottom = sr . r . bottom + r . Height ( ) ;
r . top = sr . r . bottom ;
}
else
{
r . top = sr . r . top - r . Height ( ) ;
r . bottom = sr . r . top ;
}
fOK = false ;
}
}
}
while ( ! fOK ) ;
SubRect sr ;
sr . r = r ;
sr . segment = segment ;
sr . entry = entry ;
sr . layer = layer ;
m_subrects . AddTail ( sr ) ;
return ( sr . r + CRect ( 0 , - s - > m_topborder , 0 , - s - > m_bottomborder ) ) ;
}
// CRenderedTextSubtitle
CRenderedTextSubtitle : : CRenderedTextSubtitle ( CCritSec * pLock )
: ISubPicProviderImpl ( pLock )
{
m_size = CSize ( 0 , 0 ) ;
if ( g_hDC_refcnt = = 0 )
{
g_hDC = CreateCompatibleDC ( NULL ) ;
SetBkMode ( g_hDC , TRANSPARENT ) ;
SetTextColor ( g_hDC , 0xffffff ) ;
SetMapMode ( g_hDC , MM_TEXT ) ;
}
g_hDC_refcnt + + ;
}
CRenderedTextSubtitle : : ~ CRenderedTextSubtitle ( )
{
Deinit ( ) ;
g_hDC_refcnt - - ;
if ( g_hDC_refcnt = = 0 ) DeleteDC ( g_hDC ) ;
}
void CRenderedTextSubtitle : : Copy ( CSimpleTextSubtitle & sts )
{
__super : : Copy ( sts ) ;
m_size = CSize ( 0 , 0 ) ;
if ( CRenderedTextSubtitle * pRTS = dynamic_cast < CRenderedTextSubtitle * > ( & sts ) )
{
m_size = pRTS - > m_size ;
}
}
void CRenderedTextSubtitle : : Empty ( )
{
Deinit ( ) ;
__super : : Empty ( ) ;
}
void CRenderedTextSubtitle : : OnChanged ( )
{
__super : : OnChanged ( ) ;
POSITION pos = m_subtitleCache . GetStartPosition ( ) ;
while ( pos )
{
int i ;
CSubtitle * s ;
m_subtitleCache . GetNextAssoc ( pos , i , s ) ;
delete s ;
}
m_subtitleCache . RemoveAll ( ) ;
m_sla . Empty ( ) ;
}
bool CRenderedTextSubtitle : : Init ( CSize size , CRect vidrect )
{
Deinit ( ) ;
m_size = CSize ( size . cx * 8 , size . cy * 8 ) ;
m_vidrect = CRect ( vidrect . left * 8 , vidrect . top * 8 , vidrect . right * 8 , vidrect . bottom * 8 ) ;
m_sla . Empty ( ) ;
return ( true ) ;
}
void CRenderedTextSubtitle : : Deinit ( )
{
POSITION pos = m_subtitleCache . GetStartPosition ( ) ;
while ( pos )
{
int i ;
CSubtitle * s ;
m_subtitleCache . GetNextAssoc ( pos , i , s ) ;
delete s ;
}
m_subtitleCache . RemoveAll ( ) ;
m_sla . Empty ( ) ;
m_size = CSize ( 0 , 0 ) ;
m_vidrect . SetRectEmpty ( ) ;
}
void CRenderedTextSubtitle : : ParseEffect ( CSubtitle * sub , CString str )
{
str . Trim ( ) ;
if ( ! sub | | str . IsEmpty ( ) ) return ;
const TCHAR * s = _tcschr ( str , ' ; ' ) ;
if ( ! s ) { s = ( LPTSTR ) ( LPCTSTR ) str ; s + = str . GetLength ( ) - 1 ; }
s + + ;
CString effect = str . Left ( s - str ) ;
if ( ! effect . CompareNoCase ( _T ( " Banner; " ) ) )
{
int delay , lefttoright = 0 , fadeawaywidth = 0 ;
if ( _stscanf ( s , _T ( " %d;%d;%d " ) , & delay , & lefttoright , & fadeawaywidth ) < 1 ) return ;
Effect * e = new Effect ;
if ( ! e ) return ;
sub - > m_effects [ e - > type = EF_BANNER ] = e ;
e - > param [ 0 ] = ( int ) ( max ( 1.0 * delay / sub - > m_scalex , 1 ) ) ;
e - > param [ 1 ] = lefttoright ;
e - > param [ 2 ] = ( int ) ( sub - > m_scalex * fadeawaywidth ) ;
sub - > m_wrapStyle = 2 ;
}
else if ( ! effect . CompareNoCase ( _T ( " Scroll up; " ) ) | | ! effect . CompareNoCase ( _T ( " Scroll down; " ) ) )
{
int top , bottom , delay , fadeawayheight = 0 ;
if ( _stscanf ( s , _T ( " %d;%d;%d;%d " ) , & top , & bottom , & delay , & fadeawayheight ) < 3 ) return ;
if ( top > bottom ) { int tmp = top ; top = bottom ; bottom = tmp ; }
Effect * e = new Effect ;
if ( ! e ) return ;
sub - > m_effects [ e - > type = EF_SCROLL ] = e ;
e - > param [ 0 ] = ( int ) ( sub - > m_scaley * top * 8 ) ;
e - > param [ 1 ] = ( int ) ( sub - > m_scaley * bottom * 8 ) ;
e - > param [ 2 ] = ( int ) ( max ( 1.0 * delay / sub - > m_scaley , 1 ) ) ;
e - > param [ 3 ] = ( effect . GetLength ( ) = = 12 ) ;
e - > param [ 4 ] = ( int ) ( sub - > m_scaley * fadeawayheight ) ;
}
}
void CRenderedTextSubtitle : : ParseString ( CSubtitle * sub , CStringW str , STSStyle & style )
{
if ( ! sub ) return ;
str . Replace ( L " \\ N " , L " \n " ) ;
str . Replace ( L " \\ n " , ( sub - > m_wrapStyle < 2 | | sub - > m_wrapStyle = = 3 ) ? L " " : L " \n " ) ;
str . Replace ( L " \\ h " , L " \x00A0 " ) ;
for ( int i = 0 , j = 0 , len = str . GetLength ( ) ; j < = len ; j + + )
{
WCHAR c = str [ j ] ;
if ( c ! = ' \n ' & & c ! = ' ' & & c ! = ' \ x00A0 ' & & c ! = 0 )
continue ;
if ( i < j )
{
if ( CWord * w = new CText ( style , str . Mid ( i , j - i ) , m_ktype , m_kstart , m_kend ) )
{
sub - > m_words . AddTail ( w ) ;
m_kstart = m_kend ;
}
}
if ( c = = ' \n ' )
{
if ( CWord * w = new CText ( style , CStringW ( ) , m_ktype , m_kstart , m_kend ) )
{
sub - > m_words . AddTail ( w ) ;
m_kstart = m_kend ;
}
}
else if ( c = = ' ' | | c = = ' \ x00A0 ' )
{
if ( CWord * w = new CText ( style , CStringW ( c ) , m_ktype , m_kstart , m_kend ) )
{
sub - > m_words . AddTail ( w ) ;
m_kstart = m_kend ;
}
}
i = j + 1 ;
}
return ;
}
void CRenderedTextSubtitle : : ParsePolygon ( CSubtitle * sub , CStringW str , STSStyle & style )
{
if ( ! sub | | ! str . GetLength ( ) | | ! m_nPolygon ) return ;
if ( CWord * w = new CPolygon ( style , str , m_ktype , m_kstart , m_kend , sub - > m_scalex / ( 1 < < ( m_nPolygon - 1 ) ) , sub - > m_scaley / ( 1 < < ( m_nPolygon - 1 ) ) , m_polygonBaselineOffset ) )
{
sub - > m_words . AddTail ( w ) ;
m_kstart = m_kend ;
}
}
bool CRenderedTextSubtitle : : ParseSSATag ( CSubtitle * sub , CStringW str , STSStyle & style , STSStyle & org , bool fAnimate )
{
if ( ! sub ) return ( false ) ;
int nTags = 0 , nUnrecognizedTags = 0 ;
for ( int i = 0 , j ; ( j = str . Find ( ' \\ ' , i ) ) > = 0 ; i = j )
{
CStringW cmd ;
for ( WCHAR c = str [ + + j ] ; c & & c ! = ' ( ' & & c ! = ' \\ ' ; cmd + = c , c = str [ + + j ] ) ;
cmd . Trim ( ) ;
if ( cmd . IsEmpty ( ) ) continue ;
CAtlArray < CStringW > params ;
if ( str [ j ] = = ' ( ' )
{
CStringW param ;
for ( WCHAR c = str [ + + j ] ; c & & c ! = ' ) ' ; param + = c , c = str [ + + j ] ) ;
param . Trim ( ) ;
while ( ! param . IsEmpty ( ) )
{
int i = param . Find ( ' , ' ) , j = param . Find ( ' \\ ' ) ;
if ( i > = 0 & & ( j < 0 | | i < j ) )
{
CStringW s = param . Left ( i ) . Trim ( ) ;
if ( ! s . IsEmpty ( ) ) params . Add ( s ) ;
param = i + 1 < param . GetLength ( ) ? param . Mid ( i + 1 ) : L " " ;
}
else
{
param . Trim ( ) ;
if ( ! param . IsEmpty ( ) ) params . Add ( param ) ;
param . Empty ( ) ;
}
}
}
if ( ! cmd . Find ( L " 1c " ) | | ! cmd . Find ( L " 2c " ) | | ! cmd . Find ( L " 3c " ) | | ! cmd . Find ( L " 4c " ) )
params . Add ( cmd . Mid ( 2 ) . Trim ( L " &H " ) ) , cmd = cmd . Left ( 2 ) ;
else if ( ! cmd . Find ( L " 1a " ) | | ! cmd . Find ( L " 2a " ) | | ! cmd . Find ( L " 3a " ) | | ! cmd . Find ( L " 4a " ) )
params . Add ( cmd . Mid ( 2 ) . Trim ( L " &H " ) ) , cmd = cmd . Left ( 2 ) ;
else if ( ! cmd . Find ( L " alpha " ) )
params . Add ( cmd . Mid ( 5 ) . Trim ( L " &H " ) ) , cmd = cmd . Left ( 5 ) ;
else if ( ! cmd . Find ( L " an " ) )
params . Add ( cmd . Mid ( 2 ) ) , cmd = cmd . Left ( 2 ) ;
else if ( ! cmd . Find ( L " a " ) )
params . Add ( cmd . Mid ( 1 ) ) , cmd = cmd . Left ( 1 ) ;
else if ( ! cmd . Find ( L " bord " ) )
params . Add ( cmd . Mid ( 4 ) ) , cmd = cmd . Left ( 4 ) ;
else if ( ! cmd . Find ( L " be " ) )
params . Add ( cmd . Mid ( 2 ) ) , cmd = cmd . Left ( 2 ) ;
else if ( ! cmd . Find ( L " b " ) )
params . Add ( cmd . Mid ( 1 ) ) , cmd = cmd . Left ( 1 ) ;
else if ( ! cmd . Find ( L " clip " ) )
;
else if ( ! cmd . Find ( L " c " ) )
params . Add ( cmd . Mid ( 1 ) . Trim ( L " &H " ) ) , cmd = cmd . Left ( 1 ) ;
else if ( ! cmd . Find ( L " fade " ) )
;
else if ( ! cmd . Find ( L " fe " ) )
params . Add ( cmd . Mid ( 2 ) ) , cmd = cmd . Left ( 2 ) ;
else if ( ! cmd . Find ( L " fn " ) )
params . Add ( cmd . Mid ( 2 ) ) , cmd = cmd . Left ( 2 ) ;
else if ( ! cmd . Find ( L " frx " ) | | ! cmd . Find ( L " fry " ) | | ! cmd . Find ( L " frz " ) )
params . Add ( cmd . Mid ( 3 ) ) , cmd = cmd . Left ( 3 ) ;
else if ( ! cmd . Find ( L " fax " ) | | ! cmd . Find ( L " fay " ) )
params . Add ( cmd . Mid ( 3 ) ) , cmd = cmd . Left ( 3 ) ;
else if ( ! cmd . Find ( L " fr " ) )
params . Add ( cmd . Mid ( 2 ) ) , cmd = cmd . Left ( 2 ) ;
else if ( ! cmd . Find ( L " fscx " ) | | ! cmd . Find ( L " fscy " ) )
params . Add ( cmd . Mid ( 4 ) ) , cmd = cmd . Left ( 4 ) ;
else if ( ! cmd . Find ( L " fsc " ) )
params . Add ( cmd . Mid ( 3 ) ) , cmd = cmd . Left ( 3 ) ;
else if ( ! cmd . Find ( L " fsp " ) )
params . Add ( cmd . Mid ( 3 ) ) , cmd = cmd . Left ( 3 ) ;
else if ( ! cmd . Find ( L " fs " ) )
params . Add ( cmd . Mid ( 2 ) ) , cmd = cmd . Left ( 2 ) ;
else if ( ! cmd . Find ( L " i " ) )
params . Add ( cmd . Mid ( 1 ) ) , cmd = cmd . Left ( 1 ) ;
else if ( ! cmd . Find ( L " kt " ) | | ! cmd . Find ( L " kf " ) | | ! cmd . Find ( L " ko " ) )
params . Add ( cmd . Mid ( 2 ) ) , cmd = cmd . Left ( 2 ) ;
else if ( ! cmd . Find ( L " k " ) | | ! cmd . Find ( L " K " ) )
params . Add ( cmd . Mid ( 1 ) ) , cmd = cmd . Left ( 1 ) ;
else if ( ! cmd . Find ( L " move " ) )
;
else if ( ! cmd . Find ( L " org " ) )
;
else if ( ! cmd . Find ( L " pbo " ) )
params . Add ( cmd . Mid ( 3 ) ) , cmd = cmd . Left ( 3 ) ;
else if ( ! cmd . Find ( L " pos " ) )
;
else if ( ! cmd . Find ( L " p " ) )
params . Add ( cmd . Mid ( 1 ) ) , cmd = cmd . Left ( 1 ) ;
else if ( ! cmd . Find ( L " q " ) )
params . Add ( cmd . Mid ( 1 ) ) , cmd = cmd . Left ( 1 ) ;
else if ( ! cmd . Find ( L " r " ) )
params . Add ( cmd . Mid ( 1 ) ) , cmd = cmd . Left ( 1 ) ;
else if ( ! cmd . Find ( L " shad " ) )
params . Add ( cmd . Mid ( 4 ) ) , cmd = cmd . Left ( 4 ) ;
else if ( ! cmd . Find ( L " s " ) )
params . Add ( cmd . Mid ( 1 ) ) , cmd = cmd . Left ( 1 ) ;
else if ( ! cmd . Find ( L " t " ) )
;
else if ( ! cmd . Find ( L " u " ) )
params . Add ( cmd . Mid ( 1 ) ) , cmd = cmd . Left ( 1 ) ;
else
nUnrecognizedTags + + ;
nTags + + ;
// TODO: call ParseStyleModifier(cmd, params, ..) and move the rest there
CStringW p = params . GetCount ( ) > 0 ? params [ 0 ] : L " " ;
if ( cmd = = " 1c " | | cmd = = L " 2c " | | cmd = = L " 3c " | | cmd = = L " 4c " )
{
int i = cmd [ 0 ] - ' 1 ' ;
DWORD c = wcstol ( p , NULL , 16 ) ;
style . colors [ i ] = ! p . IsEmpty ( )
? ( ( ( int ) CalcAnimation ( c & 0xff , style . colors [ i ] & 0xff , fAnimate ) ) & 0xff
| ( ( int ) CalcAnimation ( c & 0xff00 , style . colors [ i ] & 0xff00 , fAnimate ) ) & 0xff00
| ( ( int ) CalcAnimation ( c & 0xff0000 , style . colors [ i ] & 0xff0000 , fAnimate ) ) & 0xff0000 )
: org . colors [ i ] ;
}
else if ( cmd = = L " 1a " | | cmd = = L " 2a " | | cmd = = L " 3a " | | cmd = = L " 4a " )
{
int i = cmd [ 0 ] - ' 1 ' ;
style . alpha [ i ] = ! p . IsEmpty ( )
? ( BYTE ) CalcAnimation ( wcstol ( p , NULL , 16 ) , style . alpha [ i ] , fAnimate )
: org . alpha [ i ] ;
}
else if ( cmd = = L " alpha " )
{
for ( int i = 0 ; i < 4 ; i + + )
{
style . alpha [ i ] = ! p . IsEmpty ( )
? ( BYTE ) CalcAnimation ( wcstol ( p , NULL , 16 ) , style . alpha [ i ] , fAnimate )
: org . alpha [ i ] ;
}
}
else if ( cmd = = L " an " )
{
int n = wcstol ( p , NULL , 10 ) ;
if ( sub - > m_scrAlignment < 0 )
sub - > m_scrAlignment = ( n > 0 & & n < 10 ) ? n : org . scrAlignment ;
}
else if ( cmd = = L " a " )
{
int n = wcstol ( p , NULL , 10 ) ;
if ( sub - > m_scrAlignment < 0 )
sub - > m_scrAlignment = ( n > 0 & & n < 12 ) ? ( ( ( ( n - 1 ) & 3 ) + 1 ) + ( ( n & 4 ) ? 6 : 0 ) + ( ( n & 8 ) ? 3 : 0 ) ) : org . scrAlignment ;
}
else if ( cmd = = L " bord " )
{
double n = CalcAnimation ( wcstod ( p , NULL ) , style . outlineWidth , fAnimate ) ;
style . outlineWidth = ! p . IsEmpty ( )
? ( n < 0 ? 0 : n )
: org . outlineWidth ;
}
else if ( cmd = = L " be " )
{
int n = wcstol ( p , NULL , 10 ) ;
style . fBlur = ! p . IsEmpty ( )
? ( n = = 0 ? false : n = = 1 ? true : org . fBlur )
: org . fBlur ;
}
else if ( cmd = = L " b " )
{
int n = wcstol ( p , NULL , 10 ) ;
style . fontWeight = ! p . IsEmpty ( )
? ( n = = 0 ? FW_NORMAL : n = = 1 ? FW_BOLD : n > = 100 ? n : org . fontWeight )
: org . fontWeight ;
}
else if ( cmd = = L " clip " )
{
if ( params . GetCount ( ) = = 1 & & ! sub - > m_pClipper )
{
sub - > m_pClipper = new CClipper ( params [ 0 ] , CSize ( m_size . cx > > 3 , m_size . cy > > 3 ) , sub - > m_scalex , sub - > m_scaley ) ;
}
else if ( params . GetCount ( ) = = 2 & & ! sub - > m_pClipper )
{
int scale = max ( wcstol ( p , NULL , 10 ) , 1 ) ;
sub - > m_pClipper = new CClipper ( params [ 1 ] , CSize ( m_size . cx > > 3 , m_size . cy > > 3 ) , sub - > m_scalex / ( 1 < < ( scale - 1 ) ) , sub - > m_scaley / ( 1 < < ( scale - 1 ) ) ) ;
}
else if ( params . GetCount ( ) = = 4 )
{
CRect r ;
r . SetRect (
wcstol ( params [ 0 ] , NULL , 10 ) ,
wcstol ( params [ 1 ] , NULL , 10 ) ,
wcstol ( params [ 2 ] , NULL , 10 ) ,
wcstol ( params [ 3 ] , NULL , 10 ) ) ;
CPoint o ( 0 , 0 ) ;
if ( sub - > m_relativeTo = = 1 ) // TODO: this should also apply to the other two clippings above
{
o . x = m_vidrect . left > > 3 ;
o . y = m_vidrect . top > > 3 ;
}
sub - > m_clip . SetRect (
( int ) CalcAnimation ( sub - > m_scalex * r . left + o . x , sub - > m_clip . left , fAnimate ) ,
( int ) CalcAnimation ( sub - > m_scaley * r . top + o . y , sub - > m_clip . top , fAnimate ) ,
( int ) CalcAnimation ( sub - > m_scalex * r . right + o . x , sub - > m_clip . right , fAnimate ) ,
( int ) CalcAnimation ( sub - > m_scaley * r . bottom + o . y , sub - > m_clip . bottom , fAnimate ) ) ;
}
}
else if ( cmd = = L " c " )
{
DWORD c = wcstol ( p , NULL , 16 ) ;
style . colors [ 0 ] = ! p . IsEmpty ( )
? ( ( ( int ) CalcAnimation ( c & 0xff , style . colors [ 0 ] & 0xff , fAnimate ) ) & 0xff
| ( ( int ) CalcAnimation ( c & 0xff00 , style . colors [ 0 ] & 0xff00 , fAnimate ) ) & 0xff00
| ( ( int ) CalcAnimation ( c & 0xff0000 , style . colors [ 0 ] & 0xff0000 , fAnimate ) ) & 0xff0000 )
: org . colors [ 0 ] ;
}
else if ( cmd = = L " fade " | | cmd = = L " fad " )
{
if ( params . GetCount ( ) = = 7 & & ! sub - > m_effects [ EF_FADE ] ) // {\fade(a1=param[0], a2=param[1], a3=param[2], t1=t[0], t2=t[1], t3=t[2], t4=t[3])
{
if ( Effect * e = new Effect )
{
for ( int i = 0 ; i < 3 ; i + + )
e - > param [ i ] = wcstol ( params [ i ] , NULL , 10 ) ;
for ( int i = 0 ; i < 4 ; i + + )
e - > t [ i ] = wcstol ( params [ 3 + i ] , NULL , 10 ) ;
sub - > m_effects [ EF_FADE ] = e ;
}
}
else if ( params . GetCount ( ) = = 2 & & ! sub - > m_effects [ EF_FADE ] ) / / { \ fad ( t1 = t [ 1 ] , t2 = t [ 2 ] )
{
if ( Effect * e = new Effect )
{
e - > param [ 0 ] = e - > param [ 2 ] = 0xff ;
e - > param [ 1 ] = 0x00 ;
for ( int i = 1 ; i < 3 ; i + + )
e - > t [ i ] = wcstol ( params [ i - 1 ] , NULL , 10 ) ;
e - > t [ 0 ] = e - > t [ 3 ] = - 1 ; // will be substituted with "start" and "end"
sub - > m_effects [ EF_FADE ] = e ;
}
}
}
else if ( cmd = = L " fax " )
{
style . fontShiftX = ! p . IsEmpty ( )
? CalcAnimation ( wcstod ( p , NULL ) , style . fontShiftX , fAnimate )
: org . fontShiftX ;
}
else if ( cmd = = L " fay " )
{
style . fontShiftY = ! p . IsEmpty ( )
? CalcAnimation ( wcstod ( p , NULL ) , style . fontShiftY , fAnimate )
: org . fontShiftY ;
}
else if ( cmd = = L " fe " )
{
int n = wcstol ( p , NULL , 10 ) ;
style . charSet = ! p . IsEmpty ( )
? n
: org . charSet ;
}
else if ( cmd = = L " fn " )
{
style . fontName = ( ! p . IsEmpty ( ) & & p ! = ' 0 ' )
? CString ( p ) . Trim ( )
: org . fontName ;
}
else if ( cmd = = L " frx " )
{
style . fontAngleX = ! p . IsEmpty ( )
? CalcAnimation ( wcstod ( p , NULL ) , style . fontAngleX , fAnimate )
: org . fontAngleX ;
}
else if ( cmd = = L " fry " )
{
style . fontAngleY = ! p . IsEmpty ( )
? CalcAnimation ( wcstod ( p , NULL ) , style . fontAngleY , fAnimate )
: org . fontAngleY ;
}
else if ( cmd = = L " frz " | | cmd = = L " fr " )
{
style . fontAngleZ = ! p . IsEmpty ( )
? CalcAnimation ( wcstod ( p , NULL ) , style . fontAngleZ , fAnimate )
: org . fontAngleZ ;
}
else if ( cmd = = L " fscx " )
{
double n = CalcAnimation ( wcstol ( p , NULL , 10 ) , style . fontScaleX , fAnimate ) ;
style . fontScaleX = ! p . IsEmpty ( )
? ( ( n < 0 ) ? 0 : n )
: org . fontScaleX ;
}
else if ( cmd = = L " fscy " )
{
double n = CalcAnimation ( wcstol ( p , NULL , 10 ) , style . fontScaleY , fAnimate ) ;
style . fontScaleY = ! p . IsEmpty ( )
? ( ( n < 0 ) ? 0 : n )
: org . fontScaleY ;
}
else if ( cmd = = L " fsc " )
{
style . fontScaleX = org . fontScaleX ;
style . fontScaleY = org . fontScaleY ;
}
else if ( cmd = = L " fsp " )
{
style . fontSpacing = ! p . IsEmpty ( )
? CalcAnimation ( wcstod ( p , NULL ) , style . fontSpacing , fAnimate )
: org . fontSpacing ;
}
else if ( cmd = = L " fs " )
{
if ( ! p . IsEmpty ( ) )
{
if ( p [ 0 ] = = ' - ' | | p [ 0 ] = = ' + ' )
{
double n = CalcAnimation ( style . fontSize + style . fontSize * wcstol ( p , NULL , 10 ) / 10 , style . fontSize , fAnimate ) ;
style . fontSize = ( n > 0 ) ? n : org . fontSize ;
}
else
{
double n = CalcAnimation ( wcstol ( p , NULL , 10 ) , style . fontSize , fAnimate ) ;
style . fontSize = ( n > 0 ) ? n : org . fontSize ;
}
}
else
{
style . fontSize = org . fontSize ;
}
}
else if ( cmd = = L " i " )
{
int n = wcstol ( p , NULL , 10 ) ;
style . fItalic = ! p . IsEmpty ( )
? ( n = = 0 ? false : n = = 1 ? true : org . fItalic )
: org . fItalic ;
}
else if ( cmd = = L " kt " )
{
m_kstart = ! p . IsEmpty ( )
? wcstol ( p , NULL , 10 ) * 10
: 0 ;
m_kend = m_kstart ;
}
else if ( cmd = = L " kf " | | cmd = = L " K " )
{
m_ktype = 1 ;
m_kstart = m_kend ;
m_kend + = ! p . IsEmpty ( )
? wcstol ( p , NULL , 10 ) * 10
: 1000 ;
}
else if ( cmd = = L " ko " )
{
m_ktype = 2 ;
m_kstart = m_kend ;
m_kend + = ! p . IsEmpty ( )
? wcstol ( p , NULL , 10 ) * 10
: 1000 ;
}
else if ( cmd = = L " k " )
{
m_ktype = 0 ;
m_kstart = m_kend ;
m_kend + = ! p . IsEmpty ( )
? wcstol ( p , NULL , 10 ) * 10
: 1000 ;
}
else if ( cmd = = L " move " ) / / { \ move ( x1 = param [ 0 ] , y1 = param [ 1 ] , x2 = param [ 2 ] , y2 = param [ 3 ] [ , t1 = t [ 0 ] , t2 = t [ 1 ] ] ) }
{
if ( ( params . GetCount ( ) = = 4 | | params . GetCount ( ) = = 6 ) & & ! sub - > m_effects [ EF_MOVE ] )
{
if ( Effect * e = new Effect )
{
e - > param [ 0 ] = ( int ) ( sub - > m_scalex * wcstod ( params [ 0 ] , NULL ) * 8 ) ;
e - > param [ 1 ] = ( int ) ( sub - > m_scaley * wcstod ( params [ 1 ] , NULL ) * 8 ) ;
e - > param [ 2 ] = ( int ) ( sub - > m_scalex * wcstod ( params [ 2 ] , NULL ) * 8 ) ;
e - > param [ 3 ] = ( int ) ( sub - > m_scaley * wcstod ( params [ 3 ] , NULL ) * 8 ) ;
e - > t [ 0 ] = e - > t [ 1 ] = - 1 ;
if ( params . GetCount ( ) = = 6 )
{
for ( int i = 0 ; i < 2 ; i + + )
e - > t [ i ] = wcstol ( params [ 4 + i ] , NULL , 10 ) ;
}
sub - > m_effects [ EF_MOVE ] = e ;
}
}
}
else if ( cmd = = L " org " ) / / { \ org ( x = param [ 0 ] , y = param [ 1 ] ) }
{
if ( params . GetCount ( ) = = 2 & & ! sub - > m_effects [ EF_ORG ] )
{
if ( Effect * e = new Effect )
{
e - > param [ 0 ] = ( int ) ( sub - > m_scalex * wcstod ( params [ 0 ] , NULL ) * 8 ) ;
e - > param [ 1 ] = ( int ) ( sub - > m_scaley * wcstod ( params [ 1 ] , NULL ) * 8 ) ;
sub - > m_effects [ EF_ORG ] = e ;
}
}
}
else if ( cmd = = L " pbo " )
{
m_polygonBaselineOffset = wcstol ( p , NULL , 10 ) ;
}
else if ( cmd = = L " pos " )
{
if ( params . GetCount ( ) = = 2 & & ! sub - > m_effects [ EF_MOVE ] )
{
if ( Effect * e = new Effect )
{
e - > param [ 0 ] = e - > param [ 2 ] = ( int ) ( sub - > m_scalex * wcstod ( params [ 0 ] , NULL ) * 8 ) ;
e - > param [ 1 ] = e - > param [ 3 ] = ( int ) ( sub - > m_scaley * wcstod ( params [ 1 ] , NULL ) * 8 ) ;
e - > t [ 0 ] = e - > t [ 1 ] = 0 ;
sub - > m_effects [ EF_MOVE ] = e ;
}
}
}
else if ( cmd = = L " p " )
{
int n = wcstol ( p , NULL , 10 ) ;
m_nPolygon = ( n < = 0 ? 0 : n ) ;
}
else if ( cmd = = L " q " )
{
int n = wcstol ( p , NULL , 10 ) ;
sub - > m_wrapStyle = ! p . IsEmpty ( ) & & ( 0 < = n & & n < = 3 )
? n
: m_defaultWrapStyle ;
}
else if ( cmd = = L " r " )
{
STSStyle * val ;
style = ( ! p . IsEmpty ( ) & & m_styles . Lookup ( CString ( p ) , val ) & & val ) ? * val : org ;
}
else if ( cmd = = L " shad " )
{
double n = CalcAnimation ( wcstod ( p , NULL ) , style . shadowDepth , fAnimate ) ;
style . shadowDepth = ! p . IsEmpty ( )
? ( n < 0 ? 0 : n )
: org . shadowDepth ;
}
else if ( cmd = = L " s " )
{
int n = wcstol ( p , NULL , 10 ) ;
style . fStrikeOut = ! p . IsEmpty ( )
? ( n = = 0 ? false : n = = 1 ? true : org . fStrikeOut )
: org . fStrikeOut ;
}
else if ( cmd = = L " t " ) // \t([<t1>,<t2>,][<accel>,]<style modifiers>)
{
p . Empty ( ) ;
m_animStart = m_animEnd = 0 ;
m_animAccel = 1 ;
if ( params . GetCount ( ) = = 1 )
{
p = params [ 0 ] ;
}
else if ( params . GetCount ( ) = = 2 )
{
m_animAccel = wcstod ( params [ 0 ] , NULL ) ;
p = params [ 1 ] ;
}
else if ( params . GetCount ( ) = = 3 )
{
m_animStart = ( int ) wcstod ( params [ 0 ] , NULL ) ;
m_animEnd = ( int ) wcstod ( params [ 1 ] , NULL ) ;
p = params [ 2 ] ;
}
else if ( params . GetCount ( ) = = 4 )
{
m_animStart = wcstol ( params [ 0 ] , NULL , 10 ) ;
m_animEnd = wcstol ( params [ 1 ] , NULL , 10 ) ;
m_animAccel = wcstod ( params [ 2 ] , NULL ) ;
p = params [ 3 ] ;
}
ParseSSATag ( sub , p , style , org , true ) ;
sub - > m_fAnimated = true ;
}
else if ( cmd = = L " u " )
{
int n = wcstol ( p , NULL , 10 ) ;
style . fUnderline = ! p . IsEmpty ( )
? ( n = = 0 ? false : n = = 1 ? true : org . fUnderline )
: org . fUnderline ;
}
}
// return(nUnrecognizedTags < nTags);
return ( true ) ; // there are ppl keeping coments inside {}, lets make them happy now
}
bool CRenderedTextSubtitle : : ParseHtmlTag ( CSubtitle * sub , CStringW str , STSStyle & style , STSStyle & org )
{
if ( str . Find ( L " !-- " ) = = 0 )
return ( true ) ;
bool fClosing = str [ 0 ] = = ' / ' ;
str . Trim ( L " / " ) ;
int i = str . Find ( ' ' ) ;
if ( i < 0 ) i = str . GetLength ( ) ;
CStringW tag = str . Left ( i ) . MakeLower ( ) ;
str = str . Mid ( i ) . Trim ( ) ;
CAtlArray < CStringW > attribs , params ;
while ( ( i = str . Find ( ' = ' ) ) > 0 )
{
attribs . Add ( str . Left ( i ) . Trim ( ) . MakeLower ( ) ) ;
str = str . Mid ( i + 1 ) ;
for ( i = 0 ; _istspace ( str [ i ] ) ; i + + ) ;
str = str . Mid ( i ) ;
if ( str [ 0 ] = = ' \" ' ) { str = str . Mid ( 1 ) ; i = str . Find ( ' \" ' ) ; }
else i = str . Find ( ' ' ) ;
if ( i < 0 ) i = str . GetLength ( ) ;
params . Add ( str . Left ( i ) . Trim ( ) . MakeLower ( ) ) ;
str = str . Mid ( i + 1 ) ;
}
if ( tag = = L " text " )
;
else if ( tag = = L " b " | | tag = = L " strong " )
style . fontWeight = ! fClosing ? FW_BOLD : org . fontWeight ;
else if ( tag = = L " i " | | tag = = L " em " )
style . fItalic = ! fClosing ? true : org . fItalic ;
else if ( tag = = L " u " )
style . fUnderline = ! fClosing ? true : org . fUnderline ;
else if ( tag = = L " s " | | tag = = L " strike " | | tag = = L " del " )
style . fStrikeOut = ! fClosing ? true : org . fStrikeOut ;
else if ( tag = = L " font " )
{
if ( ! fClosing )
{
for ( i = 0 ; i < attribs . GetCount ( ) ; i + + )
{
if ( params [ i ] . IsEmpty ( ) ) continue ;
int nColor = - 1 ;
if ( attribs [ i ] = = L " face " )
{
style . fontName = params [ i ] ;
}
else if ( attribs [ i ] = = L " size " )
{
if ( params [ i ] [ 0 ] = = ' + ' )
style . fontSize + = wcstol ( params [ i ] , NULL , 10 ) ;
else if ( params [ i ] [ 0 ] = = ' - ' )
style . fontSize - = wcstol ( params [ i ] , NULL , 10 ) ;
else
style . fontSize = wcstol ( params [ i ] , NULL , 10 ) ;
}
else if ( attribs [ i ] = = L " color " )
{
nColor = 0 ;
}
else if ( attribs [ i ] = = L " outline-color " )
{
nColor = 2 ;
}
else if ( attribs [ i ] = = L " outline-level " )
{
style . outlineWidth = wcstol ( params [ i ] , NULL , 10 ) ;
}
else if ( attribs [ i ] = = L " shadow-color " )
{
nColor = 3 ;
}
else if ( attribs [ i ] = = L " shadow-level " )
{
style . shadowDepth = wcstol ( params [ i ] , NULL , 10 ) ;
}
if ( nColor > = 0 & & nColor < 4 )
{
CString key = WToT ( params [ i ] ) . TrimLeft ( ' # ' ) ;
DWORD val ;
if ( g_colors . Lookup ( key , val ) )
style . colors [ nColor ] = val ;
else if ( ( style . colors [ nColor ] = _tcstol ( key , NULL , 16 ) ) = = 0 )
style . colors [ nColor ] = 0x00ffffff ; // default is white
style . colors [ nColor ] = ( ( style . colors [ nColor ] > > 16 ) & 0xff ) | ( ( style . colors [ nColor ] & 0xff ) < < 16 ) | ( style . colors [ nColor ] & 0x00ff00 ) ;
}
}
}
else
{
style . fontName = org . fontName ;
style . fontSize = org . fontSize ;
memcpy ( style . colors , org . colors , sizeof ( style . colors ) ) ;
}
}
else if ( tag = = L " k " & & attribs . GetCount ( ) = = 1 & & attribs [ 0 ] = = L " t " )
{
m_ktype = 1 ;
m_kstart = m_kend ;
m_kend + = wcstol ( params [ 0 ] , NULL , 10 ) ;
}
else
return ( false ) ;
return ( true ) ;
}
double CRenderedTextSubtitle : : CalcAnimation ( double dst , double src , bool fAnimate )
{
int s = m_animStart ? m_animStart : 0 ;
int e = m_animEnd ? m_animEnd : m_delay ;
if ( fabs ( dst - src ) > = 0.0001 & & fAnimate )
{
if ( m_time < s ) dst = src ;
else if ( s < = m_time & & m_time < e )
{
double t = pow ( 1.0 * ( m_time - s ) / ( e - s ) , m_animAccel ) ;
dst = ( 1 - t ) * src + t * dst ;
}
// else dst = dst;
}
return ( dst ) ;
}
CSubtitle * CRenderedTextSubtitle : : GetSubtitle ( int entry )
{
CSubtitle * sub ;
if ( m_subtitleCache . Lookup ( entry , sub ) )
{
if ( sub - > m_fAnimated ) { delete sub ; sub = NULL ; }
else return ( sub ) ;
}
sub = new CSubtitle ( ) ;
if ( ! sub ) return ( NULL ) ;
CStringW str = GetStrW ( entry , true ) ;
STSStyle stss , orgstss ;
GetStyle ( entry , stss ) ;
orgstss = stss ;
sub - > m_clip . SetRect ( 0 , 0 , m_size . cx > > 3 , m_size . cy > > 3 ) ;
sub - > m_scrAlignment = - stss . scrAlignment ;
sub - > m_wrapStyle = m_defaultWrapStyle ;
sub - > m_fAnimated = false ;
sub - > m_relativeTo = stss . relativeTo ;
sub - > m_scalex = m_dstScreenSize . cx > 0 ? 1.0 * ( stss . relativeTo = = 1 ? m_vidrect . Width ( ) : m_size . cx ) / ( m_dstScreenSize . cx * 8 ) : 1.0 ;
sub - > m_scaley = m_dstScreenSize . cy > 0 ? 1.0 * ( stss . relativeTo = = 1 ? m_vidrect . Height ( ) : m_size . cy ) / ( m_dstScreenSize . cy * 8 ) : 1.0 ;
m_animStart = m_animEnd = 0 ;
m_animAccel = 1 ;
m_ktype = m_kstart = m_kend = 0 ;
m_nPolygon = 0 ;
m_polygonBaselineOffset = 0 ;
ParseEffect ( sub , GetAt ( entry ) . effect ) ;
while ( ! str . IsEmpty ( ) )
{
bool fParsed = false ;
int i ;
if ( str [ 0 ] = = ' { ' & & ( i = str . Find ( L ' } ' ) ) > 0 )
{
if ( fParsed = ParseSSATag ( sub , str . Mid ( 1 , i - 1 ) , stss , orgstss ) )
str = str . Mid ( i + 1 ) ;
}
else if ( str [ 0 ] = = ' < ' & & ( i = str . Find ( L ' > ' ) ) > 0 )
{
if ( fParsed = ParseHtmlTag ( sub , str . Mid ( 1 , i - 1 ) , stss , orgstss ) )
str = str . Mid ( i + 1 ) ;
}
if ( fParsed )
{
i = str . FindOneOf ( L " {< " ) ;
if ( i < 0 ) i = str . GetLength ( ) ;
if ( i = = 0 ) continue ;
}
else
{
i = str . Mid ( 1 ) . FindOneOf ( L " {< " ) ;
if ( i < 0 ) i = str . GetLength ( ) - 1 ;
i + + ;
}
STSStyle tmp = stss ;
tmp . fontSize = sub - > m_scaley * tmp . fontSize * 64 ;
tmp . fontSpacing = sub - > m_scalex * tmp . fontSpacing * 64 ;
tmp . outlineWidth * = ( m_fScaledBAS ? ( ( sub - > m_scalex + sub - > m_scaley ) / 2 ) : 1 ) * 8 ;
tmp . shadowDepth * = ( m_fScaledBAS ? ( ( sub - > m_scalex + sub - > m_scaley ) / 2 ) : 1 ) * 8 ;
if ( m_nPolygon )
{
ParsePolygon ( sub , str . Left ( i ) , tmp ) ;
}
else
{
ParseString ( sub , str . Left ( i ) , tmp ) ;
}
str = str . Mid ( i ) ;
}
// just a "work-around" solution... in most cases nobody will want to use \org together with moving but without rotating the subs
if ( sub - > m_effects [ EF_ORG ] & & ( sub - > m_effects [ EF_MOVE ] | | sub - > m_effects [ EF_BANNER ] | | sub - > m_effects [ EF_SCROLL ] ) )
sub - > m_fAnimated = true ;
sub - > m_scrAlignment = abs ( sub - > m_scrAlignment ) ;
STSEntry stse = GetAt ( entry ) ;
CRect marginRect = stse . marginRect ;
if ( marginRect . left = = 0 ) marginRect . left = orgstss . marginRect . left ;
if ( marginRect . top = = 0 ) marginRect . top = orgstss . marginRect . top ;
if ( marginRect . right = = 0 ) marginRect . right = orgstss . marginRect . right ;
if ( marginRect . bottom = = 0 ) marginRect . bottom = orgstss . marginRect . bottom ;
marginRect . left = ( int ) ( sub - > m_scalex * marginRect . left * 8 ) ;
marginRect . top = ( int ) ( sub - > m_scaley * marginRect . top * 8 ) ;
marginRect . right = ( int ) ( sub - > m_scalex * marginRect . right * 8 ) ;
marginRect . bottom = ( int ) ( sub - > m_scaley * marginRect . bottom * 8 ) ;
if ( stss . relativeTo = = 1 )
{
marginRect . left + = m_vidrect . left ;
marginRect . top + = m_vidrect . top ;
marginRect . right + = m_size . cx - m_vidrect . right ;
marginRect . bottom + = m_size . cy - m_vidrect . bottom ;
}
sub - > CreateClippers ( m_size ) ;
sub - > MakeLines ( m_size , marginRect ) ;
m_subtitleCache [ entry ] = sub ;
return ( sub ) ;
}
//
STDMETHODIMP CRenderedTextSubtitle : : NonDelegatingQueryInterface ( REFIID riid , void * * ppv )
{
CheckPointer ( ppv , E_POINTER ) ;
* ppv = NULL ;
return
QI ( IPersist )
QI ( ISubStream )
QI ( ISubPicProvider )
__super : : NonDelegatingQueryInterface ( riid , ppv ) ;
}
// ISubPicProvider
STDMETHODIMP_ ( POSITION ) CRenderedTextSubtitle : : GetStartPosition ( REFERENCE_TIME rt , double fps )
{
int iSegment = - 1 ;
SearchSubs ( ( int ) ( rt / 10000 ) , fps , & iSegment , NULL ) ;
if ( iSegment < 0 ) iSegment = 0 ;
return ( GetNext ( ( POSITION ) iSegment ) ) ;
}
STDMETHODIMP_ ( POSITION ) CRenderedTextSubtitle : : GetNext ( POSITION pos )
{
int iSegment = ( int ) pos ;
const STSSegment * stss ;
while ( ( stss = GetSegment ( iSegment ) ) & & stss - > subs . GetCount ( ) = = 0 )
iSegment + + ;
return ( stss ? ( POSITION ) ( iSegment + 1 ) : NULL ) ;
}
STDMETHODIMP_ ( REFERENCE_TIME ) CRenderedTextSubtitle : : GetStart ( POSITION pos , double fps )
{
return ( 10000 i64 * TranslateSegmentStart ( ( int ) pos - 1 , fps ) ) ;
}
STDMETHODIMP_ ( REFERENCE_TIME ) CRenderedTextSubtitle : : GetStop ( POSITION pos , double fps )
{
return ( 10000 i64 * TranslateSegmentEnd ( ( int ) pos - 1 , fps ) ) ;
}
STDMETHODIMP_ ( bool ) CRenderedTextSubtitle : : IsAnimated ( POSITION pos )
{
// TODO
return ( true ) ;
}
struct LSub { int idx , layer , readorder ; } ;
static int lscomp ( const void * ls1 , const void * ls2 )
{
int ret = ( ( LSub * ) ls1 ) - > layer - ( ( LSub * ) ls2 ) - > layer ;
if ( ! ret ) ret = ( ( LSub * ) ls1 ) - > readorder - ( ( LSub * ) ls2 ) - > readorder ;
return ( ret ) ;
}
STDMETHODIMP CRenderedTextSubtitle : : Render ( SubPicDesc & spd , REFERENCE_TIME rt , double fps , RECT & bbox )
{
CRect bbox2 ( 0 , 0 , 0 , 0 ) ;
if ( m_size ! = CSize ( spd . w * 8 , spd . h * 8 ) | | m_vidrect ! = CRect ( spd . vidrect . left * 8 , spd . vidrect . top * 8 , spd . vidrect . right * 8 , spd . vidrect . bottom * 8 ) )
Init ( CSize ( spd . w , spd . h ) , spd . vidrect ) ;
int t = ( int ) ( rt / 10000 ) ;
int segment ;
const STSSegment * stss = SearchSubs ( t , fps , & segment ) ;
if ( ! stss ) return S_FALSE ;
// clear any cached subs not in the range of +/-30secs measured from the segment's bounds
{
POSITION pos = m_subtitleCache . GetStartPosition ( ) ;
while ( pos )
{
int key ;
CSubtitle * value ;
m_subtitleCache . GetNextAssoc ( pos , key , value ) ;
STSEntry & stse = GetAt ( key ) ;
if ( stse . end < = ( t - 30000 ) | | stse . start > ( t + 30000 ) )
{
delete value ;
m_subtitleCache . RemoveKey ( key ) ;
pos = m_subtitleCache . GetStartPosition ( ) ;
}
}
}
m_sla . AdvanceToSegment ( segment , stss - > subs ) ;
CAtlArray < LSub > subs ;
for ( int i = 0 , j = stss - > subs . GetCount ( ) ; i < j ; i + + )
{
LSub ls ;
ls . idx = stss - > subs [ i ] ;
ls . layer = GetAt ( stss - > subs [ i ] ) . layer ;
ls . readorder = GetAt ( stss - > subs [ i ] ) . readorder ;
subs . Add ( ls ) ;
}
qsort ( subs . GetData ( ) , subs . GetCount ( ) , sizeof ( LSub ) , lscomp ) ;
for ( int i = 0 , j = subs . GetCount ( ) ; i < j ; i + + )
{
int entry = subs [ i ] . idx ;
STSEntry stse = GetAt ( entry ) ;
{
int start = TranslateStart ( entry , fps ) ;
m_time = t - start ;
m_delay = TranslateEnd ( entry , fps ) - start ;
}
CSubtitle * s = GetSubtitle ( entry ) ;
if ( ! s ) continue ;
CRect clipRect = s - > m_clip ;
CRect r = s - > m_rect ;
CSize spaceNeeded = r . Size ( ) ;
// apply the effects
bool fPosOverride = false , fOrgOverride = false ;
int alpha = 0x00 ;
CPoint org2 ;
for ( int k = 0 ; k < EF_NUMBEROFEFFECTS ; k + + )
{
if ( ! s - > m_effects [ k ] ) continue ;
switch ( k )
{
case EF_MOVE : // {\move(x1=param[0], y1=param[1], x2=param[2], y2=param[3], t1=t[0], t2=t[1])}
{
CPoint p ;
CPoint p1 ( s - > m_effects [ k ] - > param [ 0 ] , s - > m_effects [ k ] - > param [ 1 ] ) ;
CPoint p2 ( s - > m_effects [ k ] - > param [ 2 ] , s - > m_effects [ k ] - > param [ 3 ] ) ;
int t1 = s - > m_effects [ k ] - > t [ 0 ] ;
int t2 = s - > m_effects [ k ] - > t [ 1 ] ;
if ( t2 < t1 ) { int t = t1 ; t1 = t2 ; t2 = t ; }
if ( t1 < = 0 & & t2 < = 0 ) { t1 = 0 ; t2 = m_delay ; }
if ( m_time < = t1 ) p = p1 ;
2007-08-26 17:44:15 +02:00
else if ( p1 = = p2 ) p = p1 ; // jfs: avoid rounding error problems sometimes causing subtitles with \pos to jump around a bit
2007-07-09 20:33:44 +02:00
else if ( t1 < m_time & & m_time < t2 )
{
double t = 1.0 * ( m_time - t1 ) / ( t2 - t1 ) ;
p . x = ( int ) ( ( 1 - t ) * p1 . x + t * p2 . x ) ;
p . y = ( int ) ( ( 1 - t ) * p1 . y + t * p2 . y ) ;
}
else p = p2 ;
r = CRect (
CPoint ( ( s - > m_scrAlignment % 3 ) = = 1 ? p . x : ( s - > m_scrAlignment % 3 ) = = 0 ? p . x - spaceNeeded . cx : p . x - ( spaceNeeded . cx + 1 ) / 2 ,
s - > m_scrAlignment < = 3 ? p . y - spaceNeeded . cy : s - > m_scrAlignment < = 6 ? p . y - ( spaceNeeded . cy + 1 ) / 2 : p . y ) ,
spaceNeeded ) ;
if ( s - > m_relativeTo = = 1 )
r . OffsetRect ( m_vidrect . TopLeft ( ) ) ;
fPosOverride = true ;
}
break ;
case EF_ORG : // {\org(x=param[0], y=param[1])}
{
org2 = CPoint ( s - > m_effects [ k ] - > param [ 0 ] , s - > m_effects [ k ] - > param [ 1 ] ) ;
fOrgOverride = true ;
}
break ;
case EF_FADE : // {\fade(a1=param[0], a2=param[1], a3=param[2], t1=t[0], t2=t[1], t3=t[2], t4=t[3]) or {\fad(t1=t[1], t2=t[2])
{
int t1 = s - > m_effects [ k ] - > t [ 0 ] ;
int t2 = s - > m_effects [ k ] - > t [ 1 ] ;
int t3 = s - > m_effects [ k ] - > t [ 2 ] ;
int t4 = s - > m_effects [ k ] - > t [ 3 ] ;
if ( t1 = = - 1 & & t4 = = - 1 ) { t1 = 0 ; t3 = m_delay - t3 ; t4 = m_delay ; }
if ( m_time < t1 ) alpha = s - > m_effects [ k ] - > param [ 0 ] ;
else if ( m_time > = t1 & & m_time < t2 )
{
double t = 1.0 * ( m_time - t1 ) / ( t2 - t1 ) ;
alpha = ( int ) ( s - > m_effects [ k ] - > param [ 0 ] * ( 1 - t ) + s - > m_effects [ k ] - > param [ 1 ] * t ) ;
}
else if ( m_time > = t2 & & m_time < t3 ) alpha = s - > m_effects [ k ] - > param [ 1 ] ;
else if ( m_time > = t3 & & m_time < t4 )
{
double t = 1.0 * ( m_time - t3 ) / ( t4 - t3 ) ;
alpha = ( int ) ( s - > m_effects [ k ] - > param [ 1 ] * ( 1 - t ) + s - > m_effects [ k ] - > param [ 2 ] * t ) ;
}
else if ( m_time > = t4 ) alpha = s - > m_effects [ k ] - > param [ 2 ] ;
}
break ;
case EF_BANNER : // Banner;delay=param[0][;leftoright=param[1];fadeawaywidth=param[2]]
{
int left = s - > m_relativeTo = = 1 ? m_vidrect . left : 0 ,
right = s - > m_relativeTo = = 1 ? m_vidrect . right : m_size . cx ;
r . left = ! ! s - > m_effects [ k ] - > param [ 1 ]
? ( left /*marginRect.left*/ - spaceNeeded . cx ) + ( int ) ( m_time * 8.0 / s - > m_effects [ k ] - > param [ 0 ] )
: ( right /*- marginRect.right*/ ) - ( int ) ( m_time * 8.0 / s - > m_effects [ k ] - > param [ 0 ] ) ;
r . right = r . left + spaceNeeded . cx ;
clipRect & = CRect ( left > > 3 , clipRect . top , right > > 3 , clipRect . bottom ) ;
fPosOverride = true ;
}
break ;
case EF_SCROLL : // Scroll up/down(toptobottom=param[3]);top=param[0];bottom=param[1];delay=param[2][;fadeawayheight=param[4]]
{
r . top = ! ! s - > m_effects [ k ] - > param [ 3 ]
? s - > m_effects [ k ] - > param [ 0 ] + ( int ) ( m_time * 8.0 / s - > m_effects [ k ] - > param [ 2 ] ) - spaceNeeded . cy
: s - > m_effects [ k ] - > param [ 1 ] - ( int ) ( m_time * 8.0 / s - > m_effects [ k ] - > param [ 2 ] ) ;
r . bottom = r . top + spaceNeeded . cy ;
CRect cr ( 0 , ( s - > m_effects [ k ] - > param [ 0 ] + 4 ) > > 3 , spd . w , ( s - > m_effects [ k ] - > param [ 1 ] + 4 ) > > 3 ) ;
if ( s - > m_relativeTo = = 1 )
r . top + = m_vidrect . top ,
r . bottom + = m_vidrect . top ,
cr . top + = m_vidrect . top > > 3 ,
cr . bottom + = m_vidrect . top > > 3 ;
clipRect & = cr ;
fPosOverride = true ;
}
break ;
default :
break ;
}
}
if ( ! fPosOverride & & ! fOrgOverride & & ! s - > m_fAnimated )
r = m_sla . AllocRect ( s , segment , entry , stse . layer , m_collisions ) ;
CPoint org ;
org . x = ( s - > m_scrAlignment % 3 ) = = 1 ? r . left : ( s - > m_scrAlignment % 3 ) = = 2 ? r . CenterPoint ( ) . x : r . right ;
org . y = s - > m_scrAlignment < = 3 ? r . bottom : s - > m_scrAlignment < = 6 ? r . CenterPoint ( ) . y : r . top ;
if ( ! fOrgOverride ) org2 = org ;
BYTE * pAlphaMask = s - > m_pClipper ? s - > m_pClipper - > m_pAlphaMask : NULL ;
CPoint p , p2 ( 0 , r . top ) ;
POSITION pos ;
p = p2 ;
pos = s - > GetHeadPosition ( ) ;
while ( pos )
{
CLine * l = s - > GetNext ( pos ) ;
p . x = ( s - > m_scrAlignment % 3 ) = = 1 ? org . x
: ( s - > m_scrAlignment % 3 ) = = 0 ? org . x - l - > m_width
: org . x - ( l - > m_width / 2 ) ;
bbox2 | = l - > PaintShadow ( spd , clipRect , pAlphaMask , p , org2 , m_time , alpha ) ;
p . y + = l - > m_ascent + l - > m_descent ;
}
p = p2 ;
pos = s - > GetHeadPosition ( ) ;
while ( pos )
{
CLine * l = s - > GetNext ( pos ) ;
p . x = ( s - > m_scrAlignment % 3 ) = = 1 ? org . x
: ( s - > m_scrAlignment % 3 ) = = 0 ? org . x - l - > m_width
: org . x - ( l - > m_width / 2 ) ;
bbox2 | = l - > PaintOutline ( spd , clipRect , pAlphaMask , p , org2 , m_time , alpha ) ;
p . y + = l - > m_ascent + l - > m_descent ;
}
p = p2 ;
pos = s - > GetHeadPosition ( ) ;
while ( pos )
{
CLine * l = s - > GetNext ( pos ) ;
p . x = ( s - > m_scrAlignment % 3 ) = = 1 ? org . x
: ( s - > m_scrAlignment % 3 ) = = 0 ? org . x - l - > m_width
: org . x - ( l - > m_width / 2 ) ;
bbox2 | = l - > PaintBody ( spd , clipRect , pAlphaMask , p , org2 , m_time , alpha ) ;
p . y + = l - > m_ascent + l - > m_descent ;
}
}
bbox = bbox2 ;
return ( subs . GetCount ( ) & & ! bbox2 . IsRectEmpty ( ) ) ? S_OK : S_FALSE ;
}
// IPersist
STDMETHODIMP CRenderedTextSubtitle : : GetClassID ( CLSID * pClassID )
{
return pClassID ? * pClassID = __uuidof ( this ) , S_OK : E_POINTER ;
}
// ISubStream
STDMETHODIMP_ ( int ) CRenderedTextSubtitle : : GetStreamCount ( )
{
return ( 1 ) ;
}
STDMETHODIMP CRenderedTextSubtitle : : GetStreamInfo ( int iStream , WCHAR * * ppName , LCID * pLCID )
{
if ( iStream ! = 0 ) return E_INVALIDARG ;
if ( ppName )
{
if ( ! ( * ppName = ( WCHAR * ) CoTaskMemAlloc ( ( m_name . GetLength ( ) + 1 ) * sizeof ( WCHAR ) ) ) )
return E_OUTOFMEMORY ;
wcscpy ( * ppName , CStringW ( m_name ) ) ;
}
if ( pLCID )
{
* pLCID = 0 ; // TODO
}
return S_OK ;
}
STDMETHODIMP_ ( int ) CRenderedTextSubtitle : : GetStream ( )
{
return ( 0 ) ;
}
STDMETHODIMP CRenderedTextSubtitle : : SetStream ( int iStream )
{
return iStream = = 0 ? S_OK : E_FAIL ;
}
STDMETHODIMP CRenderedTextSubtitle : : Reload ( )
{
CFileStatus s ;
if ( ! CFile : : GetStatus ( m_path , s ) ) return E_FAIL ;
return ! m_path . IsEmpty ( ) & & Open ( m_path , DEFAULT_CHARSET ) ? S_OK : E_FAIL ;
}