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 "../SubPic/MemSubPic.h"
27 #include "../subpic/color_conv_table.h"
29 // WARNING: this isn't very thread safe, use only one RTS a time.
31 static int g_hDC_refcnt
= 0;
33 //static OverlayCache g_overlay_cache;
34 const int OVERLAY_CACHE_ITEM_NUM
= 256;
35 const int WORD_CACHE_ITEM_NUM
= 512;
36 static OverlayMruCache
g_overlay_cache(OVERLAY_CACHE_ITEM_NUM
);
37 static CWordMruCache
g_word_cache(WORD_CACHE_ITEM_NUM
);
40 std::size_t hash_value(const CWord
& key
)
42 return( CStringElementTraits
<CString
>::Hash(key
.m_str
.get()) );
45 std::size_t hash_value(const CWordCacheKey
& key
)
47 return( CStringElementTraits
<CString
>::Hash(key
.m_str
.get()) );
50 std::size_t hash_value(const OverlayKey
& key
)
52 return( CStringElementTraits
<CString
>::Hash(key
.m_str
.get()) ^ key
.m_p
.x
^ key
.m_p
.y
);
55 enum XY_MSP_SUBTYPE
{XY_AYUV
, XY_AUYV
};
56 static inline DWORD
rgb2yuv(DWORD argb
, XY_MSP_SUBTYPE type
)
58 const ColorConvTable
* color_conv_table
= ColorConvTable::GetDefaultColorConvTable();
60 int r
= (argb
& 0x00ff0000) >> 16;
61 int g
= (argb
& 0x0000ff00) >> 8;
62 int b
= (argb
& 0x000000ff);
63 int y
= (color_conv_table
->c2y_cyb
* b
+ color_conv_table
->c2y_cyg
* g
+ color_conv_table
->c2y_cyr
* r
+ 0x108000) >> 16;
64 int scaled_y
= (y
-16) * color_conv_table
->cy_cy
;
65 int u
= ((((b
<<16) - scaled_y
) >> 10) * color_conv_table
->c2y_cu
+ 0x800000 + 0x8000) >> 16;
66 int v
= ((((r
<<16) - scaled_y
) >> 10) * color_conv_table
->c2y_cv
+ 0x800000 + 0x8000) >> 16;
67 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
));
69 u
= 255 - (255-u
)*(u
<256);
71 v
= 255 - (255-v
)*(v
<256);
72 DbgLog((LOG_TRACE
, 5, TEXT("u=%x v=%x"), u
, v
));
74 axxv
= (argb
& 0xff000000) | (y
<<16) | (u
<<8) | v
;
76 axxv
= (argb
& 0xff000000) | (y
<<8) | (u
<<16) | v
;
77 DbgLog((LOG_TRACE
, 5, TEXT("axxv=%x"), axxv
));
81 static long revcolor(long c
)
83 return ((c
&0xff0000)>>16) + (c
&0xff00) + ((c
&0xff)<<16);
86 //////////////////////////////////////////////////////////////////////////////////////////////
90 CMyFont::CMyFont(const FwSTSStyle
& style
)
93 memset(&lf
, 0, sizeof(lf
));
95 lf
.lfHeight
= (LONG
)(style
.get().fontSize
+0.5);
96 lf
.lfOutPrecision
= OUT_TT_PRECIS
;
97 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
98 lf
.lfQuality
= ANTIALIASED_QUALITY
;
99 lf
.lfPitchAndFamily
= DEFAULT_PITCH
|FF_DONTCARE
;
100 if(!CreateFontIndirect(&lf
))
102 _tcscpy(lf
.lfFaceName
, _T("Arial"));
103 CreateFontIndirect(&lf
);
105 HFONT hOldFont
= SelectFont(g_hDC
, *this);
107 GetTextMetrics(g_hDC
, &tm
);
108 m_ascent
= ((tm
.tmAscent
+ 4) >> 3);
109 m_descent
= ((tm
.tmDescent
+ 4) >> 3);
110 SelectFont(g_hDC
, hOldFont
);
115 CWord::CWord(const STSStyle
& style
, const CStringW
& str
, int ktype
, int kstart
, int kend
)
116 : m_style(style
), m_str(str
)
117 , m_width(0), m_ascent(0), m_descent(0)
118 , m_ktype(ktype
), m_kstart(kstart
), m_kend(kend
)
119 , m_fDrawn(false), m_p(INT_MAX
, INT_MAX
)
120 , m_fLineBreak(false), m_fWhiteSpaceChar(false)
123 if(m_str
.get().IsEmpty())
125 m_fWhiteSpaceChar
= m_fLineBreak
= true;
127 FwCMyFont
font(m_style
);
128 m_ascent
= (int)(m_style
.get().fontScaleY
/100*font
.get().m_ascent
);
129 m_descent
= (int)(m_style
.get().fontScaleY
/100*font
.get().m_descent
);
135 if(m_pOpaqueBox
) delete m_pOpaqueBox
;
138 bool CWord::Append(CWord
* w
)
140 if(!(m_style
== w
->m_style
)
141 || m_fLineBreak
|| w
->m_fLineBreak
142 || w
->m_kstart
!= w
->m_kend
|| m_ktype
!= w
->m_ktype
) return(false);
143 m_fWhiteSpaceChar
= m_fWhiteSpaceChar
&& w
->m_fWhiteSpaceChar
;
144 CStringW temp
= m_str
.get();
145 temp
+= w
->m_str
.get();
147 m_width
+= w
->m_width
;
149 m_p
= CPoint(INT_MAX
, INT_MAX
);
153 void CWord::Paint(CPoint p
, CPoint org
, OverlayList
* overlay_list
)
155 if(!m_str
.get() || overlay_list
==NULL
) return;
157 OverlayCompatibleKey::CompKey
comp_key(this, org
-p
);
158 bool need_transform
= NeedTransform();
161 comp_key
.p
.SetPoint(0,0);
163 const OverlayMruCache::hashed_cache
& overlay_cache
= g_overlay_cache
.get_hashed_cache();
164 const OverlayMruCache::hashed_cache::iterator iter
= overlay_cache
.find(comp_key
,OverlayCompatibleKey(),OverlayCompatibleKey());
165 if(iter
==overlay_cache
.end())
167 overlay_list
->overlay
= new Overlay();
170 if(!CreatePath()) return;
172 Transform(CPoint((org
.x
-p
.x
)*8, (org
.y
-p
.y
)*8));
173 if(!ScanConvert()) return;
174 if(m_style
.get().borderStyle
== 0 && (m_style
.get().outlineWidthX
+m_style
.get().outlineWidthY
> 0))
176 if(!CreateWidenedRegion((int)(m_style
.get().outlineWidthX
+0.5), (int)(m_style
.get().outlineWidthY
+0.5))) return;
178 else if(m_style
.get().borderStyle
== 1)
180 if(!CreateOpaqueBox()) return;
183 //if(!Rasterize(p.x&7, p.y&7, m_style.get().fBlur, m_style.get().fGaussianBlur, overlay_list->overlay)) return;
184 if(!Rasterize(0, 0, m_style
.get().fBlur
, m_style
.get().fGaussianBlur
, overlay_list
->overlay
)) return;
188 //Rasterize(p.x&7, p.y&7, m_style.get().fBlur, m_style.get().fGaussianBlur, overlay_list->overlay);
189 Rasterize(0, 0, m_style
.get().fBlur
, m_style
.get().fGaussianBlur
, overlay_list
->overlay
);
191 OverlayMruItem
item(comp_key
, overlay_list
->overlay
);
192 g_overlay_cache
.update_cache(item
);
196 overlay_list
->overlay
= iter
->overlay
;
201 overlay_list
->next
= new OverlayList();
202 m_pOpaqueBox
->Paint(p
, org
, overlay_list
->next
);
205 bool CWord::NeedTransform()
207 return (fabs(m_style
.get().fontScaleX
- 100) > 0.000001) ||
208 (fabs(m_style
.get().fontScaleY
- 100) > 0.000001) ||
209 (fabs(m_style
.get().fontAngleX
) > 0.000001) ||
210 (fabs(m_style
.get().fontAngleY
) > 0.000001) ||
211 (fabs(m_style
.get().fontAngleZ
) > 0.000001) ||
212 (fabs(m_style
.get().fontShiftX
) > 0.000001) ||
213 (fabs(m_style
.get().fontShiftY
) > 0.000001);
216 void CWord::Transform(CPoint org
)
220 bool fSSE2
= !!(g_cpuid
.m_flags
& CCpuID::sse2
);
222 if(fSSE2
) { // SSE code
229 void CWord::Transform_C( CPoint
&org
)
231 double scalex
= m_style
.get().fontScaleX
/100;
232 double scaley
= m_style
.get().fontScaleY
/100;
234 double caz
= cos((3.1415/180)*m_style
.get().fontAngleZ
);
235 double saz
= sin((3.1415/180)*m_style
.get().fontAngleZ
);
236 double cax
= cos((3.1415/180)*m_style
.get().fontAngleX
);
237 double sax
= sin((3.1415/180)*m_style
.get().fontAngleX
);
238 double cay
= cos((3.1415/180)*m_style
.get().fontAngleY
);
239 double say
= sin((3.1415/180)*m_style
.get().fontAngleY
);
242 // patch m003. random text points
243 double xrnd
= m_style
.get().mod_rand
.X
*100;
244 double yrnd
= m_style
.get().mod_rand
.Y
*100;
245 double zrnd
= m_style
.get().mod_rand
.Z
*100;
247 srand(m_style
.get().mod_rand
.Seed
);
249 // patch m008. distort
251 double dst1x
,dst1y
,dst2x
,dst2y
,dst3x
,dst3y
;
252 int minx
= INT_MAX
, miny
= INT_MAX
, maxx
= -INT_MAX
, maxy
= -INT_MAX
;
254 bool is_dist
= m_style
.get().mod_distort
.enabled
;
256 for(int i
= 0; i
< mPathPoints
; i
++) {
257 if(minx
> mpPathPoints
[i
].x
) {
258 minx
= mpPathPoints
[i
].x
;
260 if(miny
> mpPathPoints
[i
].y
) {
261 miny
= mpPathPoints
[i
].y
;
263 if(maxx
< mpPathPoints
[i
].x
) {
264 maxx
= mpPathPoints
[i
].x
;
266 if(maxy
< mpPathPoints
[i
].y
) {
267 maxy
= mpPathPoints
[i
].y
;
271 xsz
= max(maxx
- minx
, 0);
272 ysz
= max(maxy
- miny
, 0);
274 dst1x
= m_style
.get().mod_distort
.pointsx
[0];
275 dst1y
= m_style
.get().mod_distort
.pointsy
[0];
276 dst2x
= m_style
.get().mod_distort
.pointsx
[1];
277 dst2y
= m_style
.get().mod_distort
.pointsy
[1];
278 dst3x
= m_style
.get().mod_distort
.pointsx
[2];
279 dst3y
= m_style
.get().mod_distort
.pointsy
[2];
283 for (size_t i
= 0; i
< mPathPoints
; i
++) {
284 double x
, y
, z
, xx
, yy
, zz
;
286 x
= mpPathPoints
[i
].x
;
287 y
= mpPathPoints
[i
].y
;
289 // patch m002. Z-coord
290 z
= m_style
.get().mod_z
;
297 x
= minx
+(0 + (dst1x
- 0)*u
+ (dst3x
-0)*v
+(0+dst2x
-dst1x
-dst3x
)*u
*v
)*xsz
;
298 y
= miny
+(0 + (dst1y
- 0)*u
+ (dst3y
-0)*v
+(0+dst2y
-dst1y
-dst3y
)*u
*v
)*ysz
;
299 //P = P0 + (P1 - P0)u + (P3 - P0)v + (P0 + P2 - P1 - P3)uv
302 // patch m003. random text points
303 x
= xrnd
> 0 ? (xrnd
- rand() % (int)(xrnd
* 2 + 1)) / 100.0 + x
: x
;
304 y
= yrnd
> 0 ? (yrnd
- rand() % (int)(yrnd
* 2 + 1)) / 100.0 + y
: y
;
305 z
= zrnd
> 0 ? (zrnd
- rand() % (int)(zrnd
* 2 + 1)) / 100.0 + z
: z
;
310 x
= scalex
* (x
+ m_style
.get().fontShiftX
* y
) - org
.x
;
311 y
= scaley
* (y
+ m_style
.get().fontShiftY
* _x
) - org
.y
;
314 yy
= -(x
*saz
- y
*caz
);
325 zz
= max(zz
, -19000);
327 x
= (xx
* 20000) / (zz
+ 20000);
328 y
= (yy
* 20000) / (zz
+ 20000);
330 mpPathPoints
[i
].x
= (LONG
)(x
+ org
.x
+ 0.5);
331 mpPathPoints
[i
].y
= (LONG
)(y
+ org
.y
+ 0.5);
335 void CWord::Transform_SSE2( CPoint
&org
)
337 // __m128 union data type currently not supported with Intel C++ Compiler, so just call C version
342 // speed up ~1.5-1.7x
343 double scalex
= m_style
.get().fontScaleX
/100;
344 double scaley
= m_style
.get().fontScaleY
/100;
346 double caz
= cos((3.1415/180)*m_style
.get().fontAngleZ
);
347 double saz
= sin((3.1415/180)*m_style
.get().fontAngleZ
);
348 double cax
= cos((3.1415/180)*m_style
.get().fontAngleX
);
349 double sax
= sin((3.1415/180)*m_style
.get().fontAngleX
);
350 double cay
= cos((3.1415/180)*m_style
.get().fontAngleY
);
351 double say
= sin((3.1415/180)*m_style
.get().fontAngleY
);
353 __m128 __xshift
= _mm_set_ps1(m_style
.get().fontShiftX
);
354 __m128 __yshift
= _mm_set_ps1(m_style
.get().fontShiftY
);
356 __m128 __xorg
= _mm_set_ps1(org
.x
);
357 __m128 __yorg
= _mm_set_ps1(org
.y
);
359 __m128 __xscale
= _mm_set_ps1(scalex
);
360 __m128 __yscale
= _mm_set_ps1(scaley
);
363 // patch m003. random text points
364 double xrnd
= m_style
.get().mod_rand
.X
*100;
365 double yrnd
= m_style
.get().mod_rand
.Y
*100;
366 double zrnd
= m_style
.get().mod_rand
.Z
*100;
368 srand(m_style
.get().mod_rand
.Seed
);
370 __m128 __xsz
= _mm_setzero_ps();
371 __m128 __ysz
= _mm_setzero_ps();
373 __m128 __dst1x
, __dst1y
, __dst213x
, __dst213y
, __dst3x
, __dst3y
;
376 __m128 __minx
= _mm_set_ps(INT_MAX
, INT_MAX
, 0, 0);
377 __m128 __max
= _mm_set_ps(-INT_MAX
, -INT_MAX
, 1, 1);
379 bool is_dist
= m_style
.get().mod_distort
.enabled
;
381 for(int i
= 0; i
< mPathPoints
; i
++) {
382 __m128 __point
= _mm_set_ps(mpPathPoints
[i
].x
, mpPathPoints
[i
].y
, 0, 0);
383 __minx
= _mm_min_ps(__minx
, __point
);
384 __max
= _mm_max_ps(__max
, __point
);
387 __m128 __zero
= _mm_setzero_ps();
388 __max
= _mm_sub_ps(__max
, __minx
); // xsz, ysz, 1, 1
389 __max
= _mm_max_ps(__max
, __zero
);
391 __xsz
= _mm_shuffle_ps(__max
, __max
, _MM_SHUFFLE(3,3,3,3));
392 __ysz
= _mm_shuffle_ps(__max
, __max
, _MM_SHUFFLE(2,2,2,2));
394 __miny
= _mm_shuffle_ps(__minx
, __minx
, _MM_SHUFFLE(2,2,2,2));
395 __minx
= _mm_shuffle_ps(__minx
, __minx
, _MM_SHUFFLE(3,3,3,3));
397 __dst1x
= _mm_set_ps1(m_style
.get().mod_distort
.pointsx
[0]);
398 __dst1y
= _mm_set_ps1(m_style
.get().mod_distort
.pointsy
[0]);
399 __dst3x
= _mm_set_ps1(m_style
.get().mod_distort
.pointsx
[2]);
400 __dst3y
= _mm_set_ps1(m_style
.get().mod_distort
.pointsy
[2]);
401 __dst213x
= _mm_set_ps1(m_style
.get().mod_distort
.pointsx
[1]); // 2 - 1 - 3
402 __dst213x
= _mm_sub_ps(__dst213x
, __dst1x
);
403 __dst213x
= _mm_sub_ps(__dst213x
, __dst3x
);
405 __dst213y
= _mm_set_ps1(m_style
.get().mod_distort
.pointsy
[1]);
406 __dst213x
= _mm_sub_ps(__dst213y
, __dst1y
);
407 __dst213x
= _mm_sub_ps(__dst213y
, __dst3y
);
411 __m128 __caz
= _mm_set_ps1(caz
);
412 __m128 __saz
= _mm_set_ps1(saz
);
413 __m128 __cax
= _mm_set_ps1(cax
);
414 __m128 __sax
= _mm_set_ps1(sax
);
415 __m128 __cay
= _mm_set_ps1(cay
);
416 __m128 __say
= _mm_set_ps1(say
);
418 // this can be paralleled for openmp
419 int mPathPointsD4
= mPathPoints
/ 4;
420 int mPathPointsM4
= mPathPoints
% 4;
422 for(ptrdiff_t i
= 0; i
< mPathPointsD4
+ 1; i
++) {
423 __m128 __pointx
, __pointy
;
424 // we can't use load .-.
425 if(i
!= mPathPointsD4
) {
426 __pointx
= _mm_set_ps(mpPathPoints
[4 * i
+ 0].x
, mpPathPoints
[4 * i
+ 1].x
, mpPathPoints
[4 * i
+ 2].x
, mpPathPoints
[4 * i
+ 3].x
);
427 __pointy
= _mm_set_ps(mpPathPoints
[4 * i
+ 0].y
, mpPathPoints
[4 * i
+ 1].y
, mpPathPoints
[4 * i
+ 2].y
, mpPathPoints
[4 * i
+ 3].y
);
428 } else { // last cycle
429 switch(mPathPointsM4
) {
434 __pointx
= _mm_set_ps(mpPathPoints
[4 * i
+ 0].x
, 0, 0, 0);
435 __pointy
= _mm_set_ps(mpPathPoints
[4 * i
+ 0].y
, 0, 0, 0);
438 __pointx
= _mm_set_ps(mpPathPoints
[4 * i
+ 0].x
, mpPathPoints
[4 * i
+ 1].x
, 0, 0);
439 __pointy
= _mm_set_ps(mpPathPoints
[4 * i
+ 0].y
, mpPathPoints
[4 * i
+ 1].y
, 0, 0);
442 __pointx
= _mm_set_ps(mpPathPoints
[4 * i
+ 0].x
, mpPathPoints
[4 * i
+ 1].x
, mpPathPoints
[4 * i
+ 2].x
, 0);
443 __pointy
= _mm_set_ps(mpPathPoints
[4 * i
+ 0].y
, mpPathPoints
[4 * i
+ 1].y
, mpPathPoints
[4 * i
+ 2].y
, 0);
449 __m128 __pointz
= _mm_set_ps1(m_style
.get().mod_z
);
453 //P = P0 + (P1 - P0)u + (P3 - P0)v + (P0 + P2 - P1 - P3)uv
454 __m128 __u
= _mm_sub_ps(__pointx
, __minx
);
455 __m128 __v
= _mm_sub_ps(__pointy
, __miny
);
456 __m128 __1_xsz
= _mm_rcp_ps(__xsz
);
457 __m128 __1_ysz
= _mm_rcp_ps(__ysz
);
458 __u
= _mm_mul_ps(__u
, __1_xsz
);
459 __v
= _mm_mul_ps(__v
, __1_ysz
);
462 __pointx
= _mm_mul_ps(__dst213x
, __u
);
463 __pointx
= _mm_mul_ps(__pointx
, __v
);
465 __m128 __tmpx
= _mm_mul_ps(__dst3x
, __v
);
466 __pointx
= _mm_add_ps(__pointx
, __tmpx
);
467 __tmpx
= _mm_mul_ps(__dst1x
, __u
);
468 __pointx
= _mm_add_ps(__pointx
, __tmpx
);
470 __pointx
= _mm_mul_ps(__pointx
, __xsz
);
471 __pointx
= _mm_add_ps(__pointx
, __minx
);
474 __pointy
= _mm_mul_ps(__dst213y
, __u
);
475 __pointy
= _mm_mul_ps(__pointy
, __v
);
477 __m128 __tmpy
= _mm_mul_ps(__dst3y
, __v
);
478 __pointy
= _mm_add_ps(__pointy
, __tmpy
);
479 __tmpy
= _mm_mul_ps(__dst1y
, __u
);
480 __pointy
= _mm_add_ps(__pointy
, __tmpy
);
482 __pointy
= _mm_mul_ps(__pointy
, __ysz
);
483 __pointy
= _mm_add_ps(__pointy
, __miny
);
487 if(xrnd
!=0 || yrnd
!=0 || zrnd
!=0) {
488 __declspec(align(16)) float rx
[4], ry
[4], rz
[4];
489 for(int k
=0; k
<4; k
++) {
490 rx
[k
] = xrnd
> 0 ? (xrnd
- rand() % (int)(xrnd
* 2 + 1)) : 0;
491 ry
[k
] = yrnd
> 0 ? (yrnd
- rand() % (int)(yrnd
* 2 + 1)) : 0;
492 rz
[k
] = zrnd
> 0 ? (zrnd
- rand() % (int)(zrnd
* 2 + 1)) : 0;
494 __m128 __001
= _mm_set_ps1(0.01f
);
497 __m128 __rx
= _mm_load_ps(rx
);
498 __rx
= _mm_mul_ps(__rx
, __001
);
499 __pointx
= _mm_add_ps(__pointx
, __rx
);
503 __m128 __ry
= _mm_load_ps(ry
);
504 __ry
= _mm_mul_ps(__ry
, __001
);
505 __pointy
= _mm_add_ps(__pointy
, __ry
);
509 __m128 __rz
= _mm_load_ps(rz
);
510 __rz
= _mm_mul_ps(__rz
, __001
);
511 __pointz
= _mm_add_ps(__pointz
, __rz
);
515 __m128 __pointz
= _mm_set_ps1(0);
520 if(m_style
.get().fontShiftX
!=0) {
521 __tmpx
= _mm_mul_ps(__xshift
, __pointy
);
522 __tmpx
= _mm_add_ps(__tmpx
, __pointx
);
526 __tmpx
= _mm_mul_ps(__tmpx
, __xscale
);
527 __tmpx
= _mm_sub_ps(__tmpx
, __xorg
);
530 if(m_style
.get().fontShiftY
!=0) {
531 __tmpy
= _mm_mul_ps(__yshift
, __pointx
);
532 __tmpy
= _mm_add_ps(__tmpy
, __pointy
);
536 __tmpy
= _mm_mul_ps(__tmpy
, __yscale
);
537 __tmpy
= _mm_sub_ps(__tmpy
, __yorg
);
540 __m128 __xx
= _mm_mul_ps(__tmpx
, __caz
);
541 __m128 __yy
= _mm_mul_ps(__tmpy
, __saz
);
542 __pointx
= _mm_add_ps(__xx
, __yy
);
543 __xx
= _mm_mul_ps(__tmpx
, __saz
);
544 __yy
= _mm_mul_ps(__tmpy
, __caz
);
545 __pointy
= _mm_sub_ps(__yy
, __xx
);
547 __m128 __zz
= _mm_mul_ps(__pointz
, __sax
);
548 __yy
= _mm_mul_ps(__pointy
, __cax
);
549 __pointy
= _mm_add_ps(__yy
, __zz
);
550 __zz
= _mm_mul_ps(__pointz
, __cax
);
551 __yy
= _mm_mul_ps(__pointy
, __sax
);
552 __pointz
= _mm_sub_ps(__zz
, __yy
);
554 __xx
= _mm_mul_ps(__pointx
, __cay
);
555 __zz
= _mm_mul_ps(__pointz
, __say
);
556 __pointx
= _mm_add_ps(__xx
, __zz
);
557 __xx
= _mm_mul_ps(__pointx
, __say
);
558 __zz
= _mm_mul_ps(__pointz
, __cay
);
559 __pointz
= _mm_sub_ps(__xx
, __zz
);
561 __zz
= _mm_set_ps1(-19000);
562 __pointz
= _mm_max_ps(__pointz
, __zz
);
564 __m128 __20000
= _mm_set_ps1(20000);
565 __zz
= _mm_add_ps(__pointz
, __20000
);
566 __zz
= _mm_rcp_ps(__zz
);
568 __pointx
= _mm_mul_ps(__pointx
, __20000
);
569 __pointx
= _mm_mul_ps(__pointx
, __zz
);
571 __pointy
= _mm_mul_ps(__pointy
, __20000
);
572 __pointy
= _mm_mul_ps(__pointy
, __zz
);
574 __pointx
= _mm_add_ps(__pointx
, __xorg
);
575 __pointy
= _mm_add_ps(__pointy
, __yorg
);
577 __m128 __05
= _mm_set_ps1(0.5);
579 __pointx
= _mm_add_ps(__pointx
, __05
);
580 __pointy
= _mm_add_ps(__pointy
, __05
);
582 if(i
== mPathPointsD4
) { // last cycle
583 for(int k
=0; k
<mPathPointsM4
; k
++) {
584 mpPathPoints
[i
*4+k
].x
= static_cast<LONG
>(__pointx
.m128_f32
[3-k
]);
585 mpPathPoints
[i
*4+k
].y
= static_cast<LONG
>(__pointy
.m128_f32
[3-k
]);
588 for(int k
=0; k
<4; k
++) {
589 mpPathPoints
[i
*4+k
].x
= static_cast<LONG
>(__pointx
.m128_f32
[3-k
]);
590 mpPathPoints
[i
*4+k
].y
= static_cast<LONG
>(__pointy
.m128_f32
[3-k
]);
597 bool CWord::CreateOpaqueBox()
599 if(m_pOpaqueBox
) return(true);
600 STSStyle style
= m_style
.get();
601 style
.borderStyle
= 0;
602 style
.outlineWidthX
= style
.outlineWidthY
= 0;
603 style
.colors
[0] = m_style
.get().colors
[2];
604 style
.alpha
[0] = m_style
.get().alpha
[2];
605 int w
= (int)(m_style
.get().outlineWidthX
+ 0.5);
606 int h
= (int)(m_style
.get().outlineWidthY
+ 0.5);
608 str
.Format(L
"m %d %d l %d %d %d %d %d %d",
611 m_width
+w
, m_ascent
+m_descent
+h
,
612 -w
, m_ascent
+m_descent
+h
);
613 m_pOpaqueBox
= new CPolygon(FwSTSStyle(style
), str
, 0, 0, 0, 1.0/8, 1.0/8, 0);
614 return(!!m_pOpaqueBox
);
619 CText::CText(const STSStyle
& style
, const CStringW
& str
, int ktype
, int kstart
, int kend
)
620 : CWord(style
, str
, ktype
, kstart
, kend
)
624 m_fWhiteSpaceChar
= true;
626 FwCMyFont
font(m_style
);
627 HFONT hOldFont
= SelectFont(g_hDC
, font
.get());
628 if(m_style
.get().fontSpacing
|| (long)GetVersion() < 0)
630 bool bFirstPath
= true;
631 for(LPCWSTR s
= m_str
.get(); *s
; s
++)
634 if(!GetTextExtentPoint32W(g_hDC
, s
, 1, &extent
)) {SelectFont(g_hDC
, hOldFont
); ASSERT(0); return;}
635 m_width
+= extent
.cx
+ (int)m_style
.get().fontSpacing
;
637 // m_width -= (int)m_style.get().fontSpacing; // TODO: subtract only at the end of the line
642 if(!GetTextExtentPoint32W(g_hDC
, m_str
.get(), wcslen(m_str
.get()), &extent
)) {SelectFont(g_hDC
, hOldFont
); ASSERT(0); return;}
643 m_width
+= extent
.cx
;
645 m_width
= (int)(m_style
.get().fontScaleX
/100*m_width
+ 4) >> 3;
646 SelectFont(g_hDC
, hOldFont
);
651 return new CText(*this);
654 bool CText::Append(CWord
* w
)
656 return(dynamic_cast<CText
*>(w
) && CWord::Append(w
));
659 bool CText::CreatePath()
661 FwCMyFont
font(m_style
);
662 HFONT hOldFont
= SelectFont(g_hDC
, font
.get());
664 if(m_style
.get().fontSpacing
|| (long)GetVersion() < 0)
666 bool bFirstPath
= true;
667 for(LPCWSTR s
= m_str
.get(); *s
; s
++)
670 if(!GetTextExtentPoint32W(g_hDC
, s
, 1, &extent
)) {SelectFont(g_hDC
, hOldFont
); ASSERT(0); return(false);}
671 PartialBeginPath(g_hDC
, bFirstPath
);
673 TextOutW(g_hDC
, 0, 0, s
, 1);
674 PartialEndPath(g_hDC
, width
, 0);
675 width
+= extent
.cx
+ (int)m_style
.get().fontSpacing
;
681 if(!GetTextExtentPoint32W(g_hDC
, m_str
.get(), m_str
.get().GetLength(), &extent
)) {SelectFont(g_hDC
, hOldFont
); ASSERT(0); return(false);}
683 TextOutW(g_hDC
, 0, 0, m_str
.get(), m_str
.get().GetLength());
686 SelectFont(g_hDC
, hOldFont
);
692 CPolygon::CPolygon(const FwSTSStyle
& style
, CStringW str
, int ktype
, int kstart
, int kend
, double scalex
, double scaley
, int baseline
)
693 : CWord(style
.get(), str
, ktype
, kstart
, kend
)
694 , m_scalex(scalex
), m_scaley(scaley
), m_baseline(baseline
)
699 CPolygon::CPolygon(CPolygon
& src
) : CWord(src
.m_style
, src
.m_str
.get(), src
.m_ktype
, src
.m_kstart
, src
.m_kend
)
701 m_scalex
= src
.m_scalex
;
702 m_scaley
= src
.m_scaley
;
703 m_baseline
= src
.m_baseline
;
704 m_width
= src
.m_width
;
705 m_ascent
= src
.m_ascent
;
706 m_descent
= src
.m_descent
;
707 m_pathTypesOrg
.Copy(src
.m_pathTypesOrg
);
708 m_pathPointsOrg
.Copy(src
.m_pathPointsOrg
);
710 CPolygon::~CPolygon()
714 CWord
* CPolygon::Copy()
716 return(DNew
CPolygon(*this));
719 bool CPolygon::Append(CWord
* w
)
722 CPolygon
* p
= dynamic_cast<CPolygon
*>(w
);
723 if(!p
) return(false);
729 bool CPolygon::GetLONG(CStringW
& str
, LONG
& ret
)
731 LPWSTR s
= (LPWSTR
)(LPCWSTR
)str
, e
= s
;
732 ret
= wcstol(str
, &e
, 10);
733 str
= str
.Mid(e
- s
);
737 bool CPolygon::GetPOINT(CStringW
& str
, POINT
& ret
)
739 return(GetLONG(str
, ret
.x
) && GetLONG(str
, ret
.y
));
742 bool CPolygon::ParseStr()
744 if(m_pathTypesOrg
.GetCount() > 0) return(true);
746 int i
, j
, lastsplinestart
= -1, firstmoveto
= -1, lastmoveto
= -1;
747 CStringW str
= m_str
.get();
748 str
.SpanIncluding(L
"mnlbspc 0123456789");
749 str
.Replace(L
"m", L
"*m");
750 str
.Replace(L
"n", L
"*n");
751 str
.Replace(L
"l", L
"*l");
752 str
.Replace(L
"b", L
"*b");
753 str
.Replace(L
"s", L
"*s");
754 str
.Replace(L
"p", L
"*p");
755 str
.Replace(L
"c", L
"*c");
757 for(CStringW s
= str
.Tokenize(L
"*", k
); !s
.IsEmpty(); s
= str
.Tokenize(L
"*", k
))
760 s
.TrimLeft(L
"mnlbspc ");
764 lastmoveto
= m_pathTypesOrg
.GetCount();
765 if(firstmoveto
== -1) firstmoveto
= lastmoveto
;
766 while(GetPOINT(s
, p
)) {m_pathTypesOrg
.Add(PT_MOVETO
); m_pathPointsOrg
.Add(p
);}
769 while(GetPOINT(s
, p
)) {m_pathTypesOrg
.Add(PT_MOVETONC
); m_pathPointsOrg
.Add(p
);}
772 while(GetPOINT(s
, p
)) {m_pathTypesOrg
.Add(PT_LINETO
); m_pathPointsOrg
.Add(p
);}
775 j
= m_pathTypesOrg
.GetCount();
776 while(GetPOINT(s
, p
)) {m_pathTypesOrg
.Add(PT_BEZIERTO
); m_pathPointsOrg
.Add(p
); j
++;}
777 j
= m_pathTypesOrg
.GetCount() - ((m_pathTypesOrg
.GetCount()-j
)%3);
778 m_pathTypesOrg
.SetCount(j
);
779 m_pathPointsOrg
.SetCount(j
);
782 j
= lastsplinestart
= m_pathTypesOrg
.GetCount();
784 while(i
-- && GetPOINT(s
, p
)) {m_pathTypesOrg
.Add(PT_BSPLINETO
); m_pathPointsOrg
.Add(p
); j
++;}
785 if(m_pathTypesOrg
.GetCount()-lastsplinestart
< 3) {m_pathTypesOrg
.SetCount(lastsplinestart
); m_pathPointsOrg
.SetCount(lastsplinestart
); lastsplinestart
= -1;}
788 while(GetPOINT(s
, p
)) {m_pathTypesOrg
.Add(PT_BSPLINEPATCHTO
); m_pathPointsOrg
.Add(p
); j
++;}
791 if(lastsplinestart
> 0)
793 m_pathTypesOrg
.Add(PT_BSPLINEPATCHTO
);
794 m_pathTypesOrg
.Add(PT_BSPLINEPATCHTO
);
795 m_pathTypesOrg
.Add(PT_BSPLINEPATCHTO
);
796 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)
797 m_pathPointsOrg
.Add(p
);
798 p
= m_pathPointsOrg
[lastsplinestart
];
799 m_pathPointsOrg
.Add(p
);
800 p
= m_pathPointsOrg
[lastsplinestart
+1];
801 m_pathPointsOrg
.Add(p
);
802 lastsplinestart
= -1;
813 while(*str && *str != 'm' && *str != 'n' && *str != 'l' && *str != 'b' && *str != 's' && *str != 'p' && *str != 'c') str++;
820 lastmoveto = m_pathTypesOrg.GetCount();
821 if(firstmoveto == -1) firstmoveto = lastmoveto;
822 while(GetPOINT(str, p)) {m_pathTypesOrg.Add(PT_MOVETO); m_pathPointsOrg.Add(p);}
825 while(GetPOINT(str, p)) {m_pathTypesOrg.Add(PT_MOVETONC); m_pathPointsOrg.Add(p);}
828 while(GetPOINT(str, p)) {m_pathTypesOrg.Add(PT_LINETO); m_pathPointsOrg.Add(p);}
831 j = m_pathTypesOrg.GetCount();
832 while(GetPOINT(str, p)) {m_pathTypesOrg.Add(PT_BEZIERTO); m_pathPointsOrg.Add(p); j++;}
833 j = m_pathTypesOrg.GetCount() - ((m_pathTypesOrg.GetCount()-j)%3);
834 m_pathTypesOrg.SetCount(j); m_pathPointsOrg.SetCount(j);
837 j = lastsplinestart = m_pathTypesOrg.GetCount();
839 while(i-- && GetPOINT(str, p)) {m_pathTypesOrg.Add(PT_BSPLINETO); m_pathPointsOrg.Add(p); j++;}
840 if(m_pathTypesOrg.GetCount()-lastsplinestart < 3) {m_pathTypesOrg.SetCount(lastsplinestart); m_pathPointsOrg.SetCount(lastsplinestart); lastsplinestart = -1;}
843 while(GetPOINT(str, p)) {m_pathTypesOrg.Add(PT_BSPLINEPATCHTO); m_pathPointsOrg.Add(p); j++;}
846 if(lastsplinestart > 0)
848 m_pathTypesOrg.Add(PT_BSPLINEPATCHTO);
849 m_pathTypesOrg.Add(PT_BSPLINEPATCHTO);
850 m_pathTypesOrg.Add(PT_BSPLINEPATCHTO);
851 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)
852 m_pathPointsOrg.Add(p);
853 p = m_pathPointsOrg[lastsplinestart];
854 m_pathPointsOrg.Add(p);
855 p = m_pathPointsOrg[lastsplinestart+1];
856 m_pathPointsOrg.Add(p);
857 lastsplinestart = -1;
864 if(firstmoveto > 0) break;
867 if(lastmoveto
== -1 || firstmoveto
> 0)
869 m_pathTypesOrg
.RemoveAll();
870 m_pathPointsOrg
.RemoveAll();
873 int minx
= INT_MAX
, miny
= INT_MAX
, maxx
= -INT_MAX
, maxy
= -INT_MAX
;
874 for(i
= 0; i
< m_pathTypesOrg
.GetCount(); i
++)
876 m_pathPointsOrg
[i
].x
= (int)(64 * m_scalex
* m_pathPointsOrg
[i
].x
);
877 m_pathPointsOrg
[i
].y
= (int)(64 * m_scaley
* m_pathPointsOrg
[i
].y
);
878 if(minx
> m_pathPointsOrg
[i
].x
) minx
= m_pathPointsOrg
[i
].x
;
879 if(miny
> m_pathPointsOrg
[i
].y
) miny
= m_pathPointsOrg
[i
].y
;
880 if(maxx
< m_pathPointsOrg
[i
].x
) maxx
= m_pathPointsOrg
[i
].x
;
881 if(maxy
< m_pathPointsOrg
[i
].y
) maxy
= m_pathPointsOrg
[i
].y
;
883 m_width
= max(maxx
- minx
, 0);
884 m_ascent
= max(maxy
- miny
, 0);
885 int baseline
= (int)(64 * m_scaley
* m_baseline
);
886 m_descent
= baseline
;
887 m_ascent
-= baseline
;
888 m_width
= ((int)(m_style
.get().fontScaleX
/100 * m_width
) + 4) >> 3;
889 m_ascent
= ((int)(m_style
.get().fontScaleY
/100 * m_ascent
) + 4) >> 3;
890 m_descent
= ((int)(m_style
.get().fontScaleY
/100 * m_descent
) + 4) >> 3;
894 bool CPolygon::CreatePath()
896 int len
= m_pathTypesOrg
.GetCount();
897 if(len
== 0) return(false);
898 if(mPathPoints
!= len
)
900 mpPathTypes
= (BYTE
*)realloc(mpPathTypes
, len
*sizeof(BYTE
));
901 mpPathPoints
= (POINT
*)realloc(mpPathPoints
, len
*sizeof(POINT
));
902 if(!mpPathTypes
|| !mpPathPoints
) return(false);
905 memcpy(mpPathTypes
, m_pathTypesOrg
.GetData(), len
*sizeof(BYTE
));
906 memcpy(mpPathPoints
, m_pathPointsOrg
.GetData(), len
*sizeof(POINT
));
912 CClipper::CClipper(CStringW str
, CSize size
, double scalex
, double scaley
, bool inverse
)
913 : CPolygon(FwSTSStyle(), str
, 0, 0, 0, scalex
, scaley
, 0)
915 m_size
.cx
= m_size
.cy
= 0;
917 if(size
.cx
< 0 || size
.cy
< 0 || !(m_pAlphaMask
= new BYTE
[size
.cx
*size
.cy
])) return;
920 memset(m_pAlphaMask
, 0, size
.cx
*size
.cy
);
921 OverlayList overlay_list
;
922 Paint(CPoint(0, 0), CPoint(0, 0), &overlay_list
);
923 int w
= overlay_list
.overlay
->mOverlayWidth
, h
= overlay_list
.overlay
->mOverlayHeight
;
924 int x
= (overlay_list
.overlay
->mOffsetX
+4)>>3, y
= (overlay_list
.overlay
->mOffsetY
+4)>>3;
926 if(x
< 0) {xo
= -x
; w
-= -x
; x
= 0;}
927 if(y
< 0) {yo
= -y
; h
-= -y
; y
= 0;}
928 if(x
+w
> m_size
.cx
) w
= m_size
.cx
-x
;
929 if(y
+h
> m_size
.cy
) h
= m_size
.cy
-y
;
930 if(w
<= 0 || h
<= 0) return;
931 const BYTE
* src
= overlay_list
.overlay
->mpOverlayBuffer
.body
+ (overlay_list
.overlay
->mOverlayPitch
* yo
+ xo
);
932 BYTE
* dst
= m_pAlphaMask
+ m_size
.cx
* y
+ x
;
935 //for(int wt=0; wt<w; ++wt)
936 // dst[wt] = src[wt];
938 src
+= overlay_list
.overlay
->mOverlayPitch
;
943 BYTE
* dst
= m_pAlphaMask
;
944 for(int i
= size
.cx
*size
.cy
; i
>0; --i
, ++dst
)
945 *dst
= 0x40 - *dst
; // mask is 6 bit
949 CClipper::~CClipper()
951 if(m_pAlphaMask
) delete [] m_pAlphaMask
;
955 CWord
* CClipper::Copy()
957 return(new CClipper(m_str
.get(), m_size
, m_scalex
, m_scaley
, m_inverse
));
960 bool CClipper::Append(CWord
* w
)
969 //POSITION pos = GetHeadPosition();
970 //while(pos) delete GetNext(pos);
973 void CLine::Compact()
975 POSITION pos
= GetHeadPosition();
978 CWord
* w
= GetNext(pos
);
979 if(!w
->m_fWhiteSpaceChar
) break;
980 m_width
-= w
->m_width
;
984 pos
= GetTailPosition();
987 CWord
* w
= GetPrev(pos
);
988 if(!w
->m_fWhiteSpaceChar
) break;
989 m_width
-= w
->m_width
;
993 if(IsEmpty()) return;
998 pos
= l
.GetHeadPosition();
1001 CWord
* w
= l
.GetNext(pos
);
1002 if(!last
|| !last
->Append(w
))
1003 AddTail(last
= w
->Copy());
1005 m_ascent
= m_descent
= m_borderX
= m_borderY
= 0;
1006 pos
= GetHeadPosition();
1009 CWord
* w
= GetNext(pos
);
1010 if(m_ascent
< w
->m_ascent
) m_ascent
= w
->m_ascent
;
1011 if(m_descent
< w
->m_descent
) m_descent
= w
->m_descent
;
1012 if(m_borderX
< w
->m_style
.get().outlineWidthX
) m_borderX
= (int)(w
->m_style
.get().outlineWidthX
+0.5);
1013 if(m_borderY
< w
->m_style
.get().outlineWidthY
) m_borderY
= (int)(w
->m_style
.get().outlineWidthY
+0.5);
1017 CRect
CLine::PaintShadow(SubPicDesc
& spd
, CRect
& clipRect
, BYTE
* pAlphaMask
, CPoint p
, CPoint org
, int time
, int alpha
)
1019 CRect
bbox(0, 0, 0, 0);
1020 POSITION pos
= GetHeadPosition();
1023 CWord
* w
= GetNext(pos
);
1024 if(w
->m_fLineBreak
) return(bbox
); // should not happen since this class is just a line of text without any breaks
1025 if(w
->m_style
.get().shadowDepthX
!= 0 || w
->m_style
.get().shadowDepthY
!= 0)
1027 int x
= p
.x
+ (int)(w
->m_style
.get().shadowDepthX
+0.5);
1028 int y
= p
.y
+ m_ascent
- w
->m_ascent
+ (int)(w
->m_style
.get().shadowDepthY
+0.5);
1029 DWORD a
= 0xff - w
->m_style
.get().alpha
[3];
1030 if(alpha
> 0) a
= MulDiv(a
, 0xff - alpha
, 0xff);
1031 COLORREF shadow
= revcolor(w
->m_style
.get().colors
[3]) | (a
<<24);
1032 DWORD sw
[6] = {shadow
, -1};
1034 if(spd
.type
== MSP_YUY2
)
1036 sw
[0] =rgb2yuv(sw
[0], XY_AUYV
);
1038 else if(spd
.type
== MSP_AYUV
|| spd
.type
== MSP_YV12
|| spd
.type
== MSP_IYUV
)
1040 sw
[0] =rgb2yuv(sw
[0], XY_AYUV
);
1042 OverlayList overlay_list
;
1043 w
->Paint(CPoint(x
, y
), org
, &overlay_list
);
1044 if(w
->m_style
.get().borderStyle
== 0)
1046 bbox
|= w
->Draw(spd
, overlay_list
.overlay
, clipRect
, pAlphaMask
, x
, y
, sw
,
1047 w
->m_ktype
> 0 || w
->m_style
.get().alpha
[0] < 0xff,
1048 (w
->m_style
.get().outlineWidthX
+w
->m_style
.get().outlineWidthY
> 0) && !(w
->m_ktype
== 2 && time
< w
->m_kstart
));
1050 else if(w
->m_style
.get().borderStyle
== 1 && w
->m_pOpaqueBox
)
1052 bbox
|= w
->m_pOpaqueBox
->Draw(spd
, overlay_list
.next
->overlay
, clipRect
, pAlphaMask
, x
, y
, sw
, true, false);
1060 CRect
CLine::PaintOutline(SubPicDesc
& spd
, CRect
& clipRect
, BYTE
* pAlphaMask
, CPoint p
, CPoint org
, int time
, int alpha
)
1062 CRect
bbox(0, 0, 0, 0);
1063 POSITION pos
= GetHeadPosition();
1066 CWord
* w
= GetNext(pos
);
1067 if(w
->m_fLineBreak
) return(bbox
); // should not happen since this class is just a line of text without any breaks
1068 if(w
->m_style
.get().outlineWidthX
+w
->m_style
.get().outlineWidthY
> 0 && !(w
->m_ktype
== 2 && time
< w
->m_kstart
))
1071 int y
= p
.y
+ m_ascent
- w
->m_ascent
;
1072 DWORD aoutline
= w
->m_style
.get().alpha
[2];
1073 if(alpha
> 0) aoutline
+= MulDiv(alpha
, 0xff - w
->m_style
.get().alpha
[2], 0xff);
1074 COLORREF outline
= revcolor(w
->m_style
.get().colors
[2]) | ((0xff-aoutline
)<<24);
1075 DWORD sw
[6] = {outline
, -1};
1077 if(spd
.type
== MSP_YUY2
)
1079 sw
[0] =rgb2yuv(sw
[0], XY_AUYV
);
1081 else if(spd
.type
== MSP_AYUV
|| spd
.type
== MSP_YV12
|| spd
.type
== MSP_IYUV
)
1083 sw
[0] =rgb2yuv(sw
[0], XY_AYUV
);
1085 OverlayList overlay_list
;
1086 w
->Paint(CPoint(x
, y
), org
, &overlay_list
);
1087 if(w
->m_style
.get().borderStyle
== 0)
1089 bbox
|= w
->Draw(spd
, overlay_list
.overlay
, clipRect
, pAlphaMask
, x
, y
, sw
, !w
->m_style
.get().alpha
[0] && !w
->m_style
.get().alpha
[1] && !alpha
, true);
1091 else if(w
->m_style
.get().borderStyle
== 1 && w
->m_pOpaqueBox
)
1093 bbox
|= w
->m_pOpaqueBox
->Draw(spd
, overlay_list
.next
->overlay
, clipRect
, pAlphaMask
, x
, y
, sw
, true, false);
1101 CRect
CLine::PaintBody(SubPicDesc
& spd
, CRect
& clipRect
, BYTE
* pAlphaMask
, CPoint p
, CPoint org
, int time
, int alpha
)
1103 CRect
bbox(0, 0, 0, 0);
1104 POSITION pos
= GetHeadPosition();
1107 CWord
* w
= GetNext(pos
);
1108 if(w
->m_fLineBreak
) return(bbox
); // should not happen since this class is just a line of text without any breaks
1110 int y
= p
.y
+ m_ascent
- w
->m_ascent
;
1112 DWORD aprimary
= w
->m_style
.get().alpha
[0];
1113 if(alpha
> 0) aprimary
+= MulDiv(alpha
, 0xff - w
->m_style
.get().alpha
[0], 0xff);
1114 COLORREF primary
= revcolor(w
->m_style
.get().colors
[0]) | ((0xff-aprimary
)<<24);
1115 DWORD asecondary
= w
->m_style
.get().alpha
[1];
1116 if(alpha
> 0) asecondary
+= MulDiv(alpha
, 0xff - w
->m_style
.get().alpha
[1], 0xff);
1117 COLORREF secondary
= revcolor(w
->m_style
.get().colors
[1]) | ((0xff-asecondary
)<<24);
1118 DWORD sw
[6] = {primary
, 0, secondary
};
1121 if(w
->m_ktype
== 0 || w
->m_ktype
== 2)
1123 t
= time
< w
->m_kstart
? 0 : 1;
1125 else if(w
->m_ktype
== 1)
1127 if(time
< w
->m_kstart
) t
= 0;
1128 else if(time
< w
->m_kend
)
1130 t
= 1.0 * (time
- w
->m_kstart
) / (w
->m_kend
- w
->m_kstart
);
1131 double angle
= fmod(w
->m_style
.get().fontAngleZ
, 360.0);
1132 if(angle
> 90 && angle
< 270)
1135 COLORREF tmp
= sw
[0];
1146 sw
[3] = (int)(w
->m_style
.get().outlineWidthX
+ t
*w
->m_width
) >> 3;
1150 if(spd
.type
== MSP_YUY2
)
1152 sw
[0] =rgb2yuv(sw
[0], XY_AUYV
);
1153 sw
[2] =rgb2yuv(sw
[2], XY_AUYV
);
1154 sw
[4] =rgb2yuv(sw
[4], XY_AUYV
);
1156 else if(spd
.type
== MSP_AYUV
|| spd
.type
== MSP_YV12
|| spd
.type
== MSP_IYUV
)
1158 sw
[0] =rgb2yuv(sw
[0], XY_AYUV
);
1159 sw
[2] =rgb2yuv(sw
[2], XY_AYUV
);
1160 sw
[4] =rgb2yuv(sw
[4], XY_AYUV
);
1162 OverlayList overlay_list
;
1163 w
->Paint(CPoint(x
, y
), org
, &overlay_list
);
1164 bbox
|= w
->Draw(spd
, overlay_list
.overlay
, clipRect
, pAlphaMask
, x
, y
, sw
, true, false);
1173 CSubtitle::CSubtitle()
1175 memset(m_effects
, 0, sizeof(Effect
*)*EF_NUMBEROFEFFECTS
);
1177 m_clipInverse
= false;
1178 m_scalex
= m_scaley
= 1;
1181 CSubtitle::~CSubtitle()
1186 void CSubtitle::Empty()
1188 POSITION pos
= GetHeadPosition();
1189 while(pos
) delete GetNext(pos
);
1190 // pos = m_words.GetHeadPosition();
1191 // while(pos) delete m_words.GetNext(pos);
1192 for(int i
= 0; i
< EF_NUMBEROFEFFECTS
; i
++) {if(m_effects
[i
]) delete m_effects
[i
];}
1193 memset(m_effects
, 0, sizeof(Effect
*)*EF_NUMBEROFEFFECTS
);
1194 if(m_pClipper
) delete m_pClipper
;
1198 int CSubtitle::GetFullWidth()
1201 POSITION pos
= m_words
.GetHeadPosition();
1202 while(pos
) width
+= m_words
.GetNext(pos
)->m_width
;
1206 int CSubtitle::GetFullLineWidth(POSITION pos
)
1211 CWord
* w
= m_words
.GetNext(pos
);
1212 if(w
->m_fLineBreak
) break;
1213 width
+= w
->m_width
;
1218 int CSubtitle::GetWrapWidth(POSITION pos
, int maxwidth
)
1220 if(m_wrapStyle
== 0 || m_wrapStyle
== 3)
1224 // int fullwidth = GetFullWidth();
1225 int fullwidth
= GetFullLineWidth(pos
);
1226 int minwidth
= fullwidth
/ ((abs(fullwidth
) / maxwidth
) + 1);
1227 int width
= 0, wordwidth
= 0;
1228 while(pos
&& width
< minwidth
)
1230 CWord
* w
= m_words
.GetNext(pos
);
1231 wordwidth
= w
->m_width
;
1232 if(abs(width
+ wordwidth
) < abs(maxwidth
)) width
+= wordwidth
;
1235 if(m_wrapStyle
== 3 && pos
) maxwidth
-= wordwidth
;
1238 else if(m_wrapStyle
== 1)
1240 // maxwidth = maxwidth;
1242 else if(m_wrapStyle
== 2)
1249 CLine
* CSubtitle::GetNextLine(POSITION
& pos
, int maxwidth
)
1251 if(pos
== NULL
) return(NULL
);
1252 CLine
* ret
= new CLine();
1253 if(!ret
) return(NULL
);
1254 ret
->m_width
= ret
->m_ascent
= ret
->m_descent
= ret
->m_borderX
= ret
->m_borderY
= 0;
1255 maxwidth
= GetWrapWidth(pos
, maxwidth
);
1256 bool fEmptyLine
= true;
1259 CWord
* w
= m_words
.GetNext(pos
);
1260 if(ret
->m_ascent
< w
->m_ascent
) ret
->m_ascent
= w
->m_ascent
;
1261 if(ret
->m_descent
< w
->m_descent
) ret
->m_descent
= w
->m_descent
;
1262 if(ret
->m_borderX
< w
->m_style
.get().outlineWidthX
) ret
->m_borderX
= (int)(w
->m_style
.get().outlineWidthX
+0.5);
1263 if(ret
->m_borderY
< w
->m_style
.get().outlineWidthY
) ret
->m_borderY
= (int)(w
->m_style
.get().outlineWidthY
+0.5);
1266 if(fEmptyLine
) {ret
->m_ascent
/= 2; ret
->m_descent
/= 2; ret
->m_borderX
= ret
->m_borderY
= 0;}
1271 bool fWSC
= w
->m_fWhiteSpaceChar
;
1272 int width
= w
->m_width
;
1273 POSITION pos2
= pos
;
1276 if(m_words
.GetAt(pos2
)->m_fWhiteSpaceChar
!= fWSC
1277 || m_words
.GetAt(pos2
)->m_fLineBreak
) break;
1278 CWord
* w2
= m_words
.GetNext(pos2
);
1279 width
+= w2
->m_width
;
1281 if((ret
->m_width
+= width
) <= maxwidth
|| ret
->IsEmpty())
1283 ret
->AddTail(w
->Copy());
1286 ret
->AddTail(m_words
.GetNext(pos
)->Copy());
1292 if(pos
) m_words
.GetPrev(pos
);
1293 else pos
= m_words
.GetTailPosition();
1294 ret
->m_width
-= width
;
1302 void CSubtitle::CreateClippers(CSize size
)
1306 if(m_effects
[EF_BANNER
] && m_effects
[EF_BANNER
]->param
[2])
1308 int width
= m_effects
[EF_BANNER
]->param
[2];
1309 int w
= size
.cx
, h
= size
.cy
;
1313 str
.Format(L
"m %d %d l %d %d %d %d %d %d", 0, 0, w
, 0, w
, h
, 0, h
);
1314 m_pClipper
= new CClipper(str
, size
, 1, 1, false);
1315 if(!m_pClipper
) return;
1317 int da
= (64<<8)/width
;
1318 BYTE
* am
= m_pClipper
->m_pAlphaMask
;
1319 for(int j
= 0; j
< h
; j
++, am
+= w
)
1322 int k
= min(width
, w
);
1323 for(int i
= 0; i
< k
; i
++, a
+= da
)
1324 am
[i
] = (am
[i
]*a
)>>14;
1327 if(k
< 0) {a
-= -k
*da
; k
= 0;}
1328 for(int i
= k
; i
< w
; i
++, a
-= da
)
1329 am
[i
] = (am
[i
]*a
)>>14;
1332 else if(m_effects
[EF_SCROLL
] && m_effects
[EF_SCROLL
]->param
[4])
1334 int height
= m_effects
[EF_SCROLL
]->param
[4];
1335 int w
= size
.cx
, h
= size
.cy
;
1339 str
.Format(L
"m %d %d l %d %d %d %d %d %d", 0, 0, w
, 0, w
, h
, 0, h
);
1340 m_pClipper
= new CClipper(str
, size
, 1, 1, false);
1341 if(!m_pClipper
) return;
1343 int da
= (64<<8)/height
;
1345 int k
= m_effects
[EF_SCROLL
]->param
[0]>>3;
1347 if(k
< 0) {a
+= -k
*da
; k
= 0;}
1351 BYTE
* am
= &m_pClipper
->m_pAlphaMask
[k
*w
];
1352 memset(m_pClipper
->m_pAlphaMask
, 0, am
- m_pClipper
->m_pAlphaMask
);
1353 for(int j
= k
; j
< l
; j
++, a
+= da
)
1355 for(int i
= 0; i
< w
; i
++, am
++)
1356 *am
= ((*am
)*a
)>>14;
1359 da
= -(64<<8)/height
;
1361 l
= m_effects
[EF_SCROLL
]->param
[1]>>3;
1363 if(k
< 0) {a
+= -k
*da
; k
= 0;}
1367 BYTE
* am
= &m_pClipper
->m_pAlphaMask
[k
*w
];
1369 for(; j
< l
; j
++, a
+= da
)
1371 for(int i
= 0; i
< w
; i
++, am
++)
1372 *am
= ((*am
)*a
)>>14;
1374 memset(am
, 0, (h
-j
)*w
);
1379 void CSubtitle::MakeLines(CSize size
, CRect marginRect
)
1381 CSize
spaceNeeded(0, 0);
1382 bool fFirstLine
= true;
1383 m_topborder
= m_bottomborder
= 0;
1385 POSITION pos
= m_words
.GetHeadPosition();
1388 l
= GetNextLine(pos
, size
.cx
- marginRect
.left
- marginRect
.right
);
1390 if(fFirstLine
) {m_topborder
= l
->m_borderY
; fFirstLine
= false;}
1391 spaceNeeded
.cx
= max(l
->m_width
+l
->m_borderX
, spaceNeeded
.cx
);
1392 spaceNeeded
.cy
+= l
->m_ascent
+ l
->m_descent
;
1395 if(l
) m_bottomborder
= l
->m_borderY
;
1397 CPoint((m_scrAlignment
%3) == 1 ? marginRect
.left
1398 : (m_scrAlignment
%3) == 2 ? (marginRect
.left
+ (size
.cx
- marginRect
.right
) - spaceNeeded
.cx
+ 1) / 2
1399 : (size
.cx
- marginRect
.right
- spaceNeeded
.cx
),
1400 m_scrAlignment
<= 3 ? (size
.cy
- marginRect
.bottom
- spaceNeeded
.cy
)
1401 : m_scrAlignment
<= 6 ? (marginRect
.top
+ (size
.cy
- marginRect
.bottom
) - spaceNeeded
.cy
+ 1) / 2
1406 // CScreenLayoutAllocator
1408 void CScreenLayoutAllocator::Empty()
1410 m_subrects
.RemoveAll();
1413 void CScreenLayoutAllocator::AdvanceToSegment(int segment
, const CAtlArray
<int>& sa
)
1415 POSITION pos
= m_subrects
.GetHeadPosition();
1418 POSITION prev
= pos
;
1419 SubRect
& sr
= m_subrects
.GetNext(pos
);
1420 bool fFound
= false;
1421 if(abs(sr
.segment
- segment
) <= 1) // using abs() makes it possible to play the subs backwards, too :)
1423 for(int i
= 0; i
< sa
.GetCount() && !fFound
; i
++)
1425 if(sa
[i
] == sr
.entry
)
1427 sr
.segment
= segment
;
1432 if(!fFound
) m_subrects
.RemoveAt(prev
);
1436 CRect
CScreenLayoutAllocator::AllocRect(CSubtitle
* s
, int segment
, int entry
, int layer
, int collisions
)
1438 // TODO: handle collisions == 1 (reversed collisions)
1439 POSITION pos
= m_subrects
.GetHeadPosition();
1442 SubRect
& sr
= m_subrects
.GetNext(pos
);
1443 if(sr
.segment
== segment
&& sr
.entry
== entry
)
1445 return(sr
.r
+ CRect(0, -s
->m_topborder
, 0, -s
->m_bottomborder
));
1448 CRect r
= s
->m_rect
+ CRect(0, s
->m_topborder
, 0, s
->m_bottomborder
);
1449 bool fSearchDown
= s
->m_scrAlignment
> 3;
1454 pos
= m_subrects
.GetHeadPosition();
1457 SubRect
& sr
= m_subrects
.GetNext(pos
);
1458 if(layer
== sr
.layer
&& !(r
& sr
.r
).IsRectEmpty())
1462 r
.bottom
= sr
.r
.bottom
+ r
.Height();
1463 r
.top
= sr
.r
.bottom
;
1467 r
.top
= sr
.r
.top
- r
.Height();
1468 r
.bottom
= sr
.r
.top
;
1477 sr
.segment
= segment
;
1480 m_subrects
.AddTail(sr
);
1481 return(sr
.r
+ CRect(0, -s
->m_topborder
, 0, -s
->m_bottomborder
));
1484 // CRenderedTextSubtitle
1486 CAtlMap
<CStringW
, CRenderedTextSubtitle::AssCmdType
, CStringElementTraits
<CStringW
>> CRenderedTextSubtitle::m_cmdMap
;
1488 CRenderedTextSubtitle::CRenderedTextSubtitle(CCritSec
* pLock
)
1489 : ISubPicProviderImpl(pLock
)
1491 if( m_cmdMap
.IsEmpty() )
1495 m_size
= CSize(0, 0);
1496 if(g_hDC_refcnt
== 0)
1498 g_hDC
= CreateCompatibleDC(NULL
);
1499 SetBkMode(g_hDC
, TRANSPARENT
);
1500 SetTextColor(g_hDC
, 0xffffff);
1501 SetMapMode(g_hDC
, MM_TEXT
);
1506 CRenderedTextSubtitle::~CRenderedTextSubtitle()
1510 if(g_hDC_refcnt
== 0) DeleteDC(g_hDC
);
1513 void CRenderedTextSubtitle::InitCmdMap()
1515 if( m_cmdMap
.IsEmpty() )
1517 m_cmdMap
.SetAt(L
"1c", CMD_1c
);
1518 m_cmdMap
.SetAt(L
"2c", CMD_2c
);
1519 m_cmdMap
.SetAt(L
"3c", CMD_3c
);
1520 m_cmdMap
.SetAt(L
"4c", CMD_4c
);
1521 m_cmdMap
.SetAt(L
"1a", CMD_1a
);
1522 m_cmdMap
.SetAt(L
"2a", CMD_2a
);
1523 m_cmdMap
.SetAt(L
"3a", CMD_3a
);
1524 m_cmdMap
.SetAt(L
"4a", CMD_4a
);
1525 m_cmdMap
.SetAt(L
"alpha", CMD_alpha
);
1526 m_cmdMap
.SetAt(L
"an", CMD_an
);
1527 m_cmdMap
.SetAt(L
"a", CMD_a
);
1528 m_cmdMap
.SetAt(L
"blur", CMD_blur
);
1529 m_cmdMap
.SetAt(L
"bord", CMD_bord
);
1530 m_cmdMap
.SetAt(L
"be", CMD_be
);
1531 m_cmdMap
.SetAt(L
"b", CMD_b
);
1532 m_cmdMap
.SetAt(L
"clip", CMD_clip
);
1533 m_cmdMap
.SetAt(L
"iclip", CMD_iclip
);
1534 m_cmdMap
.SetAt(L
"c", CMD_c
);
1535 m_cmdMap
.SetAt(L
"fade", CMD_fade
);
1536 m_cmdMap
.SetAt(L
"fad", CMD_fad
);
1537 m_cmdMap
.SetAt(L
"fax", CMD_fax
);
1538 m_cmdMap
.SetAt(L
"fay", CMD_fay
);
1539 m_cmdMap
.SetAt(L
"fe", CMD_fe
);
1540 m_cmdMap
.SetAt(L
"fn", CMD_fn
);
1541 m_cmdMap
.SetAt(L
"frx", CMD_frx
);
1542 m_cmdMap
.SetAt(L
"fry", CMD_fry
);
1543 m_cmdMap
.SetAt(L
"frz", CMD_frz
);
1544 m_cmdMap
.SetAt(L
"fr", CMD_fr
);
1545 m_cmdMap
.SetAt(L
"fscx", CMD_fscx
);
1546 m_cmdMap
.SetAt(L
"fscy", CMD_fscy
);
1547 m_cmdMap
.SetAt(L
"fsc", CMD_fsc
);
1548 m_cmdMap
.SetAt(L
"fsp", CMD_fsp
);
1549 m_cmdMap
.SetAt(L
"fs", CMD_fs
);
1550 m_cmdMap
.SetAt(L
"i", CMD_i
);
1551 m_cmdMap
.SetAt(L
"kt", CMD_kt
);
1552 m_cmdMap
.SetAt(L
"kf", CMD_kf
);
1553 m_cmdMap
.SetAt(L
"K", CMD_K
);
1554 m_cmdMap
.SetAt(L
"ko", CMD_ko
);
1555 m_cmdMap
.SetAt(L
"k", CMD_k
);
1556 m_cmdMap
.SetAt(L
"move", CMD_move
);
1557 m_cmdMap
.SetAt(L
"org", CMD_org
);
1558 m_cmdMap
.SetAt(L
"pbo", CMD_pbo
);
1559 m_cmdMap
.SetAt(L
"pos", CMD_pos
);
1560 m_cmdMap
.SetAt(L
"p", CMD_p
);
1561 m_cmdMap
.SetAt(L
"q", CMD_q
);
1562 m_cmdMap
.SetAt(L
"r", CMD_r
);
1563 m_cmdMap
.SetAt(L
"shad", CMD_shad
);
1564 m_cmdMap
.SetAt(L
"s", CMD_s
);
1565 m_cmdMap
.SetAt(L
"t", CMD_t
);
1566 m_cmdMap
.SetAt(L
"u", CMD_u
);
1567 m_cmdMap
.SetAt(L
"xbord", CMD_xbord
);
1568 m_cmdMap
.SetAt(L
"xshad", CMD_xshad
);
1569 m_cmdMap
.SetAt(L
"ybord", CMD_ybord
);
1570 m_cmdMap
.SetAt(L
"yshad", CMD_yshad
);
1574 void CRenderedTextSubtitle::Copy(CSimpleTextSubtitle
& sts
)
1577 m_size
= CSize(0, 0);
1578 if(CRenderedTextSubtitle
* pRTS
= dynamic_cast<CRenderedTextSubtitle
*>(&sts
))
1580 m_size
= pRTS
->m_size
;
1584 void CRenderedTextSubtitle::Empty()
1590 void CRenderedTextSubtitle::OnChanged()
1592 __super::OnChanged();
1593 POSITION pos
= m_subtitleCache
.GetStartPosition();
1598 m_subtitleCache
.GetNextAssoc(pos
, i
, s
);
1601 m_subtitleCache
.RemoveAll();
1605 bool CRenderedTextSubtitle::Init(CSize size
, CRect vidrect
)
1608 m_size
= CSize(size
.cx
*8, size
.cy
*8);
1609 m_vidrect
= CRect(vidrect
.left
*8, vidrect
.top
*8, vidrect
.right
*8, vidrect
.bottom
*8);
1614 void CRenderedTextSubtitle::Deinit()
1616 POSITION pos
= m_subtitleCache
.GetStartPosition();
1621 m_subtitleCache
.GetNextAssoc(pos
, i
, s
);
1624 m_subtitleCache
.RemoveAll();
1626 m_size
= CSize(0, 0);
1627 m_vidrect
.SetRectEmpty();
1629 g_word_cache
.clear();
1630 g_overlay_cache
.clear();
1633 void CRenderedTextSubtitle::ParseEffect(CSubtitle
* sub
, CString str
)
1636 if(!sub
|| str
.IsEmpty()) return;
1637 const TCHAR
* s
= _tcschr(str
, ';');
1638 if(!s
) {s
= (LPTSTR
)(LPCTSTR
)str
; s
+= str
.GetLength()-1;}
1640 CString effect
= str
.Left(s
- str
);
1641 if(!effect
.CompareNoCase(_T("Banner;")))
1643 int delay
, lefttoright
= 0, fadeawaywidth
= 0;
1644 if(_stscanf(s
, _T("%d;%d;%d"), &delay
, &lefttoright
, &fadeawaywidth
) < 1) return;
1645 Effect
* e
= new Effect
;
1647 sub
->m_effects
[e
->type
= EF_BANNER
] = e
;
1648 e
->param
[0] = (int)(max(1.0*delay
/sub
->m_scalex
, 1));
1649 e
->param
[1] = lefttoright
;
1650 e
->param
[2] = (int)(sub
->m_scalex
*fadeawaywidth
);
1651 sub
->m_wrapStyle
= 2;
1653 else if(!effect
.CompareNoCase(_T("Scroll up;")) || !effect
.CompareNoCase(_T("Scroll down;")))
1655 int top
, bottom
, delay
, fadeawayheight
= 0;
1656 if(_stscanf(s
, _T("%d;%d;%d;%d"), &top
, &bottom
, &delay
, &fadeawayheight
) < 3) return;
1657 if(top
> bottom
) {int tmp
= top
; top
= bottom
; bottom
= tmp
;}
1658 Effect
* e
= new Effect
;
1660 sub
->m_effects
[e
->type
= EF_SCROLL
] = e
;
1661 e
->param
[0] = (int)(sub
->m_scaley
*top
*8);
1662 e
->param
[1] = (int)(sub
->m_scaley
*bottom
*8);
1663 e
->param
[2] = (int)(max(1.0*delay
/sub
->m_scaley
, 1));
1664 e
->param
[3] = (effect
.GetLength() == 12);
1665 e
->param
[4] = (int)(sub
->m_scaley
*fadeawayheight
);
1669 void CRenderedTextSubtitle::ParseString(CSubtitle
* sub
, CStringW str
, const FwSTSStyle
& style
)
1672 str
.Replace(L
"\\N", L
"\n");
1673 str
.Replace(L
"\\n", (sub
->m_wrapStyle
< 2 || sub
->m_wrapStyle
== 3) ? L
" " : L
"\n");
1674 str
.Replace(L
"\\h", L
"\x00A0");
1675 for(int ite
= 0, j
= 0, len
= str
.GetLength(); j
<= len
; j
++)
1678 if(c
!= L
'\n' && c
!= L
' ' && c
!= L
'\x00A0' && c
!= 0)
1682 CWordCacheKey
word_cache_key(style
, str
.Mid(ite
, j
-ite
), m_ktype
, m_kstart
, m_kend
);
1683 const CWordMruCache::hashed_cache
& word_cache
= g_word_cache
.get_hashed_cache();
1684 const CWordMruCache::hashed_cache::iterator iter
= word_cache
.find(word_cache_key
);
1685 if( iter
!= word_cache
.end() )
1687 sub
->m_words
.AddTail(iter
->word
);
1689 else if(CWord
* w
= new CText(style
, str
.Mid(ite
, j
-ite
), m_ktype
, m_kstart
, m_kend
))
1691 sub
->m_words
.AddTail(w
);
1692 CWordMruItem
item(word_cache_key
, w
);
1693 g_word_cache
.update_cache(item
);
1697 ///TODO: overflow handling
1703 CWordCacheKey
word_cache_key(style
, CStringW(), m_ktype
, m_kstart
, m_kend
);
1704 const CWordMruCache::hashed_cache
& word_cache
= g_word_cache
.get_hashed_cache();
1705 const CWordMruCache::hashed_cache::iterator iter
= word_cache
.find(word_cache_key
);
1706 if( iter
!= word_cache
.end() )
1708 sub
->m_words
.AddTail(iter
->word
);
1710 else if(CWord
* w
= new CText(style
, CStringW(), m_ktype
, m_kstart
, m_kend
))
1712 sub
->m_words
.AddTail(w
);
1713 CWordMruItem
item(word_cache_key
, w
);
1714 g_word_cache
.update_cache(item
);
1718 ///TODO: overflow handling
1722 else if(c
== L
' ' || c
== L
'\x00A0')
1724 CWordCacheKey
word_cache_key(style
, CStringW(c
), m_ktype
, m_kstart
, m_kend
);
1725 const CWordMruCache::hashed_cache
& word_cache
= g_word_cache
.get_hashed_cache();
1726 const CWordMruCache::hashed_cache::iterator iter
= word_cache
.find(word_cache_key
);
1727 if( iter
!= word_cache
.end() )
1729 sub
->m_words
.AddTail(iter
->word
);
1731 else if(CWord
* w
= new CText(style
, CStringW(c
), m_ktype
, m_kstart
, m_kend
))
1733 sub
->m_words
.AddTail(w
);
1734 CWordMruItem
item(word_cache_key
, w
);
1735 g_word_cache
.update_cache(item
);
1739 ///TODO: overflow handling
1748 void CRenderedTextSubtitle::ParsePolygon(CSubtitle
* sub
, CStringW str
, const FwSTSStyle
& style
)
1750 if(!sub
|| !str
.GetLength() || !m_nPolygon
) return;
1752 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
))
1755 //if( CWord* w_cache = m_wordCache.lookup(*w) )
1757 // sub->m_words.AddTail(w_cache);
1762 sub
->m_words
.AddTail(w
);
1768 bool CRenderedTextSubtitle::ParseSSATag(CSubtitle
* sub
, CStringW str
, STSStyle
& style
, const STSStyle
& org
, bool fAnimate
)
1770 if(!sub
) return(false);
1771 int nTags
= 0, nUnrecognizedTags
= 0;
1772 for(int i
= 0, j
; (j
= str
.Find(L
'\\', i
)) >= 0; i
= j
)
1775 for(WCHAR c
= str
[++j
]; c
&& c
!= L
'(' && c
!= L
'\\'; cmd
+= c
, c
= str
[++j
]);
1777 if(cmd
.IsEmpty()) continue;
1778 CAtlArray
<CStringW
> params
;
1782 for(WCHAR c
= str
[++j
]; c
&& c
!= L
')'; param
+= c
, c
= str
[++j
]);
1784 while(!param
.IsEmpty())
1786 int i
= param
.Find(L
','), j
= param
.Find(L
'\\');
1787 if(i
>= 0 && (j
< 0 || i
< j
))
1789 CStringW s
= param
.Left(i
).Trim();
1790 if(!s
.IsEmpty()) params
.Add(s
);
1791 param
= i
+1 < param
.GetLength() ? param
.Mid(i
+1) : L
"";
1796 if(!param
.IsEmpty()) params
.Add(param
);
1802 AssCmdType cmd_type
= CMD_COUNT
;
1803 int cmd_length
= min(MAX_CMD_LENGTH
, cmd
.GetLength());
1804 for( ;cmd_length
>=MIN_CMD_LENGTH
;cmd_length
-- )
1806 if( m_cmdMap
.Lookup(cmd
.Left(cmd_length
), cmd_type
) )
1809 if(cmd_length
<MIN_CMD_LENGTH
)
1810 cmd_type
= CMD_COUNT
;
1850 params
.Add(cmd
.Mid(cmd_length
));
1862 params
.Add(cmd
.Mid(cmd_length
).Trim(L
"&H"));
1874 nUnrecognizedTags
++;
1878 // TODO: call ParseStyleModifier(cmd, params, ..) and move the rest there
1879 CStringW p
= params
.GetCount() > 0 ? params
[0] : L
"";
1887 int i
= cmd
[0] - L
'1';
1888 DWORD c
= wcstol(p
, NULL
, 16);
1889 style
.colors
[i
] = !p
.IsEmpty()
1890 ? (((int)CalcAnimation(c
&0xff, style
.colors
[i
]&0xff, fAnimate
))&0xff
1891 |((int)CalcAnimation(c
&0xff00, style
.colors
[i
]&0xff00, fAnimate
))&0xff00
1892 |((int)CalcAnimation(c
&0xff0000, style
.colors
[i
]&0xff0000, fAnimate
))&0xff0000)
1901 int i
= cmd
[0] - L
'1';
1902 style
.alpha
[i
] = !p
.IsEmpty()
1903 ? (BYTE
)CalcAnimation(wcstol(p
, NULL
, 16), style
.alpha
[i
], fAnimate
)
1909 for(int i
= 0; i
< 4; i
++)
1911 style
.alpha
[i
] = !p
.IsEmpty()
1912 ? (BYTE
)CalcAnimation(wcstol(p
, NULL
, 16), style
.alpha
[i
], fAnimate
)
1919 int n
= wcstol(p
, NULL
, 10);
1920 if(sub
->m_scrAlignment
< 0)
1921 sub
->m_scrAlignment
= (n
> 0 && n
< 10) ? n
: org
.scrAlignment
;
1926 int n
= wcstol(p
, NULL
, 10);
1927 if(sub
->m_scrAlignment
< 0)
1928 sub
->m_scrAlignment
= (n
> 0 && n
< 12) ? ((((n
-1)&3)+1)+((n
&4)?6:0)+((n
&8)?3:0)) : org
.scrAlignment
;
1933 double n
= CalcAnimation(wcstod(p
, NULL
), style
.fGaussianBlur
, fAnimate
);
1934 style
.fGaussianBlur
= !p
.IsEmpty()
1936 : org
.fGaussianBlur
;
1941 double dst
= wcstod(p
, NULL
);
1942 double nx
= CalcAnimation(dst
, style
.outlineWidthX
, fAnimate
);
1943 style
.outlineWidthX
= !p
.IsEmpty()
1945 : org
.outlineWidthX
;
1946 double ny
= CalcAnimation(dst
, style
.outlineWidthY
, fAnimate
);
1947 style
.outlineWidthY
= !p
.IsEmpty()
1949 : org
.outlineWidthY
;
1954 int n
= (int)(CalcAnimation(wcstol(p
, NULL
, 10), style
.fBlur
, fAnimate
)+0.5);
1955 style
.fBlur
= !p
.IsEmpty()
1962 int n
= wcstol(p
, NULL
, 10);
1963 style
.fontWeight
= !p
.IsEmpty()
1964 ? (n
== 0 ? FW_NORMAL
: n
== 1 ? FW_BOLD
: n
>= 100 ? n
: org
.fontWeight
)
1971 bool invert
= (cmd_type
== CMD_iclip
);
1972 if(params
.GetCount() == 1 && !sub
->m_pClipper
)
1974 sub
->m_pClipper
= new CClipper(params
[0], CSize(m_size
.cx
>>3, m_size
.cy
>>3), sub
->m_scalex
, sub
->m_scaley
, invert
);
1976 else if(params
.GetCount() == 2 && !sub
->m_pClipper
)
1978 int scale
= max(wcstol(p
, NULL
, 10), 1);
1979 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
);
1981 else if(params
.GetCount() == 4)
1984 sub
->m_clipInverse
= invert
;
1986 wcstol(params
[0], NULL
, 10),
1987 wcstol(params
[1], NULL
, 10),
1988 wcstol(params
[2], NULL
, 10),
1989 wcstol(params
[3], NULL
, 10));
1991 if(sub
->m_relativeTo
== 1) // TODO: this should also apply to the other two clippings above
1993 o
.x
= m_vidrect
.left
>>3;
1994 o
.y
= m_vidrect
.top
>>3;
1996 sub
->m_clip
.SetRect(
1997 (int)CalcAnimation(sub
->m_scalex
*r
.left
+ o
.x
, sub
->m_clip
.left
, fAnimate
),
1998 (int)CalcAnimation(sub
->m_scaley
*r
.top
+ o
.y
, sub
->m_clip
.top
, fAnimate
),
1999 (int)CalcAnimation(sub
->m_scalex
*r
.right
+ o
.x
, sub
->m_clip
.right
, fAnimate
),
2000 (int)CalcAnimation(sub
->m_scaley
*r
.bottom
+ o
.y
, sub
->m_clip
.bottom
, fAnimate
));
2006 DWORD c
= wcstol(p
, NULL
, 16);
2007 style
.colors
[0] = !p
.IsEmpty()
2008 ? (((int)CalcAnimation(c
&0xff, style
.colors
[0]&0xff, fAnimate
))&0xff
2009 |((int)CalcAnimation(c
&0xff00, style
.colors
[0]&0xff00, fAnimate
))&0xff00
2010 |((int)CalcAnimation(c
&0xff0000, style
.colors
[0]&0xff0000, fAnimate
))&0xff0000)
2017 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])
2019 if(Effect
* e
= new Effect
)
2021 for(int i
= 0; i
< 3; i
++)
2022 e
->param
[i
] = wcstol(params
[i
], NULL
, 10);
2023 for(int i
= 0; i
< 4; i
++)
2024 e
->t
[i
] = wcstol(params
[3+i
], NULL
, 10);
2025 sub
->m_effects
[EF_FADE
] = e
;
2028 else if(params
.GetCount() == 2 && !sub
->m_effects
[EF_FADE
]) // {\fad(t1=t[1], t2=t[2])
2030 if(Effect
* e
= new Effect
)
2032 e
->param
[0] = e
->param
[2] = 0xff;
2034 for(int i
= 1; i
< 3; i
++)
2035 e
->t
[i
] = wcstol(params
[i
-1], NULL
, 10);
2036 e
->t
[0] = e
->t
[3] = -1; // will be substituted with "start" and "end"
2037 sub
->m_effects
[EF_FADE
] = e
;
2044 style
.fontShiftX
= !p
.IsEmpty()
2045 ? CalcAnimation(wcstod(p
, NULL
), style
.fontShiftX
, fAnimate
)
2051 style
.fontShiftY
= !p
.IsEmpty()
2052 ? CalcAnimation(wcstod(p
, NULL
), style
.fontShiftY
, fAnimate
)
2058 int n
= wcstol(p
, NULL
, 10);
2059 style
.charSet
= !p
.IsEmpty()
2066 if(!p
.IsEmpty() && p
!= L
'0')
2067 style
.fontName
= CString(p
).Trim();
2069 style
.fontName
= org
.fontName
;
2074 style
.fontAngleX
= !p
.IsEmpty()
2075 ? CalcAnimation(wcstod(p
, NULL
), style
.fontAngleX
, fAnimate
)
2081 style
.fontAngleY
= !p
.IsEmpty()
2082 ? CalcAnimation(wcstod(p
, NULL
), style
.fontAngleY
, fAnimate
)
2089 style
.fontAngleZ
= !p
.IsEmpty()
2090 ? CalcAnimation(wcstod(p
, NULL
), style
.fontAngleZ
, fAnimate
)
2096 double n
= CalcAnimation(wcstol(p
, NULL
, 10), style
.fontScaleX
, fAnimate
);
2097 style
.fontScaleX
= !p
.IsEmpty()
2104 double n
= CalcAnimation(wcstol(p
, NULL
, 10), style
.fontScaleY
, fAnimate
);
2105 style
.fontScaleY
= !p
.IsEmpty()
2112 style
.fontScaleX
= org
.fontScaleX
;
2113 style
.fontScaleY
= org
.fontScaleY
;
2118 style
.fontSpacing
= !p
.IsEmpty()
2119 ? CalcAnimation(wcstod(p
, NULL
), style
.fontSpacing
, fAnimate
)
2127 if(p
[0] == L
'-' || p
[0] == L
'+')
2129 double n
= CalcAnimation(style
.fontSize
+ style
.fontSize
*wcstol(p
, NULL
, 10)/10, style
.fontSize
, fAnimate
);
2130 style
.fontSize
= (n
> 0) ? n
: org
.fontSize
;
2134 double n
= CalcAnimation(wcstol(p
, NULL
, 10), style
.fontSize
, fAnimate
);
2135 style
.fontSize
= (n
> 0) ? n
: org
.fontSize
;
2140 style
.fontSize
= org
.fontSize
;
2146 int n
= wcstol(p
, NULL
, 10);
2147 style
.fItalic
= !p
.IsEmpty()
2148 ? (n
== 0 ? false : n
== 1 ? true : org
.fItalic
)
2154 m_kstart
= !p
.IsEmpty()
2155 ? wcstol(p
, NULL
, 10)*10
2159 sub
->m_fAnimated
= true;//fix me: define m_fAnimated m_fAnimated2 strictly
2166 m_kend
+= !p
.IsEmpty()
2167 ? wcstol(p
, NULL
, 10)*10
2169 sub
->m_fAnimated
= true;//fix me: define m_fAnimated m_fAnimated2 strictly
2176 m_kend
+= !p
.IsEmpty()
2177 ? wcstol(p
, NULL
, 10)*10
2179 sub
->m_fAnimated
= true;//fix me: define m_fAnimated m_fAnimated2 strictly
2186 m_kend
+= !p
.IsEmpty()
2187 ? wcstol(p
, NULL
, 10)*10
2189 sub
->m_fAnimated
= true;//fix me: define m_fAnimated m_fAnimated2 strictly
2192 case CMD_move
: // {\move(x1=param[0], y1=param[1], x2=param[2], y2=param[3][, t1=t[0], t2=t[1]])}
2194 if((params
.GetCount() == 4 || params
.GetCount() == 6) && !sub
->m_effects
[EF_MOVE
])
2196 if(Effect
* e
= new Effect
)
2198 e
->param
[0] = (int)(sub
->m_scalex
*wcstod(params
[0], NULL
)*8);
2199 e
->param
[1] = (int)(sub
->m_scaley
*wcstod(params
[1], NULL
)*8);
2200 e
->param
[2] = (int)(sub
->m_scalex
*wcstod(params
[2], NULL
)*8);
2201 e
->param
[3] = (int)(sub
->m_scaley
*wcstod(params
[3], NULL
)*8);
2202 e
->t
[0] = e
->t
[1] = -1;
2203 if(params
.GetCount() == 6)
2205 for(int i
= 0; i
< 2; i
++)
2206 e
->t
[i
] = wcstol(params
[4+i
], NULL
, 10);
2208 sub
->m_effects
[EF_MOVE
] = e
;
2213 case CMD_org
: // {\org(x=param[0], y=param[1])}
2215 if(params
.GetCount() == 2 && !sub
->m_effects
[EF_ORG
])
2217 if(Effect
* e
= new Effect
)
2219 e
->param
[0] = (int)(sub
->m_scalex
*wcstod(params
[0], NULL
)*8);
2220 e
->param
[1] = (int)(sub
->m_scaley
*wcstod(params
[1], NULL
)*8);
2221 sub
->m_effects
[EF_ORG
] = e
;
2228 m_polygonBaselineOffset
= wcstol(p
, NULL
, 10);
2233 if(params
.GetCount() == 2 && !sub
->m_effects
[EF_MOVE
])
2235 if(Effect
* e
= new Effect
)
2237 e
->param
[0] = e
->param
[2] = (int)(sub
->m_scalex
*wcstod(params
[0], NULL
)*8);
2238 e
->param
[1] = e
->param
[3] = (int)(sub
->m_scaley
*wcstod(params
[1], NULL
)*8);
2239 e
->t
[0] = e
->t
[1] = 0;
2240 sub
->m_effects
[EF_MOVE
] = e
;
2247 int n
= wcstol(p
, NULL
, 10);
2248 m_nPolygon
= (n
<= 0 ? 0 : n
);
2253 int n
= wcstol(p
, NULL
, 10);
2254 sub
->m_wrapStyle
= !p
.IsEmpty() && (0 <= n
&& n
<= 3)
2256 : m_defaultWrapStyle
;
2262 style
= (!p
.IsEmpty() && m_styles
.Lookup(FwString(WToT(p
)), val
) && val
) ? *val
: org
;
2267 double dst
= wcstod(p
, NULL
);
2268 double nx
= CalcAnimation(dst
, style
.shadowDepthX
, fAnimate
);
2269 style
.shadowDepthX
= !p
.IsEmpty()
2272 double ny
= CalcAnimation(dst
, style
.shadowDepthY
, fAnimate
);
2273 style
.shadowDepthY
= !p
.IsEmpty()
2280 int n
= wcstol(p
, NULL
, 10);
2281 style
.fStrikeOut
= !p
.IsEmpty()
2282 ? (n
== 0 ? false : n
== 1 ? true : org
.fStrikeOut
)
2286 case CMD_t
: // \t([<t1>,<t2>,][<accel>,]<style modifiers>)
2289 m_animStart
= m_animEnd
= 0;
2291 if(params
.GetCount() == 1)
2295 else if(params
.GetCount() == 2)
2297 m_animAccel
= wcstod(params
[0], NULL
);
2300 else if(params
.GetCount() == 3)
2302 m_animStart
= (int)wcstod(params
[0], NULL
);
2303 m_animEnd
= (int)wcstod(params
[1], NULL
);
2306 else if(params
.GetCount() == 4)
2308 m_animStart
= wcstol(params
[0], NULL
, 10);
2309 m_animEnd
= wcstol(params
[1], NULL
, 10);
2310 m_animAccel
= wcstod(params
[2], NULL
);
2313 ParseSSATag(sub
, p
, style
, org
, true);
2314 sub
->m_fAnimated
= true;
2319 int n
= wcstol(p
, NULL
, 10);
2320 style
.fUnderline
= !p
.IsEmpty()
2321 ? (n
== 0 ? false : n
== 1 ? true : org
.fUnderline
)
2327 double dst
= wcstod(p
, NULL
);
2328 double nx
= CalcAnimation(dst
, style
.outlineWidthX
, fAnimate
);
2329 style
.outlineWidthX
= !p
.IsEmpty()
2331 : org
.outlineWidthX
;
2336 double dst
= wcstod(p
, NULL
);
2337 double nx
= CalcAnimation(dst
, style
.shadowDepthX
, fAnimate
);
2338 style
.shadowDepthX
= !p
.IsEmpty()
2345 double dst
= wcstod(p
, NULL
);
2346 double ny
= CalcAnimation(dst
, style
.outlineWidthY
, fAnimate
);
2347 style
.outlineWidthY
= !p
.IsEmpty()
2349 : org
.outlineWidthY
;
2354 double dst
= wcstod(p
, NULL
);
2355 double ny
= CalcAnimation(dst
, style
.shadowDepthY
, fAnimate
);
2356 style
.shadowDepthY
= !p
.IsEmpty()
2365 // return(nUnrecognizedTags < nTags);
2366 return(true); // there are ppl keeping coments inside {}, lets make them happy now
2369 bool CRenderedTextSubtitle::ParseHtmlTag(CSubtitle
* sub
, CStringW str
, STSStyle
& style
, STSStyle
& org
)
2371 if(str
.Find(L
"!--") == 0)
2373 bool fClosing
= str
[0] == L
'/';
2375 int i
= str
.Find(L
' ');
2376 if(i
< 0) i
= str
.GetLength();
2377 CStringW tag
= str
.Left(i
).MakeLower();
2378 str
= str
.Mid(i
).Trim();
2379 CAtlArray
<CStringW
> attribs
, params
;
2380 while((i
= str
.Find(L
'=')) > 0)
2382 attribs
.Add(str
.Left(i
).Trim().MakeLower());
2384 for(i
= 0; _istspace(str
[i
]); i
++);
2386 if(str
[0] == L
'\"') {str
= str
.Mid(1); i
= str
.Find(L
'\"');}
2387 else i
= str
.Find(L
' ');
2388 if(i
< 0) i
= str
.GetLength();
2389 params
.Add(str
.Left(i
).Trim().MakeLower());
2394 else if(tag
== L
"b" || tag
== L
"strong")
2395 style
.fontWeight
= !fClosing
? FW_BOLD
: org
.fontWeight
;
2396 else if(tag
== L
"i" || tag
== L
"em")
2397 style
.fItalic
= !fClosing
? true : org
.fItalic
;
2398 else if(tag
== L
"u")
2399 style
.fUnderline
= !fClosing
? true : org
.fUnderline
;
2400 else if(tag
== L
"s" || tag
== L
"strike" || tag
== L
"del")
2401 style
.fStrikeOut
= !fClosing
? true : org
.fStrikeOut
;
2402 else if(tag
== L
"font")
2406 for(i
= 0; i
< attribs
.GetCount(); i
++)
2408 if(params
[i
].IsEmpty()) continue;
2410 if(attribs
[i
] == L
"face")
2412 style
.fontName
= params
[i
];
2414 else if(attribs
[i
] == L
"size")
2416 if(params
[i
][0] == L
'+')
2417 style
.fontSize
+= wcstol(params
[i
], NULL
, 10);
2418 else if(params
[i
][0] == L
'-')
2419 style
.fontSize
-= wcstol(params
[i
], NULL
, 10);
2421 style
.fontSize
= wcstol(params
[i
], NULL
, 10);
2423 else if(attribs
[i
] == L
"color")
2427 else if(attribs
[i
] == L
"outline-color")
2431 else if(attribs
[i
] == L
"outline-level")
2433 style
.outlineWidthX
= style
.outlineWidthY
= wcstol(params
[i
], NULL
, 10);
2435 else if(attribs
[i
] == L
"shadow-color")
2439 else if(attribs
[i
] == L
"shadow-level")
2441 style
.shadowDepthX
= style
.shadowDepthY
= wcstol(params
[i
], NULL
, 10);
2443 if(nColor
>= 0 && nColor
< 4)
2445 CString key
= WToT(params
[i
]).TrimLeft(L
'#');
2447 if(g_colors
.Lookup(key
, val
))
2448 style
.colors
[nColor
] = val
;
2449 else if((style
.colors
[nColor
] = _tcstol(key
, NULL
, 16)) == 0)
2450 style
.colors
[nColor
] = 0x00ffffff; // default is white
2451 style
.colors
[nColor
] = ((style
.colors
[nColor
]>>16)&0xff)|((style
.colors
[nColor
]&0xff)<<16)|(style
.colors
[nColor
]&0x00ff00);
2457 style
.fontName
= org
.fontName
;
2458 style
.fontSize
= org
.fontSize
;
2459 memcpy(style
.colors
, org
.colors
, sizeof(style
.colors
));
2462 else if(tag
== L
"k" && attribs
.GetCount() == 1 && attribs
[0] == L
"t")
2466 m_kend
+= wcstol(params
[0], NULL
, 10);
2473 double CRenderedTextSubtitle::CalcAnimation(double dst
, double src
, bool fAnimate
)
2475 int s
= m_animStart
? m_animStart
: 0;
2476 int e
= m_animEnd
? m_animEnd
: m_delay
;
2477 if(fabs(dst
-src
) >= 0.0001 && fAnimate
)
2479 if(m_time
< s
) dst
= src
;
2480 else if(s
<= m_time
&& m_time
< e
)
2482 double t
= pow(1.0 * (m_time
- s
) / (e
- s
), m_animAccel
);
2483 dst
= (1 - t
) * src
+ t
* dst
;
2490 CSubtitle
* CRenderedTextSubtitle::GetSubtitle(int entry
)
2493 if(m_subtitleCache
.Lookup(entry
, sub
))
2495 if(sub
->m_fAnimated
) {delete sub
; sub
= NULL
;}
2498 sub
= new CSubtitle();
2499 if(!sub
) return(NULL
);
2500 CStringW str
= GetStrW(entry
, true);
2501 STSStyle stss
, orgstss
;
2502 GetStyle(entry
, &stss
);
2503 if (stss
.fontScaleX
== stss
.fontScaleY
&& m_dPARCompensation
!= 1.0)
2505 switch(m_ePARCompensationType
)
2508 if (m_dPARCompensation
< 1.0)
2509 stss
.fontScaleY
/= m_dPARCompensation
;
2511 stss
.fontScaleX
*= m_dPARCompensation
;
2514 if (m_dPARCompensation
< 1.0)
2515 stss
.fontScaleX
*= m_dPARCompensation
;
2517 stss
.fontScaleY
/= m_dPARCompensation
;
2519 case EPCTAccurateSize
:
2520 stss
.fontScaleX
*= m_dPARCompensation
;
2525 sub
->m_clip
.SetRect(0, 0, m_size
.cx
>>3, m_size
.cy
>>3);
2526 sub
->m_scrAlignment
= -stss
.scrAlignment
;
2527 sub
->m_wrapStyle
= m_defaultWrapStyle
;
2528 sub
->m_fAnimated
= false;
2529 sub
->m_relativeTo
= stss
.relativeTo
;
2530 sub
->m_scalex
= m_dstScreenSize
.cx
> 0 ? 1.0 * (stss
.relativeTo
== 1 ? m_vidrect
.Width() : m_size
.cx
) / (m_dstScreenSize
.cx
*8) : 1.0;
2531 sub
->m_scaley
= m_dstScreenSize
.cy
> 0 ? 1.0 * (stss
.relativeTo
== 1 ? m_vidrect
.Height() : m_size
.cy
) / (m_dstScreenSize
.cy
*8) : 1.0;
2532 m_animStart
= m_animEnd
= 0;
2534 m_ktype
= m_kstart
= m_kend
= 0;
2536 m_polygonBaselineOffset
= 0;
2537 ParseEffect(sub
, GetAt(entry
).effect
);
2538 while(!str
.IsEmpty())
2540 bool fParsed
= false;
2542 if(str
[0] == L
'{' && (i
= str
.Find(L
'}')) > 0)
2544 if(fParsed
= ParseSSATag(sub
, str
.Mid(1, i
-1), stss
, orgstss
))
2547 else if(str
[0] == L
'<' && (i
= str
.Find(L
'>')) > 0)
2549 if(fParsed
= ParseHtmlTag(sub
, str
.Mid(1, i
-1), stss
, orgstss
))
2554 i
= str
.FindOneOf(L
"{<");
2555 if(i
< 0) i
= str
.GetLength();
2556 if(i
== 0) continue;
2560 i
= str
.Mid(1).FindOneOf(L
"{<");
2561 if(i
< 0) i
= str
.GetLength()-1;
2564 STSStyle tmp
= stss
;
2565 tmp
.fontSize
= sub
->m_scaley
*tmp
.fontSize
*64;
2566 tmp
.fontSpacing
= sub
->m_scalex
*tmp
.fontSpacing
*64;
2567 tmp
.outlineWidthX
*= (m_fScaledBAS
? sub
->m_scalex
: 1) * 8;
2568 tmp
.outlineWidthY
*= (m_fScaledBAS
? sub
->m_scaley
: 1) * 8;
2569 tmp
.shadowDepthX
*= (m_fScaledBAS
? sub
->m_scalex
: 1) * 8;
2570 tmp
.shadowDepthY
*= (m_fScaledBAS
? sub
->m_scaley
: 1) * 8;
2571 FwSTSStyle
fw_tmp(tmp
);
2574 ParsePolygon(sub
, str
.Left(i
), fw_tmp
);
2578 ParseString(sub
, str
.Left(i
), fw_tmp
);
2582 sub
->m_fAnimated2
= sub
->m_fAnimated
;
2583 if(sub
->m_effects
[EF_FADE
] || sub
->m_effects
[EF_BANNER
] || sub
->m_effects
[EF_SCROLL
]
2584 || (sub
->m_effects
[EF_MOVE
] && (sub
->m_effects
[EF_MOVE
]->t
[1]!=sub
->m_effects
[EF_MOVE
]->t
[0])))
2585 sub
->m_fAnimated2
= true;
2586 // just a "work-around" solution... in most cases nobody will want to use \org together with moving but without rotating the subs
2587 if(sub
->m_effects
[EF_ORG
] && (sub
->m_effects
[EF_MOVE
] || sub
->m_effects
[EF_BANNER
] || sub
->m_effects
[EF_SCROLL
]))
2588 sub
->m_fAnimated
= true;
2589 sub
->m_scrAlignment
= abs(sub
->m_scrAlignment
);
2590 STSEntry stse
= GetAt(entry
);
2591 CRect marginRect
= stse
.marginRect
;
2592 if(marginRect
.left
== 0) marginRect
.left
= orgstss
.marginRect
.get().left
;
2593 if(marginRect
.top
== 0) marginRect
.top
= orgstss
.marginRect
.get().top
;
2594 if(marginRect
.right
== 0) marginRect
.right
= orgstss
.marginRect
.get().right
;
2595 if(marginRect
.bottom
== 0) marginRect
.bottom
= orgstss
.marginRect
.get().bottom
;
2596 marginRect
.left
= (int)(sub
->m_scalex
*marginRect
.left
*8);
2597 marginRect
.top
= (int)(sub
->m_scaley
*marginRect
.top
*8);
2598 marginRect
.right
= (int)(sub
->m_scalex
*marginRect
.right
*8);
2599 marginRect
.bottom
= (int)(sub
->m_scaley
*marginRect
.bottom
*8);
2600 if(stss
.relativeTo
== 1)
2602 marginRect
.left
+= m_vidrect
.left
;
2603 marginRect
.top
+= m_vidrect
.top
;
2604 marginRect
.right
+= m_size
.cx
- m_vidrect
.right
;
2605 marginRect
.bottom
+= m_size
.cy
- m_vidrect
.bottom
;
2607 sub
->CreateClippers(m_size
);
2608 sub
->MakeLines(m_size
, marginRect
);
2609 m_subtitleCache
[entry
] = sub
;
2615 STDMETHODIMP
CRenderedTextSubtitle::NonDelegatingQueryInterface(REFIID riid
, void** ppv
)
2617 CheckPointer(ppv
, E_POINTER
);
2623 __super::NonDelegatingQueryInterface(riid
, ppv
);
2628 STDMETHODIMP_(POSITION
) CRenderedTextSubtitle::GetStartPosition(REFERENCE_TIME rt
, double fps
)
2630 //DbgLog((LOG_TRACE, 3, "rt:%lu", (ULONG)rt/10000));
2631 m_fps
= fps
;//fix me: check is fps changed and do some re-init thing
2633 int subIndex
= 1;//If a segment has animate effect then it corresponds to several subpics.
2634 //subIndex, 1 based, indicates which subpic the result corresponds to.
2636 const STSSegment
*stss
= SearchSubs((int)rt
, fps
, &iSegment
, NULL
);
2639 else if(stss
->animated
)
2641 int start
= TranslateSegmentStart(iSegment
, fps
);
2643 subIndex
= (rt
-start
)/RTS_ANIMATE_SUBPIC_DUR
+ 1;
2645 //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));
2646 return (POSITION
)(subIndex
| (iSegment
<<RTS_POS_SEGMENT_INDEX_BITS
));
2647 //if(iSegment < 0) iSegment = 0;
2648 //return(GetNext((POSITION)iSegment));
2651 STDMETHODIMP_(POSITION
) CRenderedTextSubtitle::GetNext(POSITION pos
)
2653 int iSegment
= ((int)pos
>>RTS_POS_SEGMENT_INDEX_BITS
);
2654 int subIndex
= ((int)pos
& RTS_POS_SUB_INDEX_MASK
);
2655 const STSSegment
*stss
= GetSegment(iSegment
);
2656 ASSERT(stss
!=NULL
&& stss
->subs
.GetCount()>0);
2657 //DbgLog((LOG_TRACE, 3, "stss:%x count:%d", stss, stss->subs.GetCount()));
2666 TranslateSegmentStartEnd(iSegment
, m_fps
, start
, end
);
2667 if(start
+RTS_ANIMATE_SUBPIC_DUR
*subIndex
< end
)
2675 if(GetSegment(iSegment
) != NULL
)
2677 ASSERT(GetSegment(iSegment
)->subs
.GetCount()>0);
2678 return (POSITION
)(subIndex
| (iSegment
<<RTS_POS_SEGMENT_INDEX_BITS
));
2684 //@return: <0 if segment not found
2685 STDMETHODIMP_(REFERENCE_TIME
) CRenderedTextSubtitle::GetStart(POSITION pos
, double fps
)
2687 //return(10000i64 * TranslateSegmentStart((int)pos-1, fps));
2688 int iSegment
= ((int)pos
>>RTS_POS_SEGMENT_INDEX_BITS
);
2689 int subIndex
= ((int)pos
& RTS_POS_SUB_INDEX_MASK
);
2690 int start
= TranslateSegmentStart(iSegment
, fps
);
2691 const STSSegment
*stss
= GetSegment(iSegment
);
2694 return (start
+ (subIndex
-1)*RTS_ANIMATE_SUBPIC_DUR
)*10000i64
;
2702 //@return: <0 if segment not found
2703 STDMETHODIMP_(REFERENCE_TIME
) CRenderedTextSubtitle::GetStop(POSITION pos
, double fps
)
2705 // return(10000i64 * TranslateSegmentEnd((int)pos-1, fps));
2706 int iSegment
= ((int)pos
>>RTS_POS_SEGMENT_INDEX_BITS
);
2707 int subIndex
= ((int)pos
& RTS_POS_SUB_INDEX_MASK
);
2708 int start
, end
, ret
;
2709 TranslateSegmentStartEnd(iSegment
, fps
, start
, end
);
2710 const STSSegment
*stss
= GetSegment(iSegment
);
2717 ret
= start
+subIndex
*RTS_ANIMATE_SUBPIC_DUR
;
2721 return ret
*10000i64
;
2727 //@start, @stop: -1 if segment not found; @stop may < @start if subIndex exceed uppper bound
2728 STDMETHODIMP_(VOID
) CRenderedTextSubtitle::GetStartStop(POSITION pos
, double fps
, /*out*/REFERENCE_TIME
&start
, /*out*/REFERENCE_TIME
&stop
)
2730 int iSegment
= ((int)pos
>>RTS_POS_SEGMENT_INDEX_BITS
);
2731 int subIndex
= ((int)pos
& RTS_POS_SUB_INDEX_MASK
);
2732 int tempStart
, tempEnd
;
2733 TranslateSegmentStartEnd(iSegment
, fps
, tempStart
, tempEnd
);
2736 const STSSegment
*stss
= GetSegment(iSegment
);
2741 start
+= (subIndex
-1)*RTS_ANIMATE_SUBPIC_DUR
;
2742 if(start
+RTS_ANIMATE_SUBPIC_DUR
< stop
)
2743 stop
= start
+RTS_ANIMATE_SUBPIC_DUR
;
2745 //DbgLog((LOG_TRACE, 3, "animated:%d seg:%d idx:%d start:%d stop:%lu", stss->animated, iSegment, subIndex, (ULONG)start, (ULONG)stop));
2756 STDMETHODIMP_(bool) CRenderedTextSubtitle::IsAnimated(POSITION pos
)
2758 int iSegment
= ((int)pos
>>RTS_POS_SEGMENT_INDEX_BITS
);
2759 if(iSegment
>=0 && iSegment
<m_segments
.GetCount())
2760 return m_segments
[iSegment
].animated
;
2766 struct LSub
{int idx
, layer
, readorder
;};
2768 static int lscomp(const void* ls1
, const void* ls2
)
2770 int ret
= ((LSub
*)ls1
)->layer
- ((LSub
*)ls2
)->layer
;
2771 if(!ret
) ret
= ((LSub
*)ls1
)->readorder
- ((LSub
*)ls2
)->readorder
;
2775 STDMETHODIMP
CRenderedTextSubtitle::Render(SubPicDesc
& spd
, REFERENCE_TIME rt
, double fps
, CAtlList
<CRect
>& rectList
)
2777 CRect
bbox2(0,0,0,0);
2778 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))
2779 Init(CSize(spd
.w
, spd
.h
), spd
.vidrect
);
2780 int t
= (int)(rt
/ 10000);
2783 STSSegment
* stss
= SearchSubs2(t
, fps
, &segment
);
2784 if(!stss
) return S_FALSE
;
2785 // clear any cached subs not in the range of +/-30secs measured from the segment's bounds
2787 POSITION pos
= m_subtitleCache
.GetStartPosition();
2792 m_subtitleCache
.GetNextAssoc(pos
, key
, value
);
2793 STSEntry
& stse
= GetAt(key
);
2794 if(stse
.end
<= (t
-30000) || stse
.start
> (t
+30000))
2797 m_subtitleCache
.RemoveKey(key
);
2798 pos
= m_subtitleCache
.GetStartPosition();
2802 m_sla
.AdvanceToSegment(segment
, stss
->subs
);
2803 CAtlArray
<LSub
> subs
;
2804 for(int i
= 0, j
= stss
->subs
.GetCount(); i
< j
; i
++)
2807 ls
.idx
= stss
->subs
[i
];
2808 ls
.layer
= GetAt(stss
->subs
[i
]).layer
;
2809 ls
.readorder
= GetAt(stss
->subs
[i
]).readorder
;
2812 qsort(subs
.GetData(), subs
.GetCount(), sizeof(LSub
), lscomp
);
2813 for(int i
= 0, j
= subs
.GetCount(); i
< j
; i
++)
2815 int entry
= subs
[i
].idx
;
2816 STSEntry stse
= GetAt(entry
);
2818 int start
= TranslateStart(entry
, fps
);
2820 m_delay
= TranslateEnd(entry
, fps
) - start
;
2822 CSubtitle
* s
= GetSubtitle(entry
);
2824 stss
->animated
|= s
->m_fAnimated2
;
2825 CRect clipRect
= s
->m_clip
;
2826 CRect r
= s
->m_rect
;
2827 CSize spaceNeeded
= r
.Size();
2828 // apply the effects
2829 bool fPosOverride
= false, fOrgOverride
= false;
2832 for(int k
= 0; k
< EF_NUMBEROFEFFECTS
; k
++)
2834 if(!s
->m_effects
[k
]) continue;
2837 case EF_MOVE
: // {\move(x1=param[0], y1=param[1], x2=param[2], y2=param[3], t1=t[0], t2=t[1])}
2840 CPoint
p1(s
->m_effects
[k
]->param
[0], s
->m_effects
[k
]->param
[1]);
2841 CPoint
p2(s
->m_effects
[k
]->param
[2], s
->m_effects
[k
]->param
[3]);
2842 int t1
= s
->m_effects
[k
]->t
[0];
2843 int t2
= s
->m_effects
[k
]->t
[1];
2844 if(t2
< t1
) {int t
= t1
; t1
= t2
; t2
= t
;}
2845 if(t1
<= 0 && t2
<= 0) {t1
= 0; t2
= m_delay
;}
2846 if(m_time
<= t1
) p
= p1
;
2847 else if (p1
== p2
) p
= p1
;
2848 else if(t1
< m_time
&& m_time
< t2
)
2850 double t
= 1.0*(m_time
-t1
)/(t2
-t1
);
2851 p
.x
= (int)((1-t
)*p1
.x
+ t
*p2
.x
);
2852 p
.y
= (int)((1-t
)*p1
.y
+ t
*p2
.y
);
2856 CPoint((s
->m_scrAlignment
%3) == 1 ? p
.x
: (s
->m_scrAlignment
%3) == 0 ? p
.x
- spaceNeeded
.cx
: p
.x
- (spaceNeeded
.cx
+1)/2,
2857 s
->m_scrAlignment
<= 3 ? p
.y
- spaceNeeded
.cy
: s
->m_scrAlignment
<= 6 ? p
.y
- (spaceNeeded
.cy
+1)/2 : p
.y
),
2859 if(s
->m_relativeTo
== 1)
2860 r
.OffsetRect(m_vidrect
.TopLeft());
2861 fPosOverride
= true;
2864 case EF_ORG
: // {\org(x=param[0], y=param[1])}
2866 org2
= CPoint(s
->m_effects
[k
]->param
[0], s
->m_effects
[k
]->param
[1]);
2867 fOrgOverride
= true;
2870 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])
2872 int t1
= s
->m_effects
[k
]->t
[0];
2873 int t2
= s
->m_effects
[k
]->t
[1];
2874 int t3
= s
->m_effects
[k
]->t
[2];
2875 int t4
= s
->m_effects
[k
]->t
[3];
2876 if(t1
== -1 && t4
== -1) {t1
= 0; t3
= m_delay
-t3
; t4
= m_delay
;}
2877 if(m_time
< t1
) alpha
= s
->m_effects
[k
]->param
[0];
2878 else if(m_time
>= t1
&& m_time
< t2
)
2880 double t
= 1.0 * (m_time
- t1
) / (t2
- t1
);
2881 alpha
= (int)(s
->m_effects
[k
]->param
[0]*(1-t
) + s
->m_effects
[k
]->param
[1]*t
);
2883 else if(m_time
>= t2
&& m_time
< t3
) alpha
= s
->m_effects
[k
]->param
[1];
2884 else if(m_time
>= t3
&& m_time
< t4
)
2886 double t
= 1.0 * (m_time
- t3
) / (t4
- t3
);
2887 alpha
= (int)(s
->m_effects
[k
]->param
[1]*(1-t
) + s
->m_effects
[k
]->param
[2]*t
);
2889 else if(m_time
>= t4
) alpha
= s
->m_effects
[k
]->param
[2];
2892 case EF_BANNER
: // Banner;delay=param[0][;leftoright=param[1];fadeawaywidth=param[2]]
2894 int left
= s
->m_relativeTo
== 1 ? m_vidrect
.left
: 0,
2895 right
= s
->m_relativeTo
== 1 ? m_vidrect
.right
: m_size
.cx
;
2896 r
.left
= !!s
->m_effects
[k
]->param
[1]
2897 ? (left
/*marginRect.left*/ - spaceNeeded
.cx
) + (int)(m_time
*8.0/s
->m_effects
[k
]->param
[0])
2898 : (right
/*- marginRect.right*/) - (int)(m_time
*8.0/s
->m_effects
[k
]->param
[0]);
2899 r
.right
= r
.left
+ spaceNeeded
.cx
;
2900 clipRect
&= CRect(left
>>3, clipRect
.top
, right
>>3, clipRect
.bottom
);
2901 fPosOverride
= true;
2904 case EF_SCROLL
: // Scroll up/down(toptobottom=param[3]);top=param[0];bottom=param[1];delay=param[2][;fadeawayheight=param[4]]
2906 r
.top
= !!s
->m_effects
[k
]->param
[3]
2907 ? s
->m_effects
[k
]->param
[0] + (int)(m_time
*8.0/s
->m_effects
[k
]->param
[2]) - spaceNeeded
.cy
2908 : s
->m_effects
[k
]->param
[1] - (int)(m_time
*8.0/s
->m_effects
[k
]->param
[2]);
2909 r
.bottom
= r
.top
+ spaceNeeded
.cy
;
2910 CRect
cr(0, (s
->m_effects
[k
]->param
[0] + 4) >> 3, spd
.w
, (s
->m_effects
[k
]->param
[1] + 4) >> 3);
2911 if(s
->m_relativeTo
== 1)
2912 r
.top
+= m_vidrect
.top
,
2913 r
.bottom
+= m_vidrect
.top
,
2914 cr
.top
+= m_vidrect
.top
>>3,
2915 cr
.bottom
+= m_vidrect
.top
>>3;
2917 fPosOverride
= true;
2924 if(!fPosOverride
&& !fOrgOverride
&& !s
->m_fAnimated
)
2925 r
= m_sla
.AllocRect(s
, segment
, entry
, stse
.layer
, m_collisions
);
2927 org
.x
= (s
->m_scrAlignment
%3) == 1 ? r
.left
: (s
->m_scrAlignment
%3) == 2 ? r
.CenterPoint().x
: r
.right
;
2928 org
.y
= s
->m_scrAlignment
<= 3 ? r
.bottom
: s
->m_scrAlignment
<= 6 ? r
.CenterPoint().y
: r
.top
;
2929 if(!fOrgOverride
) org2
= org
;
2930 BYTE
* pAlphaMask
= s
->m_pClipper
?s
->m_pClipper
->m_pAlphaMask
:NULL
;
2931 CPoint p
, p2(0, r
.top
);
2934 // Rectangles for inverse clip
2936 iclipRect
[0] = CRect(0, 0, spd
.w
, clipRect
.top
);
2937 iclipRect
[1] = CRect(0, clipRect
.top
, clipRect
.left
, clipRect
.bottom
);
2938 iclipRect
[2] = CRect(clipRect
.right
, clipRect
.top
, spd
.w
, clipRect
.bottom
);
2939 iclipRect
[3] = CRect(0, clipRect
.bottom
, spd
.w
, spd
.h
);
2941 bbox2
= CRect(0,0,0,0);
2942 pos
= s
->GetHeadPosition();
2945 CLine
* l
= s
->GetNext(pos
);
2946 p
.x
= (s
->m_scrAlignment
%3) == 1 ? org
.x
2947 : (s
->m_scrAlignment
%3) == 0 ? org
.x
- l
->m_width
2948 : org
.x
- (l
->m_width
/2);
2949 if (s
->m_clipInverse
)
2951 bbox2
|= l
->PaintShadow(spd
, iclipRect
[0], pAlphaMask
, p
, org2
, m_time
, alpha
);
2952 bbox2
|= l
->PaintShadow(spd
, iclipRect
[1], pAlphaMask
, p
, org2
, m_time
, alpha
);
2953 bbox2
|= l
->PaintShadow(spd
, iclipRect
[2], pAlphaMask
, p
, org2
, m_time
, alpha
);
2954 bbox2
|= l
->PaintShadow(spd
, iclipRect
[3], pAlphaMask
, p
, org2
, m_time
, alpha
);
2958 bbox2
|= l
->PaintShadow(spd
, clipRect
, pAlphaMask
, p
, org2
, m_time
, alpha
);
2960 p
.y
+= l
->m_ascent
+ l
->m_descent
;
2963 pos
= s
->GetHeadPosition();
2966 CLine
* l
= s
->GetNext(pos
);
2967 p
.x
= (s
->m_scrAlignment
%3) == 1 ? org
.x
2968 : (s
->m_scrAlignment
%3) == 0 ? org
.x
- l
->m_width
2969 : org
.x
- (l
->m_width
/2);
2970 if (s
->m_clipInverse
)
2972 bbox2
|= l
->PaintOutline(spd
, iclipRect
[0], pAlphaMask
, p
, org2
, m_time
, alpha
);
2973 bbox2
|= l
->PaintOutline(spd
, iclipRect
[1], pAlphaMask
, p
, org2
, m_time
, alpha
);
2974 bbox2
|= l
->PaintOutline(spd
, iclipRect
[2], pAlphaMask
, p
, org2
, m_time
, alpha
);
2975 bbox2
|= l
->PaintOutline(spd
, iclipRect
[3], pAlphaMask
, p
, org2
, m_time
, alpha
);
2979 bbox2
|= l
->PaintOutline(spd
, clipRect
, pAlphaMask
, p
, org2
, m_time
, alpha
);
2981 p
.y
+= l
->m_ascent
+ l
->m_descent
;
2984 pos
= s
->GetHeadPosition();
2987 CLine
* l
= s
->GetNext(pos
);
2988 p
.x
= (s
->m_scrAlignment
%3) == 1 ? org
.x
2989 : (s
->m_scrAlignment
%3) == 0 ? org
.x
- l
->m_width
2990 : org
.x
- (l
->m_width
/2);
2991 if (s
->m_clipInverse
)
2993 bbox2
|= l
->PaintBody(spd
, iclipRect
[0], pAlphaMask
, p
, org2
, m_time
, alpha
);
2994 bbox2
|= l
->PaintBody(spd
, iclipRect
[1], pAlphaMask
, p
, org2
, m_time
, alpha
);
2995 bbox2
|= l
->PaintBody(spd
, iclipRect
[2], pAlphaMask
, p
, org2
, m_time
, alpha
);
2996 bbox2
|= l
->PaintBody(spd
, iclipRect
[3], pAlphaMask
, p
, org2
, m_time
, alpha
);
3000 bbox2
|= l
->PaintBody(spd
, clipRect
, pAlphaMask
, p
, org2
, m_time
, alpha
);
3002 //DbgLog((LOG_TRACE,3,"%d line:%x bbox2 l:%d, t:%d, r:%d, b:%d", dbgTest++, l, bbox2->left, bbox2->top, bbox2->right, bbox2->bottom));
3003 p
.y
+= l
->m_ascent
+ l
->m_descent
;
3005 rectList
.AddTail(bbox2
);
3007 return (subs
.GetCount() && !rectList
.IsEmpty()) ? S_OK
: S_FALSE
;
3011 STDMETHODIMP
CRenderedTextSubtitle::Render(SubPicDesc
& spd
, REFERENCE_TIME rt
, double fps
, RECT
& bbox
)
3013 CAtlList
<CRect
> rectList
;
3014 HRESULT result
= Render(spd
, rt
, fps
, rectList
);
3015 POSITION pos
= rectList
.GetHeadPosition();
3016 CRect
bbox2(0,0,0,0);
3019 bbox2
|= rectList
.GetNext(pos
);
3027 STDMETHODIMP
CRenderedTextSubtitle::GetClassID(CLSID
* pClassID
)
3029 return pClassID
? *pClassID
= __uuidof(this), S_OK
: E_POINTER
;
3034 STDMETHODIMP_(int) CRenderedTextSubtitle::GetStreamCount()
3039 STDMETHODIMP
CRenderedTextSubtitle::GetStreamInfo(int iStream
, WCHAR
** ppName
, LCID
* pLCID
)
3041 if(iStream
!= 0) return E_INVALIDARG
;
3044 if(!(*ppName
= (WCHAR
*)CoTaskMemAlloc((m_name
.GetLength()+1)*sizeof(WCHAR
))))
3045 return E_OUTOFMEMORY
;
3046 wcscpy(*ppName
, CStringW(m_name
));
3055 STDMETHODIMP_(int) CRenderedTextSubtitle::GetStream()
3060 STDMETHODIMP
CRenderedTextSubtitle::SetStream(int iStream
)
3062 return iStream
== 0 ? S_OK
: E_FAIL
;
3065 STDMETHODIMP
CRenderedTextSubtitle::Reload()
3068 if(!CFile::GetStatus(m_path
, s
)) return E_FAIL
;
3069 return !m_path
.IsEmpty() && Open(m_path
, DEFAULT_CHARSET
) ? S_OK
: E_FAIL
;
3072 CWordCacheKey::CWordCacheKey( const CWord
& word
)
3075 m_style
= word
.m_style
;
3076 m_ktype
= word
.m_ktype
;
3077 m_kstart
= word
.m_kstart
;
3078 m_kend
= word
.m_kend
;
3081 CWordCacheKey::CWordCacheKey( const CWordCacheKey
& key
)
3084 m_style
= key
.m_style
;
3085 m_ktype
= key
.m_ktype
;
3086 m_kstart
= key
.m_kstart
;
3087 m_kend
= key
.m_kend
;
3090 CWordCacheKey::CWordCacheKey( const STSStyle
& style
, const CStringW
& str
, int ktype
, int kstart
, int kend
)
3091 :m_style(style
),m_str(str
),m_ktype(ktype
),m_kstart(kstart
),m_kend(m_kend
)
3096 bool CWordCacheKey::operator==( const CWordCacheKey
& key
) const
3098 return (m_str
== key
.m_str
&&
3099 m_style
== key
.m_style
&&
3100 m_ktype
== key
.m_ktype
&&
3101 m_kstart
== key
.m_kstart
&&
3102 m_kend
== key
.m_kend
);
3105 bool CWordCacheKey::operator==(const CWord
& key
)const
3107 return (m_str
== key
.m_str
&&
3108 m_style
== key
.m_style
&&
3109 m_ktype
== key
.m_ktype
&&
3110 m_kstart
== key
.m_kstart
&&
3111 m_kend
== key
.m_kend
);
3114 void OverlayMruCache::update_cache( const OverlayMruItem
& item
)
3116 std::pair
<iterator
,bool> p
=il
.push_front(item
);
3118 if(!p
.second
){ /* duplicate item */
3119 il
.relocate(il
.begin(),p
.first
); /* put in front */
3121 else if(il
.size()>max_num_items
){ /* keep the length <= max_num_items */
3122 delete il
.rbegin()->overlay
;
3127 void OverlayMruCache::clear()
3129 for(OverlayMruCache::iterator iter
=begin();iter
!=end();iter
++)
3131 delete iter
->overlay
;
3136 void CWordMruCache::update_cache( const CWordMruItem
& item
)
3138 std::pair
<iterator
,bool> p
=il
.push_front(item
);
3140 if(!p
.second
){ /* duplicate item */
3141 il
.relocate(il
.begin(),p
.first
); /* put in front */
3143 else if(il
.size()>max_num_items
){ /* keep the length <= max_num_items */
3144 delete il
.rbegin()->word
;
3149 void CWordMruCache::clear()
3151 for(CWordMruCache::iterator iter
=begin();iter
!=end();iter
++)