2 * Copyright (C) 2003-2006 Gabest
3 * http://www.gabest.org
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
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
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GNU Make; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
26 #include "cache_manager.h"
27 #include "../subpic/color_conv_table.h"
28 #include "subpixel_position_controler.h"
30 // WARNING: this isn't very thread safe, use only one RTS a time.
32 static int g_hDC_refcnt
= 0;
34 enum XY_MSP_SUBTYPE
{XY_AYUV
, XY_AUYV
};
35 static inline DWORD
rgb2yuv(DWORD argb
, XY_MSP_SUBTYPE type
)
37 const ColorConvTable
* color_conv_table
= ColorConvTable::GetDefaultColorConvTable();
39 int r
= (argb
& 0x00ff0000) >> 16;
40 int g
= (argb
& 0x0000ff00) >> 8;
41 int b
= (argb
& 0x000000ff);
42 int y
= (color_conv_table
->c2y_cyb
* b
+ color_conv_table
->c2y_cyg
* g
+ color_conv_table
->c2y_cyr
* r
+ 0x108000) >> 16;
43 int scaled_y
= (y
-16) * color_conv_table
->cy_cy
;
44 int u
= ((((b
<<16) - scaled_y
) >> 10) * color_conv_table
->c2y_cu
+ 0x800000 + 0x8000) >> 16;
45 int v
= ((((r
<<16) - scaled_y
) >> 10) * color_conv_table
->c2y_cv
+ 0x800000 + 0x8000) >> 16;
46 DbgLog((LOG_TRACE
, 5, TEXT("argb=%x r=%d %x g=%d %x b=%d %x y=%d %x u=%d %x v=%d %x"), argb
, r
, r
, g
, g
, b
, b
, y
, y
, u
, u
, v
, v
));
48 u
= 255 - (255-u
)*(u
<256);
50 v
= 255 - (255-v
)*(v
<256);
51 DbgLog((LOG_TRACE
, 5, TEXT("u=%x v=%x"), u
, v
));
53 axxv
= (argb
& 0xff000000) | (y
<<16) | (u
<<8) | v
;
55 axxv
= (argb
& 0xff000000) | (y
<<8) | (u
<<16) | v
;
56 DbgLog((LOG_TRACE
, 5, TEXT("axxv=%x"), axxv
));
60 static long revcolor(long c
)
62 return ((c
&0xff0000)>>16) + (c
&0xff00) + ((c
&0xff)<<16);
65 // Skip all leading whitespace
66 inline CStringW::PCXSTR
SkipWhiteSpaceLeft(const CStringW
& str
)
68 CStringW::PCXSTR psz
= str
.GetString();
70 while( iswspace( *psz
) )
77 // Skip all trailing whitespace
78 inline CStringW::PCXSTR
SkipWhiteSpaceRight(const CStringW
& str
)
80 CStringW::PCXSTR psz
= str
.GetString();
81 CStringW::PCXSTR pszLast
= psz
+ str
.GetLength() - 1;
82 bool first_white
= false;
83 while( iswspace( *pszLast
) )
92 // Skip all leading whitespace
93 inline CStringW::PCXSTR
SkipWhiteSpaceLeft(CStringW::PCXSTR start
, CStringW::PCXSTR end
)
95 while( start
!=end
&& iswspace( *start
) )
102 // Skip all trailing whitespace, first char must NOT be white space
103 inline CStringW::PCXSTR
FastSkipWhiteSpaceRight(CStringW::PCXSTR start
, CStringW::PCXSTR end
)
105 while( iswspace( *--end
) );
109 inline CStringW::PCXSTR
FindChar(CStringW::PCXSTR start
, CStringW::PCXSTR end
, WCHAR c
)
111 while( start
!=end
&& *start
!=c
)
118 //////////////////////////////////////////////////////////////////////////////////////////////
122 CMyFont::CMyFont(const STSStyleBase
& style
)
125 memset(&lf
, 0, sizeof(lf
));
127 lf
.lfHeight
= (LONG
)(style
.fontSize
+0.5);
128 lf
.lfOutPrecision
= OUT_TT_PRECIS
;
129 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
130 lf
.lfQuality
= ANTIALIASED_QUALITY
;
131 lf
.lfPitchAndFamily
= DEFAULT_PITCH
|FF_DONTCARE
;
132 if(!CreateFontIndirect(&lf
))
134 _tcscpy(lf
.lfFaceName
, _T("Arial"));
135 CreateFontIndirect(&lf
);
137 HFONT hOldFont
= SelectFont(g_hDC
, *this);
139 GetTextMetrics(g_hDC
, &tm
);
140 m_ascent
= ((tm
.tmAscent
+ 4) >> 3);
141 m_descent
= ((tm
.tmDescent
+ 4) >> 3);
142 SelectFont(g_hDC
, hOldFont
);
147 CWord::CWord(const FwSTSStyle
& style
, const CStringW
& str
, int ktype
, int kstart
, int kend
)
148 : m_style(style
), m_str(str
)
149 , m_width(0), m_ascent(0), m_descent(0)
150 , m_ktype(ktype
), m_kstart(kstart
), m_kend(kend
)
151 , m_fLineBreak(false), m_fWhiteSpaceChar(false)
152 //, m_pOpaqueBox(NULL)
156 m_fWhiteSpaceChar
= m_fLineBreak
= true;
161 CWord::CWord( const CWord
& src
)
164 m_fWhiteSpaceChar
= src
.m_fWhiteSpaceChar
;
165 m_fLineBreak
= src
.m_fLineBreak
;
166 m_style
= src
.m_style
;
167 m_pOpaqueBox
= src
.m_pOpaqueBox
;//allow since it is shared_ptr
168 m_ktype
= src
.m_ktype
;
169 m_kstart
= src
.m_kstart
;
171 m_width
= src
.m_width
;
172 m_ascent
= src
.m_ascent
;
173 m_descent
= src
.m_descent
;
178 //if(m_pOpaqueBox) delete m_pOpaqueBox;
181 bool CWord::Append(const SharedPtrCWord
& w
)
183 if(!(m_style
== w
->m_style
)
184 || m_fLineBreak
|| w
->m_fLineBreak
185 || w
->m_kstart
!= w
->m_kend
|| m_ktype
!= w
->m_ktype
) return(false);
186 m_fWhiteSpaceChar
= m_fWhiteSpaceChar
&& w
->m_fWhiteSpaceChar
;
188 m_width
+= w
->m_width
;
192 void CWord::Paint( SharedPtrCWord word
, const CPoint
& p
, const CPoint
& org
, OverlayList
* overlay_list
)
194 if(!word
->m_str
|| overlay_list
==NULL
) return;
196 CPoint trans_org
= org
- p
;
197 bool need_transform
= word
->NeedTransform();
204 if( SubpixelPositionControler::GetGlobalControler().UseBilinearShift() )
206 CPoint
psub_true( (p
.x
&SubpixelPositionControler::EIGHT_X_EIGHT_MASK
), (p
.y
&SubpixelPositionControler::EIGHT_X_EIGHT_MASK
) );
207 OverlayKey
sub_key(*word
, psub_true
, trans_org
);
209 OverlayMruCache
* overlay_cache
= CacheManager::GetSubpixelVarianceCache();
211 OverlayMruCache::hashed_cache_const_iterator iter
= overlay_cache
->hash_find(sub_key
);
212 if(iter
!=overlay_cache
->hash_end())
214 overlay_list
->overlay
= iter
->overlay
;
215 overlay_cache
->update_cache( *iter
);
218 if( !overlay_list
->overlay
)
220 CPoint psub
= SubpixelPositionControler::GetGlobalControler().GetSubpixel(p
);
221 OverlayKey
overlay_key(*word
, psub
, trans_org
);
222 OverlayMruCache
* overlay_cache
= CacheManager::GetOverlayMruCache();
223 OverlayMruCache::hashed_cache_const_iterator iter
= overlay_cache
->hash_find(overlay_key
);
224 if(iter
==overlay_cache
->hash_end())
226 word
->DoPaint(psub
, trans_org
, &(overlay_list
->overlay
), overlay_key
);
227 OverlayMruItem
item(overlay_key
, overlay_list
->overlay
);
228 overlay_cache
->update_cache(item
);
232 overlay_list
->overlay
= iter
->overlay
;
233 overlay_cache
->update_cache( *iter
);
235 if( SubpixelPositionControler::GetGlobalControler().UseBilinearShift()
236 && (psub
.x
!=(p
.x
&SubpixelPositionControler::EIGHT_X_EIGHT_MASK
)
237 || psub
.y
!=(p
.y
&SubpixelPositionControler::EIGHT_X_EIGHT_MASK
)) )
239 overlay_list
->overlay
.reset(overlay_list
->overlay
->GetSubpixelVariance((p
.x
&SubpixelPositionControler::EIGHT_X_EIGHT_MASK
) - psub
.x
,
240 (p
.y
&SubpixelPositionControler::EIGHT_X_EIGHT_MASK
) - psub
.y
));
241 CPoint
psub_true( (p
.x
&SubpixelPositionControler::EIGHT_X_EIGHT_MASK
), (p
.y
&SubpixelPositionControler::EIGHT_X_EIGHT_MASK
) );
242 OverlayKey
sub_key(*word
, psub_true
, trans_org
);
243 OverlayMruCache
* overlay_cache
= CacheManager::GetSubpixelVarianceCache();
244 OverlayMruItem
item(sub_key
, overlay_list
->overlay
);
245 overlay_cache
->update_cache(item
);
249 if(word
->m_style
.get().borderStyle
== 1)
251 if(!word
->CreateOpaqueBox()) return;
252 overlay_list
->next
= new OverlayList();
253 Paint(word
->m_pOpaqueBox
, p
, org
, overlay_list
->next
);
257 void CWord::DoPaint(const CPoint
& psub
, const CPoint
& trans_org
, SharedPtrOverlay
* overlay
, const OverlayKey
& key
)
259 //overlay->reset(new Overlay());
261 OverlayNoBlurMruCache
* overlay_no_blur_cache
= CacheManager::GetOverlayNoBlurMruCache();
262 OverlayNoBlurMruCache::hashed_cache_const_iterator iter
= overlay_no_blur_cache
->hash_find(key
);
264 SharedPtrOverlay raterize_result
;
265 if(iter
==overlay_no_blur_cache
->hash_end())
267 raterize_result
.reset(new Overlay());
269 SharedPtrConstScanLineData scan_line_data
;
270 ScanLineDataMruCache
* scan_line_data_cache
= CacheManager::GetScanLineDataMruCache();
271 ScanLineDataMruCache::hashed_cache_const_iterator iter
= scan_line_data_cache
->hash_find(key
);
272 if(iter
==scan_line_data_cache
->hash_end())
274 //get outline path, if not cached, create it and cache a copy, else copy from cache
275 SharedPtrPathData
path_data(new PathData());
276 PathDataMruCache
* path_data_cache
= CacheManager::GetPathDataMruCache();
277 PathDataMruCache::hashed_cache_const_iterator iter
= path_data_cache
->hash_find(key
);
278 if(iter
==path_data_cache
->hash_end())
280 if(!CreatePath(path_data
)) return;
282 SharedPtrPathData
data(new PathData());
283 *data
= *path_data
;//important! copy not ref
284 PathDataMruItem
item(key
, data
);
285 path_data_cache
->update_cache(item
);
289 *path_data
= *(iter
->path_data
); //important! copy not ref
290 path_data_cache
->update_cache( *iter
);
293 bool need_transform
= NeedTransform();
295 Transform(path_data
, CPoint(trans_org
.x
*8, trans_org
.y
*8));
297 SharedPtrScanLineData
tmp(new ScanLineData());
298 if(!tmp
->ScanConvert(path_data
)) return;
299 if(m_style
.get().borderStyle
== 0 && (m_style
.get().outlineWidthX
+m_style
.get().outlineWidthY
> 0))
301 if(!tmp
->CreateWidenedRegion((int)(m_style
.get().outlineWidthX
+0.5), (int)(m_style
.get().outlineWidthY
+0.5))) return;
303 else if(m_style
.get().borderStyle
== 1)
305 if(!CreateOpaqueBox()) return;
308 ScanLineDataMruItem
item(key
, tmp
);
309 scan_line_data_cache
->update_cache(item
);
310 scan_line_data
= tmp
;
314 scan_line_data
= iter
->scan_line_data
;
315 scan_line_data_cache
->update_cache( *iter
);
317 if(!Rasterizer::Rasterize(*scan_line_data
, psub
.x
, psub
.y
, raterize_result
)) return;
319 OverlayNoBlurMruItem
item(key
, raterize_result
);
320 overlay_no_blur_cache
->update_cache(item
);
324 raterize_result
= iter
->overlay
;
325 overlay_no_blur_cache
->update_cache( *iter
);
327 if( m_style
.get().fBlur
>0 || m_style
.get().fGaussianBlur
>0.000001 )
329 overlay
->reset(new Overlay());
330 if(!Rasterizer::Blur(*raterize_result
, m_style
.get().fBlur
, m_style
.get().fGaussianBlur
, *overlay
))
332 *overlay
= raterize_result
;
337 *overlay
= raterize_result
;
341 bool CWord::NeedTransform()
343 return (fabs(m_style
.get().fontScaleX
- 100) > 0.000001) ||
344 (fabs(m_style
.get().fontScaleY
- 100) > 0.000001) ||
345 (fabs(m_style
.get().fontAngleX
) > 0.000001) ||
346 (fabs(m_style
.get().fontAngleY
) > 0.000001) ||
347 (fabs(m_style
.get().fontAngleZ
) > 0.000001) ||
348 (fabs(m_style
.get().fontShiftX
) > 0.000001) ||
349 (fabs(m_style
.get().fontShiftY
) > 0.000001);
352 void CWord::Transform(SharedPtrPathData path_data
, const CPoint
& org
)
355 bool fSSE2
= !!(g_cpuid
.m_flags
& CCpuID::sse2
);
357 if(fSSE2
) { // SSE code
358 Transform_SSE2(path_data
, org
);
360 Transform_C(path_data
, org
);
363 void CWord::Transform_C(const SharedPtrPathData
& path_data
, const CPoint
&org
)
365 double scalex
= m_style
.get().fontScaleX
/100;
366 double scaley
= m_style
.get().fontScaleY
/100;
368 double caz
= cos((3.1415/180)*m_style
.get().fontAngleZ
);
369 double saz
= sin((3.1415/180)*m_style
.get().fontAngleZ
);
370 double cax
= cos((3.1415/180)*m_style
.get().fontAngleX
);
371 double sax
= sin((3.1415/180)*m_style
.get().fontAngleX
);
372 double cay
= cos((3.1415/180)*m_style
.get().fontAngleY
);
373 double say
= sin((3.1415/180)*m_style
.get().fontAngleY
);
376 // patch m003. random text points
377 double xrnd
= m_style
.get().mod_rand
.X
*100;
378 double yrnd
= m_style
.get().mod_rand
.Y
*100;
379 double zrnd
= m_style
.get().mod_rand
.Z
*100;
381 srand(m_style
.get().mod_rand
.Seed
);
383 // patch m008. distort
385 double dst1x
,dst1y
,dst2x
,dst2y
,dst3x
,dst3y
;
386 int minx
= INT_MAX
, miny
= INT_MAX
, maxx
= -INT_MAX
, maxy
= -INT_MAX
;
388 bool is_dist
= m_style
.get().mod_distort
.enabled
;
390 for(int i
= 0; i
< path_data
->mPathPoints
; i
++) {
391 if(minx
> path_data
->mpPathPoints
[i
].x
) {
392 minx
= path_data
->mpPathPoints
[i
].x
;
394 if(miny
> path_data
->mpPathPoints
[i
].y
) {
395 miny
= path_data
->mpPathPoints
[i
].y
;
397 if(maxx
< path_data
->mpPathPoints
[i
].x
) {
398 maxx
= path_data
->mpPathPoints
[i
].x
;
400 if(maxy
< path_data
->mpPathPoints
[i
].y
) {
401 maxy
= path_data
->mpPathPoints
[i
].y
;
405 xsz
= max(maxx
- minx
, 0);
406 ysz
= max(maxy
- miny
, 0);
408 dst1x
= m_style
.get().mod_distort
.pointsx
[0];
409 dst1y
= m_style
.get().mod_distort
.pointsy
[0];
410 dst2x
= m_style
.get().mod_distort
.pointsx
[1];
411 dst2y
= m_style
.get().mod_distort
.pointsy
[1];
412 dst3x
= m_style
.get().mod_distort
.pointsx
[2];
413 dst3y
= m_style
.get().mod_distort
.pointsy
[2];
417 for (int i
= 0; i
< path_data
->mPathPoints
; i
++) {
418 double x
, y
, z
, xx
, yy
, zz
;
420 x
= path_data
->mpPathPoints
[i
].x
;
421 y
= path_data
->mpPathPoints
[i
].y
;
423 // patch m002. Z-coord
424 z
= m_style
.get().mod_z
;
431 x
= minx
+(0 + (dst1x
- 0)*u
+ (dst3x
-0)*v
+(0+dst2x
-dst1x
-dst3x
)*u
*v
)*xsz
;
432 y
= miny
+(0 + (dst1y
- 0)*u
+ (dst3y
-0)*v
+(0+dst2y
-dst1y
-dst3y
)*u
*v
)*ysz
;
433 //P = P0 + (P1 - P0)u + (P3 - P0)v + (P0 + P2 - P1 - P3)uv
436 // patch m003. random text points
437 x
= xrnd
> 0 ? (xrnd
- rand() % (int)(xrnd
* 2 + 1)) / 100.0 + x
: x
;
438 y
= yrnd
> 0 ? (yrnd
- rand() % (int)(yrnd
* 2 + 1)) / 100.0 + y
: y
;
439 z
= zrnd
> 0 ? (zrnd
- rand() % (int)(zrnd
* 2 + 1)) / 100.0 + z
: z
;
444 x
= scalex
* (x
+ m_style
.get().fontShiftX
* y
) - org
.x
;
445 y
= scaley
* (y
+ m_style
.get().fontShiftY
* _x
) - org
.y
;
448 yy
= -(x
*saz
- y
*caz
);
459 zz
= max(zz
, -19000);
461 x
= (xx
* 20000) / (zz
+ 20000);
462 y
= (yy
* 20000) / (zz
+ 20000);
464 path_data
->mpPathPoints
[i
].x
= (LONG
)(x
+ org
.x
+ 0.5);
465 path_data
->mpPathPoints
[i
].y
= (LONG
)(y
+ org
.y
+ 0.5);
469 void CWord::Transform_SSE2(const SharedPtrPathData
& path_data
, const CPoint
&org
)
471 // __m128 union data type currently not supported with Intel C++ Compiler, so just call C version
476 // speed up ~1.5-1.7x
477 double scalex
= m_style
.get().fontScaleX
/100;
478 double scaley
= m_style
.get().fontScaleY
/100;
480 double caz
= cos((3.1415/180)*m_style
.get().fontAngleZ
);
481 double saz
= sin((3.1415/180)*m_style
.get().fontAngleZ
);
482 double cax
= cos((3.1415/180)*m_style
.get().fontAngleX
);
483 double sax
= sin((3.1415/180)*m_style
.get().fontAngleX
);
484 double cay
= cos((3.1415/180)*m_style
.get().fontAngleY
);
485 double say
= sin((3.1415/180)*m_style
.get().fontAngleY
);
487 __m128 __xshift
= _mm_set_ps1(m_style
.get().fontShiftX
);
488 __m128 __yshift
= _mm_set_ps1(m_style
.get().fontShiftY
);
490 __m128 __xorg
= _mm_set_ps1(org
.x
);
491 __m128 __yorg
= _mm_set_ps1(org
.y
);
493 __m128 __xscale
= _mm_set_ps1(scalex
);
494 __m128 __yscale
= _mm_set_ps1(scaley
);
497 // patch m003. random text points
498 double xrnd
= m_style
.get().mod_rand
.X
*100;
499 double yrnd
= m_style
.get().mod_rand
.Y
*100;
500 double zrnd
= m_style
.get().mod_rand
.Z
*100;
502 srand(m_style
.get().mod_rand
.Seed
);
504 __m128 __xsz
= _mm_setzero_ps();
505 __m128 __ysz
= _mm_setzero_ps();
507 __m128 __dst1x
, __dst1y
, __dst213x
, __dst213y
, __dst3x
, __dst3y
;
510 __m128 __minx
= _mm_set_ps(INT_MAX
, INT_MAX
, 0, 0);
511 __m128 __max
= _mm_set_ps(-INT_MAX
, -INT_MAX
, 1, 1);
513 bool is_dist
= m_style
.get().mod_distort
.enabled
;
515 for(int i
= 0; i
< path_data
->mPathPoints
; i
++) {
516 __m128 __point
= _mm_set_ps(path_data
->mpPathPoints
[i
].x
, path_data
->mpPathPoints
[i
].y
, 0, 0);
517 __minx
= _mm_min_ps(__minx
, __point
);
518 __max
= _mm_max_ps(__max
, __point
);
521 __m128 __zero
= _mm_setzero_ps();
522 __max
= _mm_sub_ps(__max
, __minx
); // xsz, ysz, 1, 1
523 __max
= _mm_max_ps(__max
, __zero
);
525 __xsz
= _mm_shuffle_ps(__max
, __max
, _MM_SHUFFLE(3,3,3,3));
526 __ysz
= _mm_shuffle_ps(__max
, __max
, _MM_SHUFFLE(2,2,2,2));
528 __miny
= _mm_shuffle_ps(__minx
, __minx
, _MM_SHUFFLE(2,2,2,2));
529 __minx
= _mm_shuffle_ps(__minx
, __minx
, _MM_SHUFFLE(3,3,3,3));
531 __dst1x
= _mm_set_ps1(m_style
.get().mod_distort
.pointsx
[0]);
532 __dst1y
= _mm_set_ps1(m_style
.get().mod_distort
.pointsy
[0]);
533 __dst3x
= _mm_set_ps1(m_style
.get().mod_distort
.pointsx
[2]);
534 __dst3y
= _mm_set_ps1(m_style
.get().mod_distort
.pointsy
[2]);
535 __dst213x
= _mm_set_ps1(m_style
.get().mod_distort
.pointsx
[1]); // 2 - 1 - 3
536 __dst213x
= _mm_sub_ps(__dst213x
, __dst1x
);
537 __dst213x
= _mm_sub_ps(__dst213x
, __dst3x
);
539 __dst213y
= _mm_set_ps1(m_style
.get().mod_distort
.pointsy
[1]);
540 __dst213x
= _mm_sub_ps(__dst213y
, __dst1y
);
541 __dst213x
= _mm_sub_ps(__dst213y
, __dst3y
);
545 __m128 __caz
= _mm_set_ps1(caz
);
546 __m128 __saz
= _mm_set_ps1(saz
);
547 __m128 __cax
= _mm_set_ps1(cax
);
548 __m128 __sax
= _mm_set_ps1(sax
);
549 __m128 __cay
= _mm_set_ps1(cay
);
550 __m128 __say
= _mm_set_ps1(say
);
552 // this can be paralleled for openmp
553 int mPathPointsD4
= path_data
->mPathPoints
/ 4;
554 int mPathPointsM4
= path_data
->mPathPoints
% 4;
556 for(ptrdiff_t i
= 0; i
< mPathPointsD4
+ 1; i
++) {
557 POINT
* const temp_points
= path_data
->mpPathPoints
+ 4 * i
;
559 __m128 __pointx
, __pointy
;
560 // we can't use load .-.
561 if(i
!= mPathPointsD4
) {
562 __pointx
= _mm_set_ps(temp_points
[0].x
, temp_points
[1].x
, temp_points
[2].x
, temp_points
[3].x
);
563 __pointy
= _mm_set_ps(temp_points
[0].y
, temp_points
[1].y
, temp_points
[2].y
, temp_points
[3].y
);
564 } else { // last cycle
565 switch(mPathPointsM4
) {
570 __pointx
= _mm_set_ps(temp_points
[0].x
, 0, 0, 0);
571 __pointy
= _mm_set_ps(temp_points
[0].y
, 0, 0, 0);
574 __pointx
= _mm_set_ps(temp_points
[0].x
, temp_points
[1].x
, 0, 0);
575 __pointy
= _mm_set_ps(temp_points
[0].y
, temp_points
[1].y
, 0, 0);
578 __pointx
= _mm_set_ps(temp_points
[0].x
, temp_points
[1].x
, temp_points
[2].x
, 0);
579 __pointy
= _mm_set_ps(temp_points
[0].y
, temp_points
[1].y
, temp_points
[2].y
, 0);
585 __m128 __pointz
= _mm_set_ps1(m_style
.get().mod_z
);
589 //P = P0 + (P1 - P0)u + (P3 - P0)v + (P0 + P2 - P1 - P3)uv
590 __m128 __u
= _mm_sub_ps(__pointx
, __minx
);
591 __m128 __v
= _mm_sub_ps(__pointy
, __miny
);
592 __m128 __1_xsz
= _mm_rcp_ps(__xsz
);
593 __m128 __1_ysz
= _mm_rcp_ps(__ysz
);
594 __u
= _mm_mul_ps(__u
, __1_xsz
);
595 __v
= _mm_mul_ps(__v
, __1_ysz
);
598 __pointx
= _mm_mul_ps(__dst213x
, __u
);
599 __pointx
= _mm_mul_ps(__pointx
, __v
);
601 __m128 __tmpx
= _mm_mul_ps(__dst3x
, __v
);
602 __pointx
= _mm_add_ps(__pointx
, __tmpx
);
603 __tmpx
= _mm_mul_ps(__dst1x
, __u
);
604 __pointx
= _mm_add_ps(__pointx
, __tmpx
);
606 __pointx
= _mm_mul_ps(__pointx
, __xsz
);
607 __pointx
= _mm_add_ps(__pointx
, __minx
);
610 __pointy
= _mm_mul_ps(__dst213y
, __u
);
611 __pointy
= _mm_mul_ps(__pointy
, __v
);
613 __m128 __tmpy
= _mm_mul_ps(__dst3y
, __v
);
614 __pointy
= _mm_add_ps(__pointy
, __tmpy
);
615 __tmpy
= _mm_mul_ps(__dst1y
, __u
);
616 __pointy
= _mm_add_ps(__pointy
, __tmpy
);
618 __pointy
= _mm_mul_ps(__pointy
, __ysz
);
619 __pointy
= _mm_add_ps(__pointy
, __miny
);
623 if(xrnd
!=0 || yrnd
!=0 || zrnd
!=0) {
624 __declspec(align(16)) float rx
[4], ry
[4], rz
[4];
625 for(int k
=0; k
<4; k
++) {
626 rx
[k
] = xrnd
> 0 ? (xrnd
- rand() % (int)(xrnd
* 2 + 1)) : 0;
627 ry
[k
] = yrnd
> 0 ? (yrnd
- rand() % (int)(yrnd
* 2 + 1)) : 0;
628 rz
[k
] = zrnd
> 0 ? (zrnd
- rand() % (int)(zrnd
* 2 + 1)) : 0;
630 __m128 __001
= _mm_set_ps1(0.01f
);
633 __m128 __rx
= _mm_load_ps(rx
);
634 __rx
= _mm_mul_ps(__rx
, __001
);
635 __pointx
= _mm_add_ps(__pointx
, __rx
);
639 __m128 __ry
= _mm_load_ps(ry
);
640 __ry
= _mm_mul_ps(__ry
, __001
);
641 __pointy
= _mm_add_ps(__pointy
, __ry
);
645 __m128 __rz
= _mm_load_ps(rz
);
646 __rz
= _mm_mul_ps(__rz
, __001
);
647 __pointz
= _mm_add_ps(__pointz
, __rz
);
651 __m128 __pointz
= _mm_set_ps1(0);
656 if(m_style
.get().fontShiftX
!=0) {
657 __tmpx
= _mm_mul_ps(__xshift
, __pointy
);
658 __tmpx
= _mm_add_ps(__tmpx
, __pointx
);
662 __tmpx
= _mm_mul_ps(__tmpx
, __xscale
);
663 __tmpx
= _mm_sub_ps(__tmpx
, __xorg
);
666 if(m_style
.get().fontShiftY
!=0) {
667 __tmpy
= _mm_mul_ps(__yshift
, __pointx
);
668 __tmpy
= _mm_add_ps(__tmpy
, __pointy
);
672 __tmpy
= _mm_mul_ps(__tmpy
, __yscale
);
673 __tmpy
= _mm_sub_ps(__tmpy
, __yorg
);
676 __m128 __xx
= _mm_mul_ps(__tmpx
, __caz
);
677 __m128 __yy
= _mm_mul_ps(__tmpy
, __saz
);
678 __pointx
= _mm_add_ps(__xx
, __yy
);
679 __xx
= _mm_mul_ps(__tmpx
, __saz
);
680 __yy
= _mm_mul_ps(__tmpy
, __caz
);
681 __pointy
= _mm_sub_ps(__yy
, __xx
);
683 __m128 __zz
= _mm_mul_ps(__pointz
, __sax
);
684 __yy
= _mm_mul_ps(__pointy
, __cax
);
685 __pointy
= _mm_add_ps(__yy
, __zz
);
686 __zz
= _mm_mul_ps(__pointz
, __cax
);
687 __yy
= _mm_mul_ps(__pointy
, __sax
);
688 __pointz
= _mm_sub_ps(__zz
, __yy
);
690 __xx
= _mm_mul_ps(__pointx
, __cay
);
691 __zz
= _mm_mul_ps(__pointz
, __say
);
692 __pointx
= _mm_add_ps(__xx
, __zz
);
693 __xx
= _mm_mul_ps(__pointx
, __say
);
694 __zz
= _mm_mul_ps(__pointz
, __cay
);
695 __pointz
= _mm_sub_ps(__xx
, __zz
);
697 __zz
= _mm_set_ps1(-19000);
698 __pointz
= _mm_max_ps(__pointz
, __zz
);
700 __m128 __20000
= _mm_set_ps1(20000);
701 __zz
= _mm_add_ps(__pointz
, __20000
);
702 __zz
= _mm_rcp_ps(__zz
);
704 __pointx
= _mm_mul_ps(__pointx
, __20000
);
705 __pointx
= _mm_mul_ps(__pointx
, __zz
);
707 __pointy
= _mm_mul_ps(__pointy
, __20000
);
708 __pointy
= _mm_mul_ps(__pointy
, __zz
);
710 __pointx
= _mm_add_ps(__pointx
, __xorg
);
711 __pointy
= _mm_add_ps(__pointy
, __yorg
);
713 __m128 __05
= _mm_set_ps1(0.5);
715 __pointx
= _mm_add_ps(__pointx
, __05
);
716 __pointy
= _mm_add_ps(__pointy
, __05
);
718 if(i
== mPathPointsD4
) { // last cycle
719 for(int k
=0; k
<mPathPointsM4
; k
++) {
720 temp_points
[k
].x
= static_cast<LONG
>(__pointx
.m128_f32
[3-k
]);
721 temp_points
[k
].y
= static_cast<LONG
>(__pointy
.m128_f32
[3-k
]);
724 for(int k
=0; k
<4; k
++) {
725 temp_points
[k
].x
= static_cast<LONG
>(__pointx
.m128_f32
[3-k
]);
726 temp_points
[k
].y
= static_cast<LONG
>(__pointy
.m128_f32
[3-k
]);
733 bool CWord::CreateOpaqueBox()
735 if(m_pOpaqueBox
) return(true);
736 STSStyle style
= m_style
.get();
737 style
.borderStyle
= 0;
738 style
.outlineWidthX
= style
.outlineWidthY
= 0;
739 style
.colors
[0] = m_style
.get().colors
[2];
740 style
.alpha
[0] = m_style
.get().alpha
[2];
741 int w
= (int)(m_style
.get().outlineWidthX
+ 0.5);
742 int h
= (int)(m_style
.get().outlineWidthY
+ 0.5);
744 str
.Format(L
"m %d %d l %d %d %d %d %d %d",
747 m_width
+w
, m_ascent
+m_descent
+h
,
748 -w
, m_ascent
+m_descent
+h
);
749 m_pOpaqueBox
.reset( new CPolygon(FwSTSStyle(style
), str
, 0, 0, 0, 1.0/8, 1.0/8, 0) );
750 return(!!m_pOpaqueBox
);
755 CText::CText(const FwSTSStyle
& style
, const CStringW
& str
, int ktype
, int kstart
, int kend
)
756 : CWord(style
, str
, ktype
, kstart
, kend
)
760 m_fWhiteSpaceChar
= true;
762 FwCMyFont
font(m_style
);
763 m_ascent
= (int)(m_style
.get().fontScaleY
/100*font
.get().m_ascent
);
764 m_descent
= (int)(m_style
.get().fontScaleY
/100*font
.get().m_descent
);
766 HFONT hOldFont
= SelectFont(g_hDC
, font
.get());
767 if(m_style
.get().fontSpacing
|| (long)GetVersion() < 0)
769 bool bFirstPath
= true;
770 for(LPCWSTR s
= m_str
; *s
; s
++)
773 if(!GetTextExtentPoint32W(g_hDC
, s
, 1, &extent
)) {SelectFont(g_hDC
, hOldFont
); ASSERT(0); return;}
774 m_width
+= extent
.cx
+ (int)m_style
.get().fontSpacing
;
776 // m_width -= (int)m_style.get().fontSpacing; // TODO: subtract only at the end of the line
781 if(!GetTextExtentPoint32W(g_hDC
, m_str
, wcslen(m_str
), &extent
)) {SelectFont(g_hDC
, hOldFont
); ASSERT(0); return;}
782 m_width
+= extent
.cx
;
784 m_width
= (int)(m_style
.get().fontScaleX
/100*m_width
+ 4) >> 3;
785 SelectFont(g_hDC
, hOldFont
);
788 CText::CText( const CText
& src
):CWord(src
)
790 m_width
= src
.m_width
;
793 SharedPtrCWord
CText::Copy()
795 SharedPtrCWord
result(new CText(*this));
799 bool CText::Append(const SharedPtrCWord
& w
)
801 return (w
&& CWord::Append(w
));
804 bool CText::CreatePath(const SharedPtrPathData
& path_data
)
806 FwCMyFont
font(m_style
);
807 HFONT hOldFont
= SelectFont(g_hDC
, font
.get());
809 if(m_style
.get().fontSpacing
|| (long)GetVersion() < 0)
811 bool bFirstPath
= true;
812 for(LPCWSTR s
= m_str
; *s
; s
++)
815 if(!GetTextExtentPoint32W(g_hDC
, s
, 1, &extent
)) {SelectFont(g_hDC
, hOldFont
); ASSERT(0); return(false);}
816 path_data
->PartialBeginPath(g_hDC
, bFirstPath
);
818 TextOutW(g_hDC
, 0, 0, s
, 1);
819 path_data
->PartialEndPath(g_hDC
, width
, 0);
820 width
+= extent
.cx
+ (int)m_style
.get().fontSpacing
;
826 if(!GetTextExtentPoint32W(g_hDC
, m_str
, m_str
.GetLength(), &extent
)) {SelectFont(g_hDC
, hOldFont
); ASSERT(0); return(false);}
827 path_data
->BeginPath(g_hDC
);
828 TextOutW(g_hDC
, 0, 0, m_str
, m_str
.GetLength());
829 path_data
->EndPath(g_hDC
);
831 SelectFont(g_hDC
, hOldFont
);
837 CPolygon::CPolygon(const FwSTSStyle
& style
, const CStringW
& str
, int ktype
, int kstart
, int kend
, double scalex
, double scaley
, int baseline
)
838 : CWord(style
, str
, ktype
, kstart
, kend
)
839 , m_scalex(scalex
), m_scaley(scaley
), m_baseline(baseline
)
844 CPolygon::CPolygon(CPolygon
& src
) : CWord(src
)
846 m_scalex
= src
.m_scalex
;
847 m_scaley
= src
.m_scaley
;
848 m_baseline
= src
.m_baseline
;
849 m_width
= src
.m_width
;
850 m_ascent
= src
.m_ascent
;
851 m_descent
= src
.m_descent
;
852 m_pathTypesOrg
.Copy(src
.m_pathTypesOrg
);
853 m_pathPointsOrg
.Copy(src
.m_pathPointsOrg
);
855 CPolygon::~CPolygon()
859 SharedPtrCWord
CPolygon::Copy()
861 SharedPtrCWord
result(DNew
CPolygon(*this));
865 bool CPolygon::Append(const SharedPtrCWord
& w
)
871 bool CPolygon::GetLONG(CStringW
& str
, LONG
& ret
)
873 LPWSTR s
= (LPWSTR
)(LPCWSTR
)str
, e
= s
;
874 ret
= wcstol(str
, &e
, 10);
875 str
= str
.Mid(e
- s
);
879 bool CPolygon::GetPOINT(CStringW
& str
, POINT
& ret
)
881 return(GetLONG(str
, ret
.x
) && GetLONG(str
, ret
.y
));
884 bool CPolygon::ParseStr()
886 if(m_pathTypesOrg
.GetCount() > 0) return(true);
888 int j
, lastsplinestart
= -1, firstmoveto
= -1, lastmoveto
= -1;
889 CStringW str
= m_str
;
890 str
.SpanIncluding(L
"mnlbspc 0123456789");
891 str
.Replace(L
"m", L
"*m");
892 str
.Replace(L
"n", L
"*n");
893 str
.Replace(L
"l", L
"*l");
894 str
.Replace(L
"b", L
"*b");
895 str
.Replace(L
"s", L
"*s");
896 str
.Replace(L
"p", L
"*p");
897 str
.Replace(L
"c", L
"*c");
899 for(CStringW s
= str
.Tokenize(L
"*", k
); !s
.IsEmpty(); s
= str
.Tokenize(L
"*", k
))
902 s
.TrimLeft(L
"mnlbspc ");
906 lastmoveto
= m_pathTypesOrg
.GetCount();
907 if(firstmoveto
== -1) firstmoveto
= lastmoveto
;
908 while(GetPOINT(s
, p
)) {m_pathTypesOrg
.Add(PT_MOVETO
); m_pathPointsOrg
.Add(p
);}
911 while(GetPOINT(s
, p
)) {m_pathTypesOrg
.Add(PT_MOVETONC
); m_pathPointsOrg
.Add(p
);}
914 while(GetPOINT(s
, p
)) {m_pathTypesOrg
.Add(PT_LINETO
); m_pathPointsOrg
.Add(p
);}
917 j
= m_pathTypesOrg
.GetCount();
918 while(GetPOINT(s
, p
)) {m_pathTypesOrg
.Add(PT_BEZIERTO
); m_pathPointsOrg
.Add(p
); j
++;}
919 j
= m_pathTypesOrg
.GetCount() - ((m_pathTypesOrg
.GetCount()-j
)%3);
920 m_pathTypesOrg
.SetCount(j
);
921 m_pathPointsOrg
.SetCount(j
);
925 j
= lastsplinestart
= m_pathTypesOrg
.GetCount();
927 while(i
-- && GetPOINT(s
, p
)) {m_pathTypesOrg
.Add(PT_BSPLINETO
); m_pathPointsOrg
.Add(p
); j
++;}
928 if(m_pathTypesOrg
.GetCount()-lastsplinestart
< 3) {m_pathTypesOrg
.SetCount(lastsplinestart
); m_pathPointsOrg
.SetCount(lastsplinestart
); lastsplinestart
= -1;}
932 while(GetPOINT(s
, p
)) {m_pathTypesOrg
.Add(PT_BSPLINEPATCHTO
); m_pathPointsOrg
.Add(p
); j
++;}
935 if(lastsplinestart
> 0)
937 m_pathTypesOrg
.Add(PT_BSPLINEPATCHTO
);
938 m_pathTypesOrg
.Add(PT_BSPLINEPATCHTO
);
939 m_pathTypesOrg
.Add(PT_BSPLINEPATCHTO
);
940 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)
941 m_pathPointsOrg
.Add(p
);
942 p
= m_pathPointsOrg
[lastsplinestart
];
943 m_pathPointsOrg
.Add(p
);
944 p
= m_pathPointsOrg
[lastsplinestart
+1];
945 m_pathPointsOrg
.Add(p
);
946 lastsplinestart
= -1;
957 while(*str && *str != 'm' && *str != 'n' && *str != 'l' && *str != 'b' && *str != 's' && *str != 'p' && *str != 'c') str++;
964 lastmoveto = m_pathTypesOrg.GetCount();
965 if(firstmoveto == -1) firstmoveto = lastmoveto;
966 while(GetPOINT(str, p)) {m_pathTypesOrg.Add(PT_MOVETO); m_pathPointsOrg.Add(p);}
969 while(GetPOINT(str, p)) {m_pathTypesOrg.Add(PT_MOVETONC); m_pathPointsOrg.Add(p);}
972 while(GetPOINT(str, p)) {m_pathTypesOrg.Add(PT_LINETO); m_pathPointsOrg.Add(p);}
975 j = m_pathTypesOrg.GetCount();
976 while(GetPOINT(str, p)) {m_pathTypesOrg.Add(PT_BEZIERTO); m_pathPointsOrg.Add(p); j++;}
977 j = m_pathTypesOrg.GetCount() - ((m_pathTypesOrg.GetCount()-j)%3);
978 m_pathTypesOrg.SetCount(j); m_pathPointsOrg.SetCount(j);
981 j = lastsplinestart = m_pathTypesOrg.GetCount();
983 while(i-- && GetPOINT(str, p)) {m_pathTypesOrg.Add(PT_BSPLINETO); m_pathPointsOrg.Add(p); j++;}
984 if(m_pathTypesOrg.GetCount()-lastsplinestart < 3) {m_pathTypesOrg.SetCount(lastsplinestart); m_pathPointsOrg.SetCount(lastsplinestart); lastsplinestart = -1;}
987 while(GetPOINT(str, p)) {m_pathTypesOrg.Add(PT_BSPLINEPATCHTO); m_pathPointsOrg.Add(p); j++;}
990 if(lastsplinestart > 0)
992 m_pathTypesOrg.Add(PT_BSPLINEPATCHTO);
993 m_pathTypesOrg.Add(PT_BSPLINEPATCHTO);
994 m_pathTypesOrg.Add(PT_BSPLINEPATCHTO);
995 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)
996 m_pathPointsOrg.Add(p);
997 p = m_pathPointsOrg[lastsplinestart];
998 m_pathPointsOrg.Add(p);
999 p = m_pathPointsOrg[lastsplinestart+1];
1000 m_pathPointsOrg.Add(p);
1001 lastsplinestart = -1;
1008 if(firstmoveto > 0) break;
1011 if(lastmoveto
== -1 || firstmoveto
> 0)
1013 m_pathTypesOrg
.RemoveAll();
1014 m_pathPointsOrg
.RemoveAll();
1017 int minx
= INT_MAX
, miny
= INT_MAX
, maxx
= -INT_MAX
, maxy
= -INT_MAX
;
1018 for(size_t i
= 0; i
< m_pathTypesOrg
.GetCount(); i
++)
1020 m_pathPointsOrg
[i
].x
= (int)(64 * m_scalex
* m_pathPointsOrg
[i
].x
);
1021 m_pathPointsOrg
[i
].y
= (int)(64 * m_scaley
* m_pathPointsOrg
[i
].y
);
1022 if(minx
> m_pathPointsOrg
[i
].x
) minx
= m_pathPointsOrg
[i
].x
;
1023 if(miny
> m_pathPointsOrg
[i
].y
) miny
= m_pathPointsOrg
[i
].y
;
1024 if(maxx
< m_pathPointsOrg
[i
].x
) maxx
= m_pathPointsOrg
[i
].x
;
1025 if(maxy
< m_pathPointsOrg
[i
].y
) maxy
= m_pathPointsOrg
[i
].y
;
1027 m_width
= max(maxx
- minx
, 0);
1028 m_ascent
= max(maxy
- miny
, 0);
1029 int baseline
= (int)(64 * m_scaley
* m_baseline
);
1030 m_descent
= baseline
;
1031 m_ascent
-= baseline
;
1032 m_width
= ((int)(m_style
.get().fontScaleX
/100 * m_width
) + 4) >> 3;
1033 m_ascent
= ((int)(m_style
.get().fontScaleY
/100 * m_ascent
) + 4) >> 3;
1034 m_descent
= ((int)(m_style
.get().fontScaleY
/100 * m_descent
) + 4) >> 3;
1038 bool CPolygon::CreatePath(const SharedPtrPathData
& path_data
)
1040 int len
= m_pathTypesOrg
.GetCount();
1041 if(len
== 0) return(false);
1042 if(path_data
->mPathPoints
!= len
)
1044 path_data
->mpPathTypes
= (BYTE
*)realloc(path_data
->mpPathTypes
, len
*sizeof(BYTE
));
1045 path_data
->mpPathPoints
= (POINT
*)realloc(path_data
->mpPathPoints
, len
*sizeof(POINT
));
1046 if(!path_data
->mpPathTypes
|| !path_data
->mpPathPoints
) return(false);
1047 path_data
->mPathPoints
= len
;
1049 memcpy(path_data
->mpPathTypes
, m_pathTypesOrg
.GetData(), len
*sizeof(BYTE
));
1050 memcpy(path_data
->mpPathPoints
, m_pathPointsOrg
.GetData(), len
*sizeof(POINT
));
1056 CClipper::CClipper(CStringW str
, CSize size
, double scalex
, double scaley
, bool inverse
)
1057 : m_polygon( new CPolygon(FwSTSStyle(), str
, 0, 0, 0, scalex
, scaley
, 0) )
1059 m_size
.cx
= m_size
.cy
= 0;
1060 //m_pAlphaMask = NULL;
1061 if(size
.cx
< 0 || size
.cy
< 0)
1063 m_pAlphaMask
.reset(new BYTE
[size
.cx
*size
.cy
]);
1067 m_inverse
= inverse
;
1068 memset( m_pAlphaMask
.get(), 0, size
.cx
*size
.cy
);
1069 OverlayList overlay_list
;
1070 CWord::Paint( m_polygon
, CPoint(0, 0), CPoint(0, 0), &overlay_list
);
1071 int w
= overlay_list
.overlay
->mOverlayWidth
, h
= overlay_list
.overlay
->mOverlayHeight
;
1072 int x
= (overlay_list
.overlay
->mOffsetX
+4)>>3, y
= (overlay_list
.overlay
->mOffsetY
+4)>>3;
1074 if(x
< 0) {xo
= -x
; w
-= -x
; x
= 0;}
1075 if(y
< 0) {yo
= -y
; h
-= -y
; y
= 0;}
1076 if(x
+w
> m_size
.cx
) w
= m_size
.cx
-x
;
1077 if(y
+h
> m_size
.cy
) h
= m_size
.cy
-y
;
1078 if(w
<= 0 || h
<= 0) return;
1079 const BYTE
* src
= overlay_list
.overlay
->mpOverlayBuffer
.body
+ (overlay_list
.overlay
->mOverlayPitch
* yo
+ xo
);
1080 BYTE
* dst
= m_pAlphaMask
.get() + m_size
.cx
* y
+ x
;
1083 //for(int wt=0; wt<w; ++wt)
1084 // dst[wt] = src[wt];
1085 memcpy(dst
, src
, w
);
1086 src
+= overlay_list
.overlay
->mOverlayPitch
;
1091 BYTE
* dst
= m_pAlphaMask
.get();
1092 for(int i
= size
.cx
*size
.cy
; i
>0; --i
, ++dst
)
1093 *dst
= 0x40 - *dst
; // mask is 6 bit
1097 CClipper::~CClipper()
1099 m_pAlphaMask
.reset(NULL
);
1106 //POSITION pos = GetHeadPosition();
1107 //while(pos) delete GetNext(pos);
1110 void CLine::Compact()
1112 POSITION pos
= GetHeadPosition();
1115 SharedPtrCWord w
= GetNext(pos
);
1116 if(!w
->m_fWhiteSpaceChar
) break;
1117 m_width
-= w
->m_width
;
1121 pos
= GetTailPosition();
1124 SharedPtrCWord w
= GetPrev(pos
);
1125 if(!w
->m_fWhiteSpaceChar
) break;
1126 m_width
-= w
->m_width
;
1130 if(IsEmpty()) return;
1132 l
.AddTailList(this);
1134 SharedPtrCWord last
;
1135 pos
= l
.GetHeadPosition();
1138 SharedPtrCWord w
= l
.GetNext(pos
);
1139 if(!last
|| !last
->Append(w
))
1140 AddTail(last
= w
->Copy());
1142 m_ascent
= m_descent
= m_borderX
= m_borderY
= 0;
1143 pos
= GetHeadPosition();
1146 SharedPtrCWord w
= GetNext(pos
);
1147 if(m_ascent
< w
->m_ascent
) m_ascent
= w
->m_ascent
;
1148 if(m_descent
< w
->m_descent
) m_descent
= w
->m_descent
;
1149 if(m_borderX
< w
->m_style
.get().outlineWidthX
) m_borderX
= (int)(w
->m_style
.get().outlineWidthX
+0.5);
1150 if(m_borderY
< w
->m_style
.get().outlineWidthY
) m_borderY
= (int)(w
->m_style
.get().outlineWidthY
+0.5);
1154 CRect
CLine::PaintShadow(CompositeDrawItemList
* output
, SubPicDesc
& spd
, CRect
& clipRect
, SharedArrayByte pAlphaMask
, CPoint p
, CPoint org
, int time
, int alpha
)
1156 CRect
bbox(0, 0, 0, 0);
1157 POSITION pos
= GetHeadPosition();
1158 POSITION outputPos
= output
->GetHeadPosition();
1161 SharedPtrCWord w
= GetNext(pos
);
1162 CompositeDrawItem
& outputItem
= output
->GetNext(outputPos
);
1164 if(w
->m_fLineBreak
) return(bbox
); // should not happen since this class is just a line of text without any breaks
1165 if(w
->m_style
.get().shadowDepthX
!= 0 || w
->m_style
.get().shadowDepthY
!= 0)
1167 int x
= p
.x
+ (int)(w
->m_style
.get().shadowDepthX
+0.5);
1168 int y
= p
.y
+ m_ascent
- w
->m_ascent
+ (int)(w
->m_style
.get().shadowDepthY
+0.5);
1169 DWORD a
= 0xff - w
->m_style
.get().alpha
[3];
1170 if(alpha
> 0) a
= MulDiv(a
, 0xff - alpha
, 0xff);
1171 COLORREF shadow
= revcolor(w
->m_style
.get().colors
[3]) | (a
<<24);
1172 DWORD sw
[6] = {shadow
, -1};
1174 if(spd
.type
== MSP_AUYV
)
1176 sw
[0] =rgb2yuv(sw
[0], XY_AUYV
);
1178 else if(spd
.type
== MSP_AYUV
|| spd
.type
== MSP_AY11
)
1180 sw
[0] =rgb2yuv(sw
[0], XY_AYUV
);
1182 OverlayList overlay_list
;
1183 CWord::Paint(w
, CPoint(x
, y
), org
, &overlay_list
);
1184 if(w
->m_style
.get().borderStyle
== 0)
1186 outputItem
.shadow
.reset(
1187 Rasterizer::CreateDrawItem(spd
, overlay_list
.overlay
, clipRect
, pAlphaMask
, x
, y
, sw
,
1188 w
->m_ktype
> 0 || w
->m_style
.get().alpha
[0] < 0xff,
1189 (w
->m_style
.get().outlineWidthX
+w
->m_style
.get().outlineWidthY
> 0) && !(w
->m_ktype
== 2 && time
< w
->m_kstart
))
1191 bbox
|= Rasterizer::DryDraw(spd
, *outputItem
.shadow
);
1193 else if(w
->m_style
.get().borderStyle
== 1 && w
->m_pOpaqueBox
)
1195 outputItem
.shadow
.reset(
1196 Rasterizer::CreateDrawItem(spd
, overlay_list
.next
->overlay
, clipRect
, pAlphaMask
, x
, y
, sw
, true, false)
1198 bbox
|= Rasterizer::DryDraw(spd
, *outputItem
.shadow
);
1206 CRect
CLine::PaintOutline(CompositeDrawItemList
* output
, SubPicDesc
& spd
, CRect
& clipRect
, SharedArrayByte pAlphaMask
, CPoint p
, CPoint org
, int time
, int alpha
)
1208 CRect
bbox(0, 0, 0, 0);
1209 POSITION pos
= GetHeadPosition();
1210 POSITION outputPos
= output
->GetHeadPosition();
1213 SharedPtrCWord w
= GetNext(pos
);
1214 CompositeDrawItem
& outputItem
= output
->GetNext(outputPos
);
1215 if(w
->m_fLineBreak
) return(bbox
); // should not happen since this class is just a line of text without any breaks
1216 if(w
->m_style
.get().outlineWidthX
+w
->m_style
.get().outlineWidthY
> 0 && !(w
->m_ktype
== 2 && time
< w
->m_kstart
))
1219 int y
= p
.y
+ m_ascent
- w
->m_ascent
;
1220 DWORD aoutline
= w
->m_style
.get().alpha
[2];
1221 if(alpha
> 0) aoutline
+= MulDiv(alpha
, 0xff - w
->m_style
.get().alpha
[2], 0xff);
1222 COLORREF outline
= revcolor(w
->m_style
.get().colors
[2]) | ((0xff-aoutline
)<<24);
1223 DWORD sw
[6] = {outline
, -1};
1225 if(spd
.type
== MSP_AUYV
)
1227 sw
[0] =rgb2yuv(sw
[0], XY_AUYV
);
1229 else if(spd
.type
== MSP_AYUV
|| spd
.type
== MSP_AY11
)
1231 sw
[0] =rgb2yuv(sw
[0], XY_AYUV
);
1233 OverlayList overlay_list
;
1234 CWord::Paint(w
, CPoint(x
, y
), org
, &overlay_list
);
1235 if(w
->m_style
.get().borderStyle
== 0)
1237 outputItem
.outline
.reset(
1238 Rasterizer::CreateDrawItem(spd
, overlay_list
.overlay
, clipRect
, pAlphaMask
, x
, y
, sw
, !w
->m_style
.get().alpha
[0] && !w
->m_style
.get().alpha
[1] && !alpha
, true)
1240 bbox
|= Rasterizer::DryDraw(spd
, *outputItem
.outline
);
1242 else if(w
->m_style
.get().borderStyle
== 1 && w
->m_pOpaqueBox
)
1244 outputItem
.outline
.reset(
1245 Rasterizer::CreateDrawItem(spd
, overlay_list
.next
->overlay
, clipRect
, pAlphaMask
, x
, y
, sw
, true, false)
1247 bbox
|= Rasterizer::DryDraw(spd
, *outputItem
.outline
);
1255 CRect
CLine::PaintBody(CompositeDrawItemList
* output
, SubPicDesc
& spd
, CRect
& clipRect
, SharedArrayByte pAlphaMask
, CPoint p
, CPoint org
, int time
, int alpha
)
1257 CRect
bbox(0, 0, 0, 0);
1258 POSITION pos
= GetHeadPosition();
1259 POSITION outputPos
= output
->GetHeadPosition();
1262 SharedPtrCWord w
= GetNext(pos
);
1263 CompositeDrawItem
& outputItem
= output
->GetNext(outputPos
);
1264 if(w
->m_fLineBreak
) return(bbox
); // should not happen since this class is just a line of text without any breaks
1266 int y
= p
.y
+ m_ascent
- w
->m_ascent
;
1268 DWORD aprimary
= w
->m_style
.get().alpha
[0];
1269 if(alpha
> 0) aprimary
+= MulDiv(alpha
, 0xff - w
->m_style
.get().alpha
[0], 0xff);
1270 COLORREF primary
= revcolor(w
->m_style
.get().colors
[0]) | ((0xff-aprimary
)<<24);
1271 DWORD asecondary
= w
->m_style
.get().alpha
[1];
1272 if(alpha
> 0) asecondary
+= MulDiv(alpha
, 0xff - w
->m_style
.get().alpha
[1], 0xff);
1273 COLORREF secondary
= revcolor(w
->m_style
.get().colors
[1]) | ((0xff-asecondary
)<<24);
1274 DWORD sw
[6] = {primary
, 0, secondary
};
1277 if(w
->m_ktype
== 0 || w
->m_ktype
== 2)
1279 t
= time
< w
->m_kstart
? 0 : 1;
1281 else if(w
->m_ktype
== 1)
1283 if(time
< w
->m_kstart
) t
= 0;
1284 else if(time
< w
->m_kend
)
1286 t
= 1.0 * (time
- w
->m_kstart
) / (w
->m_kend
- w
->m_kstart
);
1287 double angle
= fmod(w
->m_style
.get().fontAngleZ
, 360.0);
1288 if(angle
> 90 && angle
< 270)
1291 COLORREF tmp
= sw
[0];
1302 sw
[3] = (int)(w
->m_style
.get().outlineWidthX
+ t
*w
->m_width
) >> 3;
1306 if(spd
.type
== MSP_AUYV
)
1308 sw
[0] =rgb2yuv(sw
[0], XY_AUYV
);
1309 sw
[2] =rgb2yuv(sw
[2], XY_AUYV
);
1310 sw
[4] =rgb2yuv(sw
[4], XY_AUYV
);
1312 else if(spd
.type
== MSP_AYUV
|| spd
.type
== MSP_AY11
)
1314 sw
[0] =rgb2yuv(sw
[0], XY_AYUV
);
1315 sw
[2] =rgb2yuv(sw
[2], XY_AYUV
);
1316 sw
[4] =rgb2yuv(sw
[4], XY_AYUV
);
1318 OverlayList overlay_list
;
1319 CWord::Paint(w
, CPoint(x
, y
), org
, &overlay_list
);
1320 outputItem
.body
.reset(
1321 Rasterizer::CreateDrawItem(spd
, overlay_list
.overlay
, clipRect
, pAlphaMask
, x
, y
, sw
, true, false)
1323 bbox
|= Rasterizer::DryDraw(spd
, *outputItem
.body
);
1329 void CLine::AddWord2Tail( SharedPtrCWord words
)
1331 __super::AddTail(words
);
1334 bool CLine::IsEmpty()
1336 return __super::IsEmpty();
1339 int CLine::GetWordCount()
1347 CSubtitle::CSubtitle()
1349 memset(m_effects
, 0, sizeof(Effect
*)*EF_NUMBEROFEFFECTS
);
1351 m_clipInverse
= false;
1352 m_scalex
= m_scaley
= 1;
1353 m_fAnimated2
= false;
1356 CSubtitle::~CSubtitle()
1361 void CSubtitle::Empty()
1363 POSITION pos
= GetHeadPosition();
1364 while(pos
) delete GetNext(pos
);
1365 // pos = m_words.GetHeadPosition();
1366 // while(pos) delete m_words.GetNext(pos);
1367 for(int i
= 0; i
< EF_NUMBEROFEFFECTS
; i
++) {if(m_effects
[i
]) delete m_effects
[i
];}
1368 memset(m_effects
, 0, sizeof(Effect
*)*EF_NUMBEROFEFFECTS
);
1369 if(m_pClipper
) delete m_pClipper
;
1373 int CSubtitle::GetFullWidth()
1376 POSITION pos
= m_words
.GetHeadPosition();
1377 while(pos
) width
+= m_words
.GetNext(pos
)->m_width
;
1381 int CSubtitle::GetFullLineWidth(POSITION pos
)
1386 SharedPtrCWord w
= m_words
.GetNext(pos
);
1387 if(w
->m_fLineBreak
) break;
1388 width
+= w
->m_width
;
1393 int CSubtitle::GetWrapWidth(POSITION pos
, int maxwidth
)
1395 if(m_wrapStyle
== 0 || m_wrapStyle
== 3)
1399 // int fullwidth = GetFullWidth();
1400 int fullwidth
= GetFullLineWidth(pos
);
1401 int minwidth
= fullwidth
/ ((abs(fullwidth
) / maxwidth
) + 1);
1402 int width
= 0, wordwidth
= 0;
1403 while(pos
&& width
< minwidth
)
1405 SharedPtrCWord w
= m_words
.GetNext(pos
);
1406 wordwidth
= w
->m_width
;
1407 if(abs(width
+ wordwidth
) < abs(maxwidth
)) width
+= wordwidth
;
1410 if(m_wrapStyle
== 3 && pos
) maxwidth
-= wordwidth
;
1413 else if(m_wrapStyle
== 1)
1415 // maxwidth = maxwidth;
1417 else if(m_wrapStyle
== 2)
1424 CLine
* CSubtitle::GetNextLine(POSITION
& pos
, int maxwidth
)
1426 if(pos
== NULL
) return(NULL
);
1427 CLine
* ret
= new CLine();
1428 if(!ret
) return(NULL
);
1429 ret
->m_width
= ret
->m_ascent
= ret
->m_descent
= ret
->m_borderX
= ret
->m_borderY
= 0;
1430 maxwidth
= GetWrapWidth(pos
, maxwidth
);
1431 bool fEmptyLine
= true;
1434 SharedPtrCWord w
= m_words
.GetNext(pos
);
1435 if(ret
->m_ascent
< w
->m_ascent
) ret
->m_ascent
= w
->m_ascent
;
1436 if(ret
->m_descent
< w
->m_descent
) ret
->m_descent
= w
->m_descent
;
1437 if(ret
->m_borderX
< w
->m_style
.get().outlineWidthX
) ret
->m_borderX
= (int)(w
->m_style
.get().outlineWidthX
+0.5);
1438 if(ret
->m_borderY
< w
->m_style
.get().outlineWidthY
) ret
->m_borderY
= (int)(w
->m_style
.get().outlineWidthY
+0.5);
1441 if(fEmptyLine
) {ret
->m_ascent
/= 2; ret
->m_descent
/= 2; ret
->m_borderX
= ret
->m_borderY
= 0;}
1446 bool fWSC
= w
->m_fWhiteSpaceChar
;
1447 int width
= w
->m_width
;
1448 POSITION pos2
= pos
;
1451 if(m_words
.GetAt(pos2
)->m_fWhiteSpaceChar
!= fWSC
1452 || m_words
.GetAt(pos2
)->m_fLineBreak
) break;
1453 SharedPtrCWord w2
= m_words
.GetNext(pos2
);
1454 width
+= w2
->m_width
;
1456 if((ret
->m_width
+= width
) <= maxwidth
|| ret
->IsEmpty())
1458 ret
->AddWord2Tail(w
);
1461 ret
->AddWord2Tail(m_words
.GetNext(pos
));
1467 if(pos
) m_words
.GetPrev(pos
);
1468 else pos
= m_words
.GetTailPosition();
1469 ret
->m_width
-= width
;
1477 void CSubtitle::CreateClippers(CSize size
)
1481 if(m_effects
[EF_BANNER
] && m_effects
[EF_BANNER
]->param
[2])
1483 int width
= m_effects
[EF_BANNER
]->param
[2];
1484 int w
= size
.cx
, h
= size
.cy
;
1488 str
.Format(L
"m %d %d l %d %d %d %d %d %d", 0, 0, w
, 0, w
, h
, 0, h
);
1489 m_pClipper
= new CClipper(str
, size
, 1, 1, false);
1490 if(!m_pClipper
) return;
1492 int da
= (64<<8)/width
;
1493 BYTE
* am
= m_pClipper
->m_pAlphaMask
.get();
1494 for(int j
= 0; j
< h
; j
++, am
+= w
)
1497 int k
= min(width
, w
);
1498 for(int i
= 0; i
< k
; i
++, a
+= da
)
1499 am
[i
] = (am
[i
]*a
)>>14;
1502 if(k
< 0) {a
-= -k
*da
; k
= 0;}
1503 for(int i
= k
; i
< w
; i
++, a
-= da
)
1504 am
[i
] = (am
[i
]*a
)>>14;
1507 else if(m_effects
[EF_SCROLL
] && m_effects
[EF_SCROLL
]->param
[4])
1509 int height
= m_effects
[EF_SCROLL
]->param
[4];
1510 int w
= size
.cx
, h
= size
.cy
;
1514 str
.Format(L
"m %d %d l %d %d %d %d %d %d", 0, 0, w
, 0, w
, h
, 0, h
);
1515 m_pClipper
= new CClipper(str
, size
, 1, 1, false);
1516 if(!m_pClipper
) return;
1518 int da
= (64<<8)/height
;
1520 int k
= m_effects
[EF_SCROLL
]->param
[0]>>3;
1522 if(k
< 0) {a
+= -k
*da
; k
= 0;}
1526 BYTE
* am
= &m_pClipper
->m_pAlphaMask
[k
*w
];
1527 memset(m_pClipper
->m_pAlphaMask
.get(), 0, am
- m_pClipper
->m_pAlphaMask
.get());
1528 for(int j
= k
; j
< l
; j
++, a
+= da
)
1530 for(int i
= 0; i
< w
; i
++, am
++)
1531 *am
= ((*am
)*a
)>>14;
1534 da
= -(64<<8)/height
;
1536 l
= m_effects
[EF_SCROLL
]->param
[1]>>3;
1538 if(k
< 0) {a
+= -k
*da
; k
= 0;}
1542 BYTE
* am
= &m_pClipper
->m_pAlphaMask
[k
*w
];
1544 for(; j
< l
; j
++, a
+= da
)
1546 for(int i
= 0; i
< w
; i
++, am
++)
1547 *am
= ((*am
)*a
)>>14;
1549 memset(am
, 0, (h
-j
)*w
);
1554 void CSubtitle::MakeLines(CSize size
, CRect marginRect
)
1556 CSize
spaceNeeded(0, 0);
1557 bool fFirstLine
= true;
1558 m_topborder
= m_bottomborder
= 0;
1560 POSITION pos
= m_words
.GetHeadPosition();
1563 l
= GetNextLine(pos
, size
.cx
- marginRect
.left
- marginRect
.right
);
1565 if(fFirstLine
) {m_topborder
= l
->m_borderY
; fFirstLine
= false;}
1566 spaceNeeded
.cx
= max(l
->m_width
+l
->m_borderX
, spaceNeeded
.cx
);
1567 spaceNeeded
.cy
+= l
->m_ascent
+ l
->m_descent
;
1570 if(l
) m_bottomborder
= l
->m_borderY
;
1572 CPoint((m_scrAlignment
%3) == 1 ? marginRect
.left
1573 : (m_scrAlignment
%3) == 2 ? (marginRect
.left
+ (size
.cx
- marginRect
.right
) - spaceNeeded
.cx
+ 1) / 2
1574 : (size
.cx
- marginRect
.right
- spaceNeeded
.cx
),
1575 m_scrAlignment
<= 3 ? (size
.cy
- marginRect
.bottom
- spaceNeeded
.cy
)
1576 : m_scrAlignment
<= 6 ? (marginRect
.top
+ (size
.cy
- marginRect
.bottom
) - spaceNeeded
.cy
+ 1) / 2
1581 POSITION
CSubtitle::GetHeadLinePosition()
1583 return __super::GetHeadPosition();
1586 CLine
* CSubtitle::GetNextLine( POSITION
& pos
)
1588 return __super::GetNext(pos
);
1591 // CScreenLayoutAllocator
1593 void CScreenLayoutAllocator::Empty()
1595 m_subrects
.RemoveAll();
1598 void CScreenLayoutAllocator::AdvanceToSegment(int segment
, const CAtlArray
<int>& sa
)
1600 POSITION pos
= m_subrects
.GetHeadPosition();
1603 POSITION prev
= pos
;
1604 SubRect
& sr
= m_subrects
.GetNext(pos
);
1605 bool fFound
= false;
1606 if(abs(sr
.segment
- segment
) <= 1) // using abs() makes it possible to play the subs backwards, too :)
1608 for(size_t i
= 0; i
< sa
.GetCount() && !fFound
; i
++)
1610 if(sa
[i
] == sr
.entry
)
1612 sr
.segment
= segment
;
1617 if(!fFound
) m_subrects
.RemoveAt(prev
);
1621 CRect
CScreenLayoutAllocator::AllocRect(CSubtitle
* s
, int segment
, int entry
, int layer
, int collisions
)
1623 // TODO: handle collisions == 1 (reversed collisions)
1624 POSITION pos
= m_subrects
.GetHeadPosition();
1627 SubRect
& sr
= m_subrects
.GetNext(pos
);
1628 if(sr
.segment
== segment
&& sr
.entry
== entry
)
1630 return(sr
.r
+ CRect(0, -s
->m_topborder
, 0, -s
->m_bottomborder
));
1633 CRect r
= s
->m_rect
+ CRect(0, s
->m_topborder
, 0, s
->m_bottomborder
);
1634 bool fSearchDown
= s
->m_scrAlignment
> 3;
1639 pos
= m_subrects
.GetHeadPosition();
1642 SubRect
& sr
= m_subrects
.GetNext(pos
);
1643 if(layer
== sr
.layer
&& !(r
& sr
.r
).IsRectEmpty())
1647 r
.bottom
= sr
.r
.bottom
+ r
.Height();
1648 r
.top
= sr
.r
.bottom
;
1652 r
.top
= sr
.r
.top
- r
.Height();
1653 r
.bottom
= sr
.r
.top
;
1662 sr
.segment
= segment
;
1665 m_subrects
.AddTail(sr
);
1666 return(sr
.r
+ CRect(0, -s
->m_topborder
, 0, -s
->m_bottomborder
));
1669 // CRenderedTextSubtitle
1671 CAtlMap
<CStringW
, CRenderedTextSubtitle::AssCmdType
, CStringElementTraits
<CStringW
>> CRenderedTextSubtitle::m_cmdMap
;
1673 CRenderedTextSubtitle::CRenderedTextSubtitle(CCritSec
* pLock
)
1674 : CSubPicProviderImpl(pLock
)
1676 if( m_cmdMap
.IsEmpty() )
1680 m_size
= CSize(0, 0);
1681 if(g_hDC_refcnt
== 0)
1683 g_hDC
= CreateCompatibleDC(NULL
);
1684 SetBkMode(g_hDC
, TRANSPARENT
);
1685 SetTextColor(g_hDC
, 0xffffff);
1686 SetMapMode(g_hDC
, MM_TEXT
);
1691 CRenderedTextSubtitle::~CRenderedTextSubtitle()
1695 if(g_hDC_refcnt
== 0) DeleteDC(g_hDC
);
1698 void CRenderedTextSubtitle::InitCmdMap()
1700 if( m_cmdMap
.IsEmpty() )
1702 m_cmdMap
.SetAt(L
"1c", CMD_1c
);
1703 m_cmdMap
.SetAt(L
"2c", CMD_2c
);
1704 m_cmdMap
.SetAt(L
"3c", CMD_3c
);
1705 m_cmdMap
.SetAt(L
"4c", CMD_4c
);
1706 m_cmdMap
.SetAt(L
"1a", CMD_1a
);
1707 m_cmdMap
.SetAt(L
"2a", CMD_2a
);
1708 m_cmdMap
.SetAt(L
"3a", CMD_3a
);
1709 m_cmdMap
.SetAt(L
"4a", CMD_4a
);
1710 m_cmdMap
.SetAt(L
"alpha", CMD_alpha
);
1711 m_cmdMap
.SetAt(L
"an", CMD_an
);
1712 m_cmdMap
.SetAt(L
"a", CMD_a
);
1713 m_cmdMap
.SetAt(L
"blur", CMD_blur
);
1714 m_cmdMap
.SetAt(L
"bord", CMD_bord
);
1715 m_cmdMap
.SetAt(L
"be", CMD_be
);
1716 m_cmdMap
.SetAt(L
"b", CMD_b
);
1717 m_cmdMap
.SetAt(L
"clip", CMD_clip
);
1718 m_cmdMap
.SetAt(L
"iclip", CMD_iclip
);
1719 m_cmdMap
.SetAt(L
"c", CMD_c
);
1720 m_cmdMap
.SetAt(L
"fade", CMD_fade
);
1721 m_cmdMap
.SetAt(L
"fad", CMD_fad
);
1722 m_cmdMap
.SetAt(L
"fax", CMD_fax
);
1723 m_cmdMap
.SetAt(L
"fay", CMD_fay
);
1724 m_cmdMap
.SetAt(L
"fe", CMD_fe
);
1725 m_cmdMap
.SetAt(L
"fn", CMD_fn
);
1726 m_cmdMap
.SetAt(L
"frx", CMD_frx
);
1727 m_cmdMap
.SetAt(L
"fry", CMD_fry
);
1728 m_cmdMap
.SetAt(L
"frz", CMD_frz
);
1729 m_cmdMap
.SetAt(L
"fr", CMD_fr
);
1730 m_cmdMap
.SetAt(L
"fscx", CMD_fscx
);
1731 m_cmdMap
.SetAt(L
"fscy", CMD_fscy
);
1732 m_cmdMap
.SetAt(L
"fsc", CMD_fsc
);
1733 m_cmdMap
.SetAt(L
"fsp", CMD_fsp
);
1734 m_cmdMap
.SetAt(L
"fs", CMD_fs
);
1735 m_cmdMap
.SetAt(L
"i", CMD_i
);
1736 m_cmdMap
.SetAt(L
"kt", CMD_kt
);
1737 m_cmdMap
.SetAt(L
"kf", CMD_kf
);
1738 m_cmdMap
.SetAt(L
"K", CMD_K
);
1739 m_cmdMap
.SetAt(L
"ko", CMD_ko
);
1740 m_cmdMap
.SetAt(L
"k", CMD_k
);
1741 m_cmdMap
.SetAt(L
"move", CMD_move
);
1742 m_cmdMap
.SetAt(L
"org", CMD_org
);
1743 m_cmdMap
.SetAt(L
"pbo", CMD_pbo
);
1744 m_cmdMap
.SetAt(L
"pos", CMD_pos
);
1745 m_cmdMap
.SetAt(L
"p", CMD_p
);
1746 m_cmdMap
.SetAt(L
"q", CMD_q
);
1747 m_cmdMap
.SetAt(L
"r", CMD_r
);
1748 m_cmdMap
.SetAt(L
"shad", CMD_shad
);
1749 m_cmdMap
.SetAt(L
"s", CMD_s
);
1750 m_cmdMap
.SetAt(L
"t", CMD_t
);
1751 m_cmdMap
.SetAt(L
"u", CMD_u
);
1752 m_cmdMap
.SetAt(L
"xbord", CMD_xbord
);
1753 m_cmdMap
.SetAt(L
"xshad", CMD_xshad
);
1754 m_cmdMap
.SetAt(L
"ybord", CMD_ybord
);
1755 m_cmdMap
.SetAt(L
"yshad", CMD_yshad
);
1759 void CRenderedTextSubtitle::Copy(CRenderedTextSubtitle
& rts
)
1762 m_size
= rts
.m_size
;
1765 void CRenderedTextSubtitle::Copy(CSimpleTextSubtitle
& sts
)
1770 void CRenderedTextSubtitle::Empty()
1776 void CRenderedTextSubtitle::OnChanged()
1778 __super::OnChanged();
1779 POSITION pos
= m_subtitleCache
.GetStartPosition();
1784 m_subtitleCache
.GetNextAssoc(pos
, i
, s
);
1787 m_subtitleCache
.RemoveAll();
1791 bool CRenderedTextSubtitle::Init(CSize size
, CRect vidrect
)
1794 m_size
= CSize(size
.cx
*8, size
.cy
*8);
1795 m_vidrect
= CRect(vidrect
.left
*8, vidrect
.top
*8, vidrect
.right
*8, vidrect
.bottom
*8);
1800 void CRenderedTextSubtitle::Deinit()
1802 POSITION pos
= m_subtitleCache
.GetStartPosition();
1807 m_subtitleCache
.GetNextAssoc(pos
, i
, s
);
1810 m_subtitleCache
.RemoveAll();
1812 m_size
= CSize(0, 0);
1813 m_vidrect
.SetRectEmpty();
1815 CacheManager::GetCWordMruCache()->clear();
1816 CacheManager::GetPathDataMruCache()->clear();
1817 CacheManager::GetScanLineDataMruCache()->clear();
1818 CacheManager::GetOverlayNoBlurMruCache()->clear();
1819 CacheManager::GetOverlayMruCache()->clear();
1822 void CRenderedTextSubtitle::ParseEffect(CSubtitle
* sub
, const CStringW
& str
)
1824 CStringW::PCXSTR str_start
= str
.GetString();
1825 CStringW::PCXSTR str_end
= str_start
+ str
.GetLength();
1826 str_start
= SkipWhiteSpaceLeft(str_start
, str_end
);
1828 if(!sub
|| *str_start
==0)
1831 str_end
= FastSkipWhiteSpaceRight(str_start
, str_end
);
1833 const WCHAR
* s
= FindChar(str_start
, str_end
, L
';');
1838 const CStringW
effect(str_start
, s
-str_start
);
1839 if(!effect
.CompareNoCase( L
"Banner;" ) )
1841 int delay
, lefttoright
= 0, fadeawaywidth
= 0;
1842 if(swscanf(s
, L
"%d;%d;%d", &delay
, &lefttoright
, &fadeawaywidth
) < 1) return;
1843 Effect
* e
= new Effect
;
1845 sub
->m_effects
[e
->type
= EF_BANNER
] = e
;
1846 e
->param
[0] = (int)(max(1.0*delay
/sub
->m_scalex
, 1));
1847 e
->param
[1] = lefttoright
;
1848 e
->param
[2] = (int)(sub
->m_scalex
*fadeawaywidth
);
1849 sub
->m_wrapStyle
= 2;
1851 else if(!effect
.CompareNoCase(L
"Scroll up;") || !effect
.CompareNoCase(L
"Scroll down;"))
1853 int top
, bottom
, delay
, fadeawayheight
= 0;
1854 if(swscanf(s
, L
"%d;%d;%d;%d", &top
, &bottom
, &delay
, &fadeawayheight
) < 3) return;
1855 if(top
> bottom
) {int tmp
= top
; top
= bottom
; bottom
= tmp
;}
1856 Effect
* e
= new Effect
;
1858 sub
->m_effects
[e
->type
= EF_SCROLL
] = e
;
1859 e
->param
[0] = (int)(sub
->m_scaley
*top
*8);
1860 e
->param
[1] = (int)(sub
->m_scaley
*bottom
*8);
1861 e
->param
[2] = (int)(max(1.0*delay
/sub
->m_scaley
, 1));
1862 e
->param
[3] = (effect
.GetLength() == 12);
1863 e
->param
[4] = (int)(sub
->m_scaley
*fadeawayheight
);
1867 void CRenderedTextSubtitle::ParseString(CSubtitle
* sub
, CStringW str
, const FwSTSStyle
& style
)
1870 str
.Replace(L
"\\N", L
"\n");
1871 str
.Replace(L
"\\n", (sub
->m_wrapStyle
< 2 || sub
->m_wrapStyle
== 3) ? L
" " : L
"\n");
1872 str
.Replace(L
"\\h", L
"\x00A0");
1873 CWordMruCache
* word_mru_cache
=CacheManager::GetCWordMruCache();
1874 for(int ite
= 0, j
= 0, len
= str
.GetLength(); j
<= len
; j
++)
1877 if(c
!= L
'\n' && c
!= L
' ' && c
!= L
'\x00A0' && c
!= 0)
1881 CWordCacheKey
word_cache_key(style
, str
.Mid(ite
, j
-ite
), m_ktype
, m_kstart
, m_kend
);
1882 CWordMruCache::hashed_cache_const_iterator iter
= word_mru_cache
->hash_find(word_cache_key
);
1883 if( iter
!= word_mru_cache
->hash_end() )
1885 sub
->m_words
.AddTail(iter
->word
);
1887 else if(PCWord tmp_ptr
= new CText(style
, str
.Mid(ite
, j
-ite
), m_ktype
, m_kstart
, m_kend
))
1889 SharedPtrCWord
w(tmp_ptr
);
1890 sub
->m_words
.AddTail(w
);
1891 CWordMruItem
item(word_cache_key
, w
);
1892 word_mru_cache
->update_cache(item
);
1896 ///TODO: overflow handling
1902 CWordCacheKey
word_cache_key(style
, CStringW(), m_ktype
, m_kstart
, m_kend
);
1903 CWordMruCache::hashed_cache_const_iterator iter
= word_mru_cache
->hash_find(word_cache_key
);
1904 if( iter
!= word_mru_cache
->hash_end() )
1906 sub
->m_words
.AddTail(iter
->word
);
1908 else if(PCWord tmp_ptr
= new CText(style
, CStringW(), m_ktype
, m_kstart
, m_kend
))
1910 SharedPtrCWord
w(tmp_ptr
);
1911 sub
->m_words
.AddTail(w
);
1912 CWordMruItem
item(word_cache_key
, w
);
1913 word_mru_cache
->update_cache(item
);
1917 ///TODO: overflow handling
1921 else if(c
== L
' ' || c
== L
'\x00A0')
1923 CWordCacheKey
word_cache_key(style
, CStringW(c
), m_ktype
, m_kstart
, m_kend
);
1924 CWordMruCache::hashed_cache_const_iterator iter
= word_mru_cache
->hash_find(word_cache_key
);
1925 if( iter
!= word_mru_cache
->hash_end() )
1927 sub
->m_words
.AddTail(iter
->word
);
1929 else if(PCWord tmp_ptr
= new CText(style
, CStringW(c
), m_ktype
, m_kstart
, m_kend
))
1931 SharedPtrCWord
w(tmp_ptr
);
1932 sub
->m_words
.AddTail(w
);
1933 CWordMruItem
item(word_cache_key
, w
);
1934 word_mru_cache
->update_cache(item
);
1938 ///TODO: overflow handling
1947 void CRenderedTextSubtitle::ParsePolygon(CSubtitle
* sub
, const CStringW
& str
, const FwSTSStyle
& style
)
1949 if(!sub
|| !str
.GetLength() || !m_nPolygon
) return;
1951 if(PCWord tmp_ptr
= 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
))
1953 SharedPtrCWord
w(tmp_ptr
);
1955 //if( PCWord w_cache = m_wordCache.lookup(*w) )
1957 // sub->m_words.AddTail(w_cache);
1962 sub
->m_words
.AddTail(w
);
1968 bool CRenderedTextSubtitle::ParseSSATag( AssTagList
*assTags
, const CStringW
& str
)
1970 if(!assTags
) return(false);
1971 int nTags
= 0, nUnrecognizedTags
= 0;
1972 for(int i
= 0, j
; (j
= str
.Find(L
'\\', i
)) >= 0; i
= j
)
1974 POSITION pos
= assTags
->AddTail();
1975 AssTag
& assTag
= assTags
->GetAt(pos
);
1976 assTag
.cmdType
= CMD_COUNT
;
1979 CStringW::PCXSTR str_start
= str
.GetString() + j
;
1980 CStringW::PCXSTR pc
= str_start
;
1981 while( iswspace(*pc
) )
1987 while( *pc
&& *pc
!= L
'(' && *pc
!= L
'\\' )
1992 if( pc
-str_start
>0 )
1994 while( iswspace(*--pc
) );
1998 const CStringW
cmd(str_start
, pc
-str_start
);
1999 if(cmd
.IsEmpty()) continue;
2001 CAtlArray
<CStringW
>& params
= assTag
.strParams
;
2005 CStringW::PCXSTR str_start
= str
.GetString() + j
;
2006 CStringW::PCXSTR pc
= str_start
;
2007 while( iswspace(*pc
) )
2013 while( *pc
&& *pc
!= L
')' )
2018 if( pc
-str_start
>0 )
2020 while( iswspace(*--pc
) );
2024 CStringW::PCXSTR param_start
= str_start
;
2025 CStringW::PCXSTR param_end
= pc
;
2026 while( param_start
<param_end
)
2028 param_start
= SkipWhiteSpaceLeft(param_start
, param_end
);
2030 CStringW::PCXSTR newstart
= FindChar(param_start
, param_end
, L
',');
2031 CStringW::PCXSTR newend
= FindChar(param_start
, param_end
, L
'\\');
2032 if(newstart
> param_start
&& newstart
< newend
)
2034 newstart
= FastSkipWhiteSpaceRight(param_start
, newstart
);
2035 CStringW
s(param_start
, newstart
- param_start
);
2037 if(!s
.IsEmpty()) params
.Add(s
);
2038 param_start
= newstart
+ 1;
2040 else if(param_start
<param_end
)
2042 CStringW
s(param_start
, param_end
- param_start
);
2045 param_start
= param_end
;
2050 AssCmdType cmd_type
= CMD_COUNT
;
2051 int cmd_length
= min(MAX_CMD_LENGTH
, cmd
.GetLength());
2052 for( ;cmd_length
>=MIN_CMD_LENGTH
;cmd_length
-- )
2054 if( m_cmdMap
.Lookup(cmd
.Left(cmd_length
), cmd_type
) )
2057 if(cmd_length
<MIN_CMD_LENGTH
)
2058 cmd_type
= CMD_COUNT
;
2098 params
.Add(cmd
.Mid(cmd_length
));
2110 params
.Add(cmd
.Mid(cmd_length
).Trim(L
"&H"));
2121 ParseSSATag(&assTag
.embeded
, params
[0]);
2124 nUnrecognizedTags
++;
2129 assTag
.cmdType
= cmd_type
;
2136 bool CRenderedTextSubtitle::ParseSSATag( CSubtitle
* sub
, const AssTagList
& assTags
, STSStyle
& style
, const STSStyle
& org
, bool fAnimate
/*= false*/ )
2138 if(!sub
) return(false);
2140 POSITION pos
= assTags
.GetHeadPosition();
2143 const AssTag
& assTag
= assTags
.GetNext(pos
);
2144 const CStringW
& cmd
= assTag
.cmd
;
2145 AssCmdType cmd_type
= assTag
.cmdType
;
2146 const CAtlArray
<CStringW
>& params
= assTag
.strParams
;
2148 // TODO: call ParseStyleModifier(cmd, params, ..) and move the rest there
2149 const CStringW
& p
= params
.GetCount() > 0 ? params
[0] : CStringW("");
2157 int i
= cmd
[0] - L
'1';
2158 DWORD c
= wcstol(p
, NULL
, 16);
2159 style
.colors
[i
] = !p
.IsEmpty()
2160 ? (((int)CalcAnimation(c
&0xff, style
.colors
[i
]&0xff, fAnimate
))&0xff
2161 |((int)CalcAnimation(c
&0xff00, style
.colors
[i
]&0xff00, fAnimate
))&0xff00
2162 |((int)CalcAnimation(c
&0xff0000, style
.colors
[i
]&0xff0000, fAnimate
))&0xff0000)
2171 int i
= cmd
[0] - L
'1';
2172 style
.alpha
[i
] = !p
.IsEmpty()
2173 ? (BYTE
)CalcAnimation(wcstol(p
, NULL
, 16), style
.alpha
[i
], fAnimate
)
2179 for(int i
= 0; i
< 4; i
++)
2181 style
.alpha
[i
] = !p
.IsEmpty()
2182 ? (BYTE
)CalcAnimation(wcstol(p
, NULL
, 16), style
.alpha
[i
], fAnimate
)
2189 int n
= wcstol(p
, NULL
, 10);
2190 if(sub
->m_scrAlignment
< 0)
2191 sub
->m_scrAlignment
= (n
> 0 && n
< 10) ? n
: org
.scrAlignment
;
2196 int n
= wcstol(p
, NULL
, 10);
2197 if(sub
->m_scrAlignment
< 0)
2198 sub
->m_scrAlignment
= (n
> 0 && n
< 12) ? ((((n
-1)&3)+1)+((n
&4)?6:0)+((n
&8)?3:0)) : org
.scrAlignment
;
2203 double n
= CalcAnimation(wcstod(p
, NULL
), style
.fGaussianBlur
, fAnimate
);
2204 style
.fGaussianBlur
= !p
.IsEmpty()
2206 : org
.fGaussianBlur
;
2211 double dst
= wcstod(p
, NULL
);
2212 double nx
= CalcAnimation(dst
, style
.outlineWidthX
, fAnimate
);
2213 style
.outlineWidthX
= !p
.IsEmpty()
2215 : org
.outlineWidthX
;
2216 double ny
= CalcAnimation(dst
, style
.outlineWidthY
, fAnimate
);
2217 style
.outlineWidthY
= !p
.IsEmpty()
2219 : org
.outlineWidthY
;
2224 int n
= (int)(CalcAnimation(wcstol(p
, NULL
, 10), style
.fBlur
, fAnimate
)+0.5);
2225 style
.fBlur
= !p
.IsEmpty()
2232 int n
= wcstol(p
, NULL
, 10);
2233 style
.fontWeight
= !p
.IsEmpty()
2234 ? (n
== 0 ? FW_NORMAL
: n
== 1 ? FW_BOLD
: n
>= 100 ? n
: org
.fontWeight
)
2241 bool invert
= (cmd_type
== CMD_iclip
);
2242 if(params
.GetCount() == 1 && !sub
->m_pClipper
)
2244 sub
->m_pClipper
= new CClipper(params
[0], CSize(m_size
.cx
>>3, m_size
.cy
>>3), sub
->m_scalex
, sub
->m_scaley
, invert
);
2246 else if(params
.GetCount() == 2 && !sub
->m_pClipper
)
2248 int scale
= max(wcstol(p
, NULL
, 10), 1);
2249 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)), invert
);
2251 else if(params
.GetCount() == 4)
2254 sub
->m_clipInverse
= invert
;
2256 wcstol(params
[0], NULL
, 10),
2257 wcstol(params
[1], NULL
, 10),
2258 wcstol(params
[2], NULL
, 10),
2259 wcstol(params
[3], NULL
, 10));
2261 if(sub
->m_relativeTo
== 1) // TODO: this should also apply to the other two clippings above
2263 o
.x
= m_vidrect
.left
>>3;
2264 o
.y
= m_vidrect
.top
>>3;
2266 sub
->m_clip
.SetRect(
2267 (int)CalcAnimation(sub
->m_scalex
*r
.left
+ o
.x
, sub
->m_clip
.left
, fAnimate
),
2268 (int)CalcAnimation(sub
->m_scaley
*r
.top
+ o
.y
, sub
->m_clip
.top
, fAnimate
),
2269 (int)CalcAnimation(sub
->m_scalex
*r
.right
+ o
.x
, sub
->m_clip
.right
, fAnimate
),
2270 (int)CalcAnimation(sub
->m_scaley
*r
.bottom
+ o
.y
, sub
->m_clip
.bottom
, fAnimate
));
2276 DWORD c
= wcstol(p
, NULL
, 16);
2277 style
.colors
[0] = !p
.IsEmpty()
2278 ? (((int)CalcAnimation(c
&0xff, style
.colors
[0]&0xff, fAnimate
))&0xff
2279 |((int)CalcAnimation(c
&0xff00, style
.colors
[0]&0xff00, fAnimate
))&0xff00
2280 |((int)CalcAnimation(c
&0xff0000, style
.colors
[0]&0xff0000, fAnimate
))&0xff0000)
2287 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])
2289 if(Effect
* e
= new Effect
)
2291 for(int i
= 0; i
< 3; i
++)
2292 e
->param
[i
] = wcstol(params
[i
], NULL
, 10);
2293 for(int i
= 0; i
< 4; i
++)
2294 e
->t
[i
] = wcstol(params
[3+i
], NULL
, 10);
2295 sub
->m_effects
[EF_FADE
] = e
;
2298 else if(params
.GetCount() == 2 && !sub
->m_effects
[EF_FADE
]) // {\fad(t1=t[1], t2=t[2])
2300 if(Effect
* e
= new Effect
)
2302 e
->param
[0] = e
->param
[2] = 0xff;
2304 for(int i
= 1; i
< 3; i
++)
2305 e
->t
[i
] = wcstol(params
[i
-1], NULL
, 10);
2306 e
->t
[0] = e
->t
[3] = -1; // will be substituted with "start" and "end"
2307 sub
->m_effects
[EF_FADE
] = e
;
2314 style
.fontShiftX
= !p
.IsEmpty()
2315 ? CalcAnimation(wcstod(p
, NULL
), style
.fontShiftX
, fAnimate
)
2321 style
.fontShiftY
= !p
.IsEmpty()
2322 ? CalcAnimation(wcstod(p
, NULL
), style
.fontShiftY
, fAnimate
)
2328 int n
= wcstol(p
, NULL
, 10);
2329 style
.charSet
= !p
.IsEmpty()
2336 if(!p
.IsEmpty() && p
!= L
'0')
2337 style
.fontName
= CString(p
).Trim();
2339 style
.fontName
= org
.fontName
;
2344 style
.fontAngleX
= !p
.IsEmpty()
2345 ? CalcAnimation(wcstod(p
, NULL
), style
.fontAngleX
, fAnimate
)
2351 style
.fontAngleY
= !p
.IsEmpty()
2352 ? CalcAnimation(wcstod(p
, NULL
), style
.fontAngleY
, fAnimate
)
2359 style
.fontAngleZ
= !p
.IsEmpty()
2360 ? CalcAnimation(wcstod(p
, NULL
), style
.fontAngleZ
, fAnimate
)
2366 double n
= CalcAnimation(wcstol(p
, NULL
, 10), style
.fontScaleX
, fAnimate
);
2367 style
.fontScaleX
= !p
.IsEmpty()
2374 double n
= CalcAnimation(wcstol(p
, NULL
, 10), style
.fontScaleY
, fAnimate
);
2375 style
.fontScaleY
= !p
.IsEmpty()
2382 style
.fontScaleX
= org
.fontScaleX
;
2383 style
.fontScaleY
= org
.fontScaleY
;
2388 style
.fontSpacing
= !p
.IsEmpty()
2389 ? CalcAnimation(wcstod(p
, NULL
), style
.fontSpacing
, fAnimate
)
2397 if(p
[0] == L
'-' || p
[0] == L
'+')
2399 double n
= CalcAnimation(style
.fontSize
+ style
.fontSize
*wcstol(p
, NULL
, 10)/10, style
.fontSize
, fAnimate
);
2400 style
.fontSize
= (n
> 0) ? n
: org
.fontSize
;
2404 double n
= CalcAnimation(wcstol(p
, NULL
, 10), style
.fontSize
, fAnimate
);
2405 style
.fontSize
= (n
> 0) ? n
: org
.fontSize
;
2410 style
.fontSize
= org
.fontSize
;
2416 int n
= wcstol(p
, NULL
, 10);
2417 style
.fItalic
= !p
.IsEmpty()
2418 ? (n
== 0 ? false : n
== 1 ? true : org
.fItalic
)
2424 m_kstart
= !p
.IsEmpty()
2425 ? wcstol(p
, NULL
, 10)*10
2429 sub
->m_fAnimated2
= true;//fix me: define m_fAnimated m_fAnimated2 strictly
2436 m_kend
+= !p
.IsEmpty()
2437 ? wcstol(p
, NULL
, 10)*10
2439 sub
->m_fAnimated2
= true;//fix me: define m_fAnimated m_fAnimated2 strictly
2446 m_kend
+= !p
.IsEmpty()
2447 ? wcstol(p
, NULL
, 10)*10
2449 sub
->m_fAnimated2
= true;//fix me: define m_fAnimated m_fAnimated2 strictly
2456 m_kend
+= !p
.IsEmpty()
2457 ? wcstol(p
, NULL
, 10)*10
2459 sub
->m_fAnimated2
= true;//fix me: define m_fAnimated m_fAnimated2 strictly
2462 case CMD_move
: // {\move(x1=param[0], y1=param[1], x2=param[2], y2=param[3][, t1=t[0], t2=t[1]])}
2464 if((params
.GetCount() == 4 || params
.GetCount() == 6) && !sub
->m_effects
[EF_MOVE
])
2466 if(Effect
* e
= new Effect
)
2468 e
->param
[0] = (int)(sub
->m_scalex
*wcstod(params
[0], NULL
)*8);
2469 e
->param
[1] = (int)(sub
->m_scaley
*wcstod(params
[1], NULL
)*8);
2470 e
->param
[2] = (int)(sub
->m_scalex
*wcstod(params
[2], NULL
)*8);
2471 e
->param
[3] = (int)(sub
->m_scaley
*wcstod(params
[3], NULL
)*8);
2472 e
->t
[0] = e
->t
[1] = -1;
2473 if(params
.GetCount() == 6)
2475 for(int i
= 0; i
< 2; i
++)
2476 e
->t
[i
] = wcstol(params
[4+i
], NULL
, 10);
2478 sub
->m_effects
[EF_MOVE
] = e
;
2483 case CMD_org
: // {\org(x=param[0], y=param[1])}
2485 if(params
.GetCount() == 2 && !sub
->m_effects
[EF_ORG
])
2487 if(Effect
* e
= new Effect
)
2489 e
->param
[0] = (int)(sub
->m_scalex
*wcstod(params
[0], NULL
)*8);
2490 e
->param
[1] = (int)(sub
->m_scaley
*wcstod(params
[1], NULL
)*8);
2491 sub
->m_effects
[EF_ORG
] = e
;
2498 m_polygonBaselineOffset
= wcstol(p
, NULL
, 10);
2503 if(params
.GetCount() == 2 && !sub
->m_effects
[EF_MOVE
])
2505 if(Effect
* e
= new Effect
)
2507 e
->param
[0] = e
->param
[2] = (int)(sub
->m_scalex
*wcstod(params
[0], NULL
)*8);
2508 e
->param
[1] = e
->param
[3] = (int)(sub
->m_scaley
*wcstod(params
[1], NULL
)*8);
2509 e
->t
[0] = e
->t
[1] = 0;
2510 sub
->m_effects
[EF_MOVE
] = e
;
2517 int n
= wcstol(p
, NULL
, 10);
2518 m_nPolygon
= (n
<= 0 ? 0 : n
);
2523 int n
= wcstol(p
, NULL
, 10);
2524 sub
->m_wrapStyle
= !p
.IsEmpty() && (0 <= n
&& n
<= 3)
2526 : m_defaultWrapStyle
;
2532 style
= (!p
.IsEmpty() && m_styles
.Lookup(WToT(p
), val
) && val
) ? *val
: org
;
2537 double dst
= wcstod(p
, NULL
);
2538 double nx
= CalcAnimation(dst
, style
.shadowDepthX
, fAnimate
);
2539 style
.shadowDepthX
= !p
.IsEmpty()
2542 double ny
= CalcAnimation(dst
, style
.shadowDepthY
, fAnimate
);
2543 style
.shadowDepthY
= !p
.IsEmpty()
2550 int n
= wcstol(p
, NULL
, 10);
2551 style
.fStrikeOut
= !p
.IsEmpty()
2552 ? (n
== 0 ? false : n
== 1 ? true : org
.fStrikeOut
)
2556 case CMD_t
: // \t([<t1>,<t2>,][<accel>,]<style modifiers>)
2559 m_animStart
= m_animEnd
= 0;
2561 if(params
.GetCount() == 1)
2565 else if(params
.GetCount() == 2)
2567 m_animAccel
= wcstod(params
[0], NULL
);
2570 else if(params
.GetCount() == 3)
2572 m_animStart
= (int)wcstod(params
[0], NULL
);
2573 m_animEnd
= (int)wcstod(params
[1], NULL
);
2576 else if(params
.GetCount() == 4)
2578 m_animStart
= wcstol(params
[0], NULL
, 10);
2579 m_animEnd
= wcstol(params
[1], NULL
, 10);
2580 m_animAccel
= wcstod(params
[2], NULL
);
2583 ParseSSATag(sub
, assTag
.embeded
, style
, org
, true);
2584 sub
->m_fAnimated
= true;
2589 int n
= wcstol(p
, NULL
, 10);
2590 style
.fUnderline
= !p
.IsEmpty()
2591 ? (n
== 0 ? false : n
== 1 ? true : org
.fUnderline
)
2597 double dst
= wcstod(p
, NULL
);
2598 double nx
= CalcAnimation(dst
, style
.outlineWidthX
, fAnimate
);
2599 style
.outlineWidthX
= !p
.IsEmpty()
2601 : org
.outlineWidthX
;
2606 double dst
= wcstod(p
, NULL
);
2607 double nx
= CalcAnimation(dst
, style
.shadowDepthX
, fAnimate
);
2608 style
.shadowDepthX
= !p
.IsEmpty()
2615 double dst
= wcstod(p
, NULL
);
2616 double ny
= CalcAnimation(dst
, style
.outlineWidthY
, fAnimate
);
2617 style
.outlineWidthY
= !p
.IsEmpty()
2619 : org
.outlineWidthY
;
2624 double dst
= wcstod(p
, NULL
);
2625 double ny
= CalcAnimation(dst
, style
.shadowDepthY
, fAnimate
);
2626 style
.shadowDepthY
= !p
.IsEmpty()
2638 bool CRenderedTextSubtitle::ParseSSATag(CSubtitle
* sub
, const CStringW
& str
, STSStyle
& style
, const STSStyle
& org
, bool fAnimate
)
2640 if(!sub
) return(false);
2642 SharedPtrConstAssTagList assTags
;
2643 AssTagListMruCache
*ass_tag_cache
= CacheManager::GetAssTagListMruCache();
2644 AssTagListMruCache::hashed_cache_const_iterator iter
= ass_tag_cache
->hash_find(str
);
2645 if (iter
==ass_tag_cache
->hash_end())
2647 AssTagList
*tmp
= new AssTagList();
2648 ParseSSATag(tmp
, str
);
2650 AssTagListMruItem item
;
2651 item
.script
= str
; item
.tag_list
= assTags
;
2652 ass_tag_cache
->update_cache( item
);
2656 assTags
= iter
->tag_list
;
2657 ass_tag_cache
->update_cache( *iter
);
2659 return ParseSSATag(sub
, *assTags
, style
, org
, fAnimate
);
2662 bool CRenderedTextSubtitle::ParseHtmlTag(CSubtitle
* sub
, CStringW str
, STSStyle
& style
, STSStyle
& org
)
2664 if(str
.Find(L
"!--") == 0)
2666 bool fClosing
= str
[0] == L
'/';
2668 int i
= str
.Find(L
' ');
2669 if(i
< 0) i
= str
.GetLength();
2670 CStringW tag
= str
.Left(i
).MakeLower();
2671 str
= str
.Mid(i
).Trim();
2672 CAtlArray
<CStringW
> attribs
, params
;
2673 while((i
= str
.Find(L
'=')) > 0)
2675 attribs
.Add(str
.Left(i
).Trim().MakeLower());
2677 for(i
= 0; _istspace(str
[i
]); i
++);
2679 if(str
[0] == L
'\"') {str
= str
.Mid(1); i
= str
.Find(L
'\"');}
2680 else i
= str
.Find(L
' ');
2681 if(i
< 0) i
= str
.GetLength();
2682 params
.Add(str
.Left(i
).Trim().MakeLower());
2687 else if(tag
== L
"b" || tag
== L
"strong")
2688 style
.fontWeight
= !fClosing
? FW_BOLD
: org
.fontWeight
;
2689 else if(tag
== L
"i" || tag
== L
"em")
2690 style
.fItalic
= !fClosing
? true : org
.fItalic
;
2691 else if(tag
== L
"u")
2692 style
.fUnderline
= !fClosing
? true : org
.fUnderline
;
2693 else if(tag
== L
"s" || tag
== L
"strike" || tag
== L
"del")
2694 style
.fStrikeOut
= !fClosing
? true : org
.fStrikeOut
;
2695 else if(tag
== L
"font")
2699 for(size_t i
= 0; i
< attribs
.GetCount(); i
++)
2701 if(params
[i
].IsEmpty()) continue;
2703 if(attribs
[i
] == L
"face")
2705 style
.fontName
= params
[i
];
2707 else if(attribs
[i
] == L
"size")
2709 if(params
[i
][0] == L
'+')
2710 style
.fontSize
+= wcstol(params
[i
], NULL
, 10);
2711 else if(params
[i
][0] == L
'-')
2712 style
.fontSize
-= wcstol(params
[i
], NULL
, 10);
2714 style
.fontSize
= wcstol(params
[i
], NULL
, 10);
2716 else if(attribs
[i
] == L
"color")
2720 else if(attribs
[i
] == L
"outline-color")
2724 else if(attribs
[i
] == L
"outline-level")
2726 style
.outlineWidthX
= style
.outlineWidthY
= wcstol(params
[i
], NULL
, 10);
2728 else if(attribs
[i
] == L
"shadow-color")
2732 else if(attribs
[i
] == L
"shadow-level")
2734 style
.shadowDepthX
= style
.shadowDepthY
= wcstol(params
[i
], NULL
, 10);
2736 if(nColor
>= 0 && nColor
< 4)
2738 CString key
= WToT(params
[i
]).TrimLeft(L
'#');
2740 if(g_colors
.Lookup(key
, val
))
2741 style
.colors
[nColor
] = val
;
2742 else if((style
.colors
[nColor
] = _tcstol(key
, NULL
, 16)) == 0)
2743 style
.colors
[nColor
] = 0x00ffffff; // default is white
2744 style
.colors
[nColor
] = ((style
.colors
[nColor
]>>16)&0xff)|((style
.colors
[nColor
]&0xff)<<16)|(style
.colors
[nColor
]&0x00ff00);
2750 style
.fontName
= org
.fontName
;
2751 style
.fontSize
= org
.fontSize
;
2752 memcpy(style
.colors
, org
.colors
, sizeof(style
.colors
));
2755 else if(tag
== L
"k" && attribs
.GetCount() == 1 && attribs
[0] == L
"t")
2759 m_kend
+= wcstol(params
[0], NULL
, 10);
2766 double CRenderedTextSubtitle::CalcAnimation(double dst
, double src
, bool fAnimate
)
2768 int s
= m_animStart
? m_animStart
: 0;
2769 int e
= m_animEnd
? m_animEnd
: m_delay
;
2770 if(fabs(dst
-src
) >= 0.0001 && fAnimate
)
2772 if(m_time
< s
) dst
= src
;
2773 else if(s
<= m_time
&& m_time
< e
)
2775 double t
= pow(1.0 * (m_time
- s
) / (e
- s
), m_animAccel
);
2776 dst
= (1 - t
) * src
+ t
* dst
;
2783 CSubtitle
* CRenderedTextSubtitle::GetSubtitle(int entry
)
2786 if(m_subtitleCache
.Lookup(entry
, sub
))
2788 if(sub
->m_fAnimated
) {delete sub
; sub
= NULL
;}
2791 sub
= new CSubtitle();
2792 if(!sub
) return(NULL
);
2793 CStringW str
= GetStrW(entry
, true);
2794 STSStyle stss
, orgstss
;
2795 GetStyle(entry
, &stss
);
2796 if (stss
.fontScaleX
== stss
.fontScaleY
&& m_dPARCompensation
!= 1.0)
2798 switch(m_ePARCompensationType
)
2801 if (m_dPARCompensation
< 1.0)
2802 stss
.fontScaleY
/= m_dPARCompensation
;
2804 stss
.fontScaleX
*= m_dPARCompensation
;
2807 if (m_dPARCompensation
< 1.0)
2808 stss
.fontScaleX
*= m_dPARCompensation
;
2810 stss
.fontScaleY
/= m_dPARCompensation
;
2812 case EPCTAccurateSize
:
2813 stss
.fontScaleX
*= m_dPARCompensation
;
2818 sub
->m_clip
.SetRect(0, 0, m_size
.cx
>>3, m_size
.cy
>>3);
2819 sub
->m_scrAlignment
= -stss
.scrAlignment
;
2820 sub
->m_wrapStyle
= m_defaultWrapStyle
;
2821 sub
->m_fAnimated
= false;
2822 sub
->m_relativeTo
= stss
.relativeTo
;
2823 sub
->m_scalex
= m_dstScreenSize
.cx
> 0 ? 1.0 * (stss
.relativeTo
== 1 ? m_vidrect
.Width() : m_size
.cx
) / (m_dstScreenSize
.cx
*8) : 1.0;
2824 sub
->m_scaley
= m_dstScreenSize
.cy
> 0 ? 1.0 * (stss
.relativeTo
== 1 ? m_vidrect
.Height() : m_size
.cy
) / (m_dstScreenSize
.cy
*8) : 1.0;
2825 m_animStart
= m_animEnd
= 0;
2827 m_ktype
= m_kstart
= m_kend
= 0;
2829 m_polygonBaselineOffset
= 0;
2830 ParseEffect(sub
, m_entries
.GetAt(entry
).effect
);
2831 while(!str
.IsEmpty())
2833 bool fParsed
= false;
2835 if(str
[0] == L
'{' && (i
= str
.Find(L
'}')) > 0)
2837 if(fParsed
= ParseSSATag(sub
, str
.Mid(1, i
-1), stss
, orgstss
))
2840 else if(str
[0] == L
'<' && (i
= str
.Find(L
'>')) > 0)
2842 if(fParsed
= ParseHtmlTag(sub
, str
.Mid(1, i
-1), stss
, orgstss
))
2847 i
= str
.FindOneOf(L
"{<");
2848 if(i
< 0) i
= str
.GetLength();
2849 if(i
== 0) continue;
2853 i
= str
.Mid(1).FindOneOf(L
"{<");
2854 if(i
< 0) i
= str
.GetLength()-1;
2857 STSStyle tmp
= stss
;
2858 tmp
.fontSize
= sub
->m_scaley
*tmp
.fontSize
*64;
2859 tmp
.fontSpacing
= sub
->m_scalex
*tmp
.fontSpacing
*64;
2860 tmp
.outlineWidthX
*= (m_fScaledBAS
? sub
->m_scalex
: 1) * 8;
2861 tmp
.outlineWidthY
*= (m_fScaledBAS
? sub
->m_scaley
: 1) * 8;
2862 tmp
.shadowDepthX
*= (m_fScaledBAS
? sub
->m_scalex
: 1) * 8;
2863 tmp
.shadowDepthY
*= (m_fScaledBAS
? sub
->m_scaley
: 1) * 8;
2864 FwSTSStyle
fw_tmp(tmp
);
2867 ParsePolygon(sub
, str
.Left(i
), fw_tmp
);
2871 ParseString(sub
, str
.Left(i
), fw_tmp
);
2875 sub
->m_fAnimated2
|= sub
->m_fAnimated
;
2876 if( sub
->m_effects
[EF_FADE
] || sub
->m_effects
[EF_BANNER
] || sub
->m_effects
[EF_SCROLL
]
2877 || sub
->m_effects
[EF_MOVE
] )
2878 sub
->m_fAnimated2
= true;
2879 // just a "work-around" solution... in most cases nobody will want to use \org together with moving but without rotating the subs
2880 if(sub
->m_effects
[EF_ORG
] && (sub
->m_effects
[EF_MOVE
] || sub
->m_effects
[EF_BANNER
] || sub
->m_effects
[EF_SCROLL
]))
2881 sub
->m_fAnimated
= true;
2882 sub
->m_scrAlignment
= abs(sub
->m_scrAlignment
);
2883 STSEntry stse
= m_entries
.GetAt(entry
);
2884 CRect marginRect
= stse
.marginRect
;
2885 if(marginRect
.left
== 0) marginRect
.left
= orgstss
.marginRect
.get().left
;
2886 if(marginRect
.top
== 0) marginRect
.top
= orgstss
.marginRect
.get().top
;
2887 if(marginRect
.right
== 0) marginRect
.right
= orgstss
.marginRect
.get().right
;
2888 if(marginRect
.bottom
== 0) marginRect
.bottom
= orgstss
.marginRect
.get().bottom
;
2889 marginRect
.left
= (int)(sub
->m_scalex
*marginRect
.left
*8);
2890 marginRect
.top
= (int)(sub
->m_scaley
*marginRect
.top
*8);
2891 marginRect
.right
= (int)(sub
->m_scalex
*marginRect
.right
*8);
2892 marginRect
.bottom
= (int)(sub
->m_scaley
*marginRect
.bottom
*8);
2893 if(stss
.relativeTo
== 1)
2895 marginRect
.left
+= m_vidrect
.left
;
2896 marginRect
.top
+= m_vidrect
.top
;
2897 marginRect
.right
+= m_size
.cx
- m_vidrect
.right
;
2898 marginRect
.bottom
+= m_size
.cy
- m_vidrect
.bottom
;
2900 sub
->CreateClippers(m_size
);
2901 sub
->MakeLines(m_size
, marginRect
);
2902 m_subtitleCache
[entry
] = sub
;
2908 STDMETHODIMP
CRenderedTextSubtitle::NonDelegatingQueryInterface(REFIID riid
, void** ppv
)
2910 CheckPointer(ppv
, E_POINTER
);
2916 QI(ISubPicProviderEx
)
2917 __super::NonDelegatingQueryInterface(riid
, ppv
);
2922 STDMETHODIMP_(POSITION
) CRenderedTextSubtitle::GetStartPosition(REFERENCE_TIME rt
, double fps
)
2924 //DbgLog((LOG_TRACE, 3, "rt:%lu", (ULONG)rt/10000));
2925 m_fps
= fps
;//fix me: check is fps changed and do some re-init thing
2927 int subIndex
= 1;//If a segment has animate effect then it corresponds to several subpics.
2928 //subIndex, 1 based, indicates which subpic the result corresponds to.
2930 const STSSegment
*stss
= SearchSubs((int)rt
, fps
, &iSegment
, NULL
);
2933 else if(stss
->animated
)
2935 int start
= TranslateSegmentStart(iSegment
, fps
);
2937 subIndex
= (rt
-start
)/RTS_ANIMATE_SUBPIC_DUR
+ 1;
2939 //DbgLog((LOG_TRACE, 3, "animated:%d seg:%d idx:%d DUR:%d rt:%lu", stss->animated, iSegment, subIndex, RTS_ANIMATE_SUBPIC_DUR, (ULONG)rt/10000));
2940 return (POSITION
)(subIndex
| (iSegment
<<RTS_POS_SEGMENT_INDEX_BITS
));
2941 //if(iSegment < 0) iSegment = 0;
2942 //return(GetNext((POSITION)iSegment));
2945 STDMETHODIMP_(POSITION
) CRenderedTextSubtitle::GetNext(POSITION pos
)
2947 int iSegment
= ((int)pos
>>RTS_POS_SEGMENT_INDEX_BITS
);
2948 int subIndex
= ((int)pos
& RTS_POS_SUB_INDEX_MASK
);
2949 const STSSegment
*stss
= GetSegment(iSegment
);
2950 ASSERT(stss
!=NULL
&& stss
->subs
.GetCount()>0);
2951 //DbgLog((LOG_TRACE, 3, "stss:%x count:%d", stss, stss->subs.GetCount()));
2960 TranslateSegmentStartEnd(iSegment
, m_fps
, start
, end
);
2961 if(start
+RTS_ANIMATE_SUBPIC_DUR
*subIndex
< end
)
2969 if(GetSegment(iSegment
) != NULL
)
2971 ASSERT(GetSegment(iSegment
)->subs
.GetCount()>0);
2972 return (POSITION
)(subIndex
| (iSegment
<<RTS_POS_SEGMENT_INDEX_BITS
));
2978 //@return: <0 if segment not found
2979 STDMETHODIMP_(REFERENCE_TIME
) CRenderedTextSubtitle::GetStart(POSITION pos
, double fps
)
2981 //return(10000i64 * TranslateSegmentStart((int)pos-1, fps));
2982 int iSegment
= ((int)pos
>>RTS_POS_SEGMENT_INDEX_BITS
);
2983 int subIndex
= ((int)pos
& RTS_POS_SUB_INDEX_MASK
);
2984 int start
= TranslateSegmentStart(iSegment
, fps
);
2985 const STSSegment
*stss
= GetSegment(iSegment
);
2988 return (start
+ (subIndex
-1)*RTS_ANIMATE_SUBPIC_DUR
)*10000i64
;
2996 //@return: <0 if segment not found
2997 STDMETHODIMP_(REFERENCE_TIME
) CRenderedTextSubtitle::GetStop(POSITION pos
, double fps
)
2999 // return(10000i64 * TranslateSegmentEnd((int)pos-1, fps));
3000 int iSegment
= ((int)pos
>>RTS_POS_SEGMENT_INDEX_BITS
);
3001 int subIndex
= ((int)pos
& RTS_POS_SUB_INDEX_MASK
);
3002 int start
, end
, ret
;
3003 TranslateSegmentStartEnd(iSegment
, fps
, start
, end
);
3004 const STSSegment
*stss
= GetSegment(iSegment
);
3011 ret
= start
+subIndex
*RTS_ANIMATE_SUBPIC_DUR
;
3015 return ret
*10000i64
;
3021 //@start, @stop: -1 if segment not found; @stop may < @start if subIndex exceed uppper bound
3022 STDMETHODIMP_(VOID
) CRenderedTextSubtitle::GetStartStop(POSITION pos
, double fps
, /*out*/REFERENCE_TIME
&start
, /*out*/REFERENCE_TIME
&stop
)
3024 int iSegment
= ((int)pos
>>RTS_POS_SEGMENT_INDEX_BITS
);
3025 int subIndex
= ((int)pos
& RTS_POS_SUB_INDEX_MASK
);
3026 int tempStart
, tempEnd
;
3027 TranslateSegmentStartEnd(iSegment
, fps
, tempStart
, tempEnd
);
3030 const STSSegment
*stss
= GetSegment(iSegment
);
3035 start
+= (subIndex
-1)*RTS_ANIMATE_SUBPIC_DUR
;
3036 if(start
+RTS_ANIMATE_SUBPIC_DUR
< stop
)
3037 stop
= start
+RTS_ANIMATE_SUBPIC_DUR
;
3039 //DbgLog((LOG_TRACE, 3, "animated:%d seg:%d idx:%d start:%d stop:%lu", stss->animated, iSegment, subIndex, (ULONG)start, (ULONG)stop));
3050 STDMETHODIMP_(bool) CRenderedTextSubtitle::IsAnimated(POSITION pos
)
3052 int iSegment
= ((int)pos
>>RTS_POS_SEGMENT_INDEX_BITS
);
3053 if(iSegment
>=0 && iSegment
<m_segments
.GetCount())
3054 return m_segments
[iSegment
].animated
;
3060 struct LSub
{int idx
, layer
, readorder
;};
3062 static int lscomp(const void* ls1
, const void* ls2
)
3064 int ret
= ((LSub
*)ls1
)->layer
- ((LSub
*)ls2
)->layer
;
3065 if(!ret
) ret
= ((LSub
*)ls1
)->readorder
- ((LSub
*)ls2
)->readorder
;
3069 STDMETHODIMP
CRenderedTextSubtitle::RenderEx(SubPicDesc
& spd
, REFERENCE_TIME rt
, double fps
, CAtlList
<CRect
>& rectList
)
3071 CRect
bbox2(0,0,0,0);
3072 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))
3073 Init(CSize(spd
.w
, spd
.h
), spd
.vidrect
);
3074 int t
= (int)(rt
/ 10000);
3077 STSSegment
* stss
= SearchSubs2(t
, fps
, &segment
);
3078 if(!stss
) return S_FALSE
;
3079 // clear any cached subs not in the range of +/-30secs measured from the segment's bounds
3081 POSITION pos
= m_subtitleCache
.GetStartPosition();
3086 m_subtitleCache
.GetNextAssoc(pos
, key
, value
);
3087 STSEntry
& stse
= m_entries
.GetAt(key
);
3088 if(stse
.end
<= (t
-30000) || stse
.start
> (t
+30000))
3091 m_subtitleCache
.RemoveKey(key
);
3092 pos
= m_subtitleCache
.GetStartPosition();
3096 m_sla
.AdvanceToSegment(segment
, stss
->subs
);
3097 CAtlArray
<LSub
> subs
;
3098 for(int i
= 0, j
= stss
->subs
.GetCount(); i
< j
; i
++)
3101 ls
.idx
= stss
->subs
[i
];
3102 ls
.layer
= m_entries
.GetAt(stss
->subs
[i
]).layer
;
3103 ls
.readorder
= m_entries
.GetAt(stss
->subs
[i
]).readorder
;
3106 qsort(subs
.GetData(), subs
.GetCount(), sizeof(LSub
), lscomp
);
3108 CompositeDrawItemList drawItemList
;
3109 for(int i
= 0, j
= subs
.GetCount(); i
< j
; i
++)
3111 int entry
= subs
[i
].idx
;
3112 STSEntry stse
= m_entries
.GetAt(entry
);
3114 int start
= TranslateStart(entry
, fps
);
3116 m_delay
= TranslateEnd(entry
, fps
) - start
;
3118 CSubtitle
* s
= GetSubtitle(entry
);
3120 stss
->animated
|= s
->m_fAnimated2
;
3121 CRect clipRect
= s
->m_clip
;
3122 CRect r
= s
->m_rect
;
3123 CSize spaceNeeded
= r
.Size();
3124 // apply the effects
3125 bool fPosOverride
= false, fOrgOverride
= false;
3128 for(int k
= 0; k
< EF_NUMBEROFEFFECTS
; k
++)
3130 if(!s
->m_effects
[k
]) continue;
3133 case EF_MOVE
: // {\move(x1=param[0], y1=param[1], x2=param[2], y2=param[3], t1=t[0], t2=t[1])}
3136 CPoint
p1(s
->m_effects
[k
]->param
[0], s
->m_effects
[k
]->param
[1]);
3137 CPoint
p2(s
->m_effects
[k
]->param
[2], s
->m_effects
[k
]->param
[3]);
3138 int t1
= s
->m_effects
[k
]->t
[0];
3139 int t2
= s
->m_effects
[k
]->t
[1];
3140 if(t2
< t1
) {int t
= t1
; t1
= t2
; t2
= t
;}
3141 if(t1
<= 0 && t2
<= 0) {t1
= 0; t2
= m_delay
;}
3142 if(m_time
<= t1
) p
= p1
;
3143 else if (p1
== p2
) p
= p1
;
3144 else if(t1
< m_time
&& m_time
< t2
)
3146 double t
= 1.0*(m_time
-t1
)/(t2
-t1
);
3147 p
.x
= (int)((1-t
)*p1
.x
+ t
*p2
.x
);
3148 p
.y
= (int)((1-t
)*p1
.y
+ t
*p2
.y
);
3152 CPoint((s
->m_scrAlignment
%3) == 1 ? p
.x
: (s
->m_scrAlignment
%3) == 0 ? p
.x
- spaceNeeded
.cx
: p
.x
- (spaceNeeded
.cx
+1)/2,
3153 s
->m_scrAlignment
<= 3 ? p
.y
- spaceNeeded
.cy
: s
->m_scrAlignment
<= 6 ? p
.y
- (spaceNeeded
.cy
+1)/2 : p
.y
),
3155 if(s
->m_relativeTo
== 1)
3156 r
.OffsetRect(m_vidrect
.TopLeft());
3157 fPosOverride
= true;
3160 case EF_ORG
: // {\org(x=param[0], y=param[1])}
3162 org2
= CPoint(s
->m_effects
[k
]->param
[0], s
->m_effects
[k
]->param
[1]);
3163 fOrgOverride
= true;
3166 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])
3168 int t1
= s
->m_effects
[k
]->t
[0];
3169 int t2
= s
->m_effects
[k
]->t
[1];
3170 int t3
= s
->m_effects
[k
]->t
[2];
3171 int t4
= s
->m_effects
[k
]->t
[3];
3172 if(t1
== -1 && t4
== -1) {t1
= 0; t3
= m_delay
-t3
; t4
= m_delay
;}
3173 if(m_time
< t1
) alpha
= s
->m_effects
[k
]->param
[0];
3174 else if(m_time
>= t1
&& m_time
< t2
)
3176 double t
= 1.0 * (m_time
- t1
) / (t2
- t1
);
3177 alpha
= (int)(s
->m_effects
[k
]->param
[0]*(1-t
) + s
->m_effects
[k
]->param
[1]*t
);
3179 else if(m_time
>= t2
&& m_time
< t3
) alpha
= s
->m_effects
[k
]->param
[1];
3180 else if(m_time
>= t3
&& m_time
< t4
)
3182 double t
= 1.0 * (m_time
- t3
) / (t4
- t3
);
3183 alpha
= (int)(s
->m_effects
[k
]->param
[1]*(1-t
) + s
->m_effects
[k
]->param
[2]*t
);
3185 else if(m_time
>= t4
) alpha
= s
->m_effects
[k
]->param
[2];
3188 case EF_BANNER
: // Banner;delay=param[0][;leftoright=param[1];fadeawaywidth=param[2]]
3190 int left
= s
->m_relativeTo
== 1 ? m_vidrect
.left
: 0,
3191 right
= s
->m_relativeTo
== 1 ? m_vidrect
.right
: m_size
.cx
;
3192 r
.left
= !!s
->m_effects
[k
]->param
[1]
3193 ? (left
/*marginRect.left*/ - spaceNeeded
.cx
) + (int)(m_time
*8.0/s
->m_effects
[k
]->param
[0])
3194 : (right
/*- marginRect.right*/) - (int)(m_time
*8.0/s
->m_effects
[k
]->param
[0]);
3195 r
.right
= r
.left
+ spaceNeeded
.cx
;
3196 clipRect
&= CRect(left
>>3, clipRect
.top
, right
>>3, clipRect
.bottom
);
3197 fPosOverride
= true;
3200 case EF_SCROLL
: // Scroll up/down(toptobottom=param[3]);top=param[0];bottom=param[1];delay=param[2][;fadeawayheight=param[4]]
3202 r
.top
= !!s
->m_effects
[k
]->param
[3]
3203 ? s
->m_effects
[k
]->param
[0] + (int)(m_time
*8.0/s
->m_effects
[k
]->param
[2]) - spaceNeeded
.cy
3204 : s
->m_effects
[k
]->param
[1] - (int)(m_time
*8.0/s
->m_effects
[k
]->param
[2]);
3205 r
.bottom
= r
.top
+ spaceNeeded
.cy
;
3206 CRect
cr(0, (s
->m_effects
[k
]->param
[0] + 4) >> 3, spd
.w
, (s
->m_effects
[k
]->param
[1] + 4) >> 3);
3207 if(s
->m_relativeTo
== 1)
3208 r
.top
+= m_vidrect
.top
,
3209 r
.bottom
+= m_vidrect
.top
,
3210 cr
.top
+= m_vidrect
.top
>>3,
3211 cr
.bottom
+= m_vidrect
.top
>>3;
3213 fPosOverride
= true;
3220 if(!fPosOverride
&& !fOrgOverride
&& !s
->m_fAnimated
)
3221 r
= m_sla
.AllocRect(s
, segment
, entry
, stse
.layer
, m_collisions
);
3223 org
.x
= (s
->m_scrAlignment
%3) == 1 ? r
.left
: (s
->m_scrAlignment
%3) == 2 ? r
.CenterPoint().x
: r
.right
;
3224 org
.y
= s
->m_scrAlignment
<= 3 ? r
.bottom
: s
->m_scrAlignment
<= 6 ? r
.CenterPoint().y
: r
.top
;
3225 if(!fOrgOverride
) org2
= org
;
3226 SharedArrayByte pAlphaMask
;
3228 pAlphaMask
= s
->m_pClipper
->m_pAlphaMask
;
3229 CPoint p
, p2(0, r
.top
);
3232 // Rectangles for inverse clip
3234 iclipRect
[0] = CRect(0, 0, spd
.w
, clipRect
.top
);
3235 iclipRect
[1] = CRect(0, clipRect
.top
, clipRect
.left
, clipRect
.bottom
);
3236 iclipRect
[2] = CRect(clipRect
.right
, clipRect
.top
, spd
.w
, clipRect
.bottom
);
3237 iclipRect
[3] = CRect(0, clipRect
.bottom
, spd
.w
, spd
.h
);
3239 bbox2
= CRect(0,0,0,0);
3240 pos
= s
->GetHeadLinePosition();
3243 CLine
* l
= s
->GetNextLine(pos
);
3244 p
.x
= (s
->m_scrAlignment
%3) == 1 ? org
.x
3245 : (s
->m_scrAlignment
%3) == 0 ? org
.x
- l
->m_width
3246 : org
.x
- (l
->m_width
/2);
3248 CompositeDrawItemList tmpDrawItemList
;
3249 if (s
->m_clipInverse
)
3251 for (int i
=0;i
<l
->GetWordCount();i
++)
3253 tmpDrawItemList
.AddTail();
3254 tmpDrawItemList
.AddTail();
3255 tmpDrawItemList
.AddTail();
3256 tmpDrawItemList
.AddTail();
3258 bbox2
|= l
->PaintShadow(&tmpDrawItemList
, spd
, iclipRect
[0], pAlphaMask
, p
, org2
, m_time
, alpha
);
3259 bbox2
|= l
->PaintShadow(&tmpDrawItemList
, spd
, iclipRect
[1], pAlphaMask
, p
, org2
, m_time
, alpha
);
3260 bbox2
|= l
->PaintShadow(&tmpDrawItemList
, spd
, iclipRect
[2], pAlphaMask
, p
, org2
, m_time
, alpha
);
3261 bbox2
|= l
->PaintShadow(&tmpDrawItemList
, spd
, iclipRect
[3], pAlphaMask
, p
, org2
, m_time
, alpha
);
3263 bbox2
|= l
->PaintOutline(&tmpDrawItemList
, spd
, iclipRect
[0], pAlphaMask
, p
, org2
, m_time
, alpha
);
3264 bbox2
|= l
->PaintOutline(&tmpDrawItemList
, spd
, iclipRect
[1], pAlphaMask
, p
, org2
, m_time
, alpha
);
3265 bbox2
|= l
->PaintOutline(&tmpDrawItemList
, spd
, iclipRect
[2], pAlphaMask
, p
, org2
, m_time
, alpha
);
3266 bbox2
|= l
->PaintOutline(&tmpDrawItemList
, spd
, iclipRect
[3], pAlphaMask
, p
, org2
, m_time
, alpha
);
3268 bbox2
|= l
->PaintBody(&tmpDrawItemList
, spd
, iclipRect
[0], pAlphaMask
, p
, org2
, m_time
, alpha
);
3269 bbox2
|= l
->PaintBody(&tmpDrawItemList
, spd
, iclipRect
[1], pAlphaMask
, p
, org2
, m_time
, alpha
);
3270 bbox2
|= l
->PaintBody(&tmpDrawItemList
, spd
, iclipRect
[2], pAlphaMask
, p
, org2
, m_time
, alpha
);
3271 bbox2
|= l
->PaintBody(&tmpDrawItemList
, spd
, iclipRect
[3], pAlphaMask
, p
, org2
, m_time
, alpha
);
3275 for (int i
=0;i
<l
->GetWordCount();i
++)
3277 tmpDrawItemList
.AddTail();
3279 bbox2
|= l
->PaintShadow(&tmpDrawItemList
, spd
, clipRect
, pAlphaMask
, p
, org2
, m_time
, alpha
);
3281 bbox2
|= l
->PaintOutline(&tmpDrawItemList
, spd
, clipRect
, pAlphaMask
, p
, org2
, m_time
, alpha
);
3283 bbox2
|= l
->PaintBody(&tmpDrawItemList
, spd
, clipRect
, pAlphaMask
, p
, org2
, m_time
, alpha
);
3286 drawItemList
.AddTailList(&tmpDrawItemList
);
3287 p
.y
+= l
->m_ascent
+ l
->m_descent
;
3289 rectList
.AddTail(bbox2
);
3292 Draw(spd
, drawItemList
);
3293 return (subs
.GetCount() && !rectList
.IsEmpty()) ? S_OK
: S_FALSE
;
3297 STDMETHODIMP
CRenderedTextSubtitle::Render(SubPicDesc
& spd
, REFERENCE_TIME rt
, double fps
, RECT
& bbox
)
3299 CAtlList
<CRect
> rectList
;
3300 HRESULT result
= RenderEx(spd
, rt
, fps
, rectList
);
3301 POSITION pos
= rectList
.GetHeadPosition();
3302 CRect
bbox2(0,0,0,0);
3305 bbox2
|= rectList
.GetNext(pos
);
3313 STDMETHODIMP
CRenderedTextSubtitle::GetClassID(CLSID
* pClassID
)
3315 return pClassID
? *pClassID
= __uuidof(this), S_OK
: E_POINTER
;
3320 STDMETHODIMP_(int) CRenderedTextSubtitle::GetStreamCount()
3325 STDMETHODIMP
CRenderedTextSubtitle::GetStreamInfo(int iStream
, WCHAR
** ppName
, LCID
* pLCID
)
3327 if(iStream
!= 0) return E_INVALIDARG
;
3330 if(!(*ppName
= (WCHAR
*)CoTaskMemAlloc((m_name
.GetLength()+1)*sizeof(WCHAR
))))
3331 return E_OUTOFMEMORY
;
3332 wcscpy(*ppName
, CStringW(m_name
));
3341 STDMETHODIMP_(int) CRenderedTextSubtitle::GetStream()
3346 STDMETHODIMP
CRenderedTextSubtitle::SetStream(int iStream
)
3348 return iStream
== 0 ? S_OK
: E_FAIL
;
3351 STDMETHODIMP
CRenderedTextSubtitle::Reload()
3354 if(!CFile::GetStatus(m_path
, s
)) return E_FAIL
;
3355 return !m_path
.IsEmpty() && Open(m_path
, DEFAULT_CHARSET
) ? S_OK
: E_FAIL
;
3358 STDMETHODIMP_(bool) CRenderedTextSubtitle::IsColorTypeSupported( int type
)
3360 return type
==MSP_AY11
||
3366 void CRenderedTextSubtitle::Draw( SubPicDesc
& spd
, CompositeDrawItemList
& drawItemList
)
3368 POSITION pos
= drawItemList
.GetHeadPosition();
3371 CompositeDrawItem
& draw_item
= drawItemList
.GetNext(pos
);
3372 if(draw_item
.shadow
)
3373 Rasterizer::Draw( spd
, *draw_item
.shadow
);
3375 pos
= drawItemList
.GetHeadPosition();
3378 CompositeDrawItem
& draw_item
= drawItemList
.GetNext(pos
);
3379 if(draw_item
.outline
)
3380 Rasterizer::Draw( spd
, *draw_item
.outline
);
3382 pos
= drawItemList
.GetHeadPosition();
3385 CompositeDrawItem
& draw_item
= drawItemList
.GetNext(pos
);
3387 Rasterizer::Draw( spd
, *draw_item
.body
);