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 "draw_item.h"
27 #include "cache_manager.h"
28 #include "subpixel_position_controler.h"
29 #include "xy_overlay_paint_machine.h"
30 #include "xy_clipper_paint_machine.h"
32 // WARNING: this isn't very thread safe, use only one RTS a time.
34 static int g_hDC_refcnt
= 0;
36 static long revcolor(long c
)
38 return ((c
&0xff0000)>>16) + (c
&0xff00) + ((c
&0xff)<<16);
41 // Skip all leading whitespace
42 inline CStringW::PCXSTR
SkipWhiteSpaceLeft(const CStringW
& str
)
44 CStringW::PCXSTR psz
= str
.GetString();
46 while( iswspace( *psz
) )
53 // Skip all trailing whitespace
54 inline CStringW::PCXSTR
SkipWhiteSpaceRight(const CStringW
& str
)
56 CStringW::PCXSTR psz
= str
.GetString();
57 CStringW::PCXSTR pszLast
= psz
+ str
.GetLength() - 1;
58 bool first_white
= false;
59 while( iswspace( *pszLast
) )
68 // Skip all leading whitespace
69 inline CStringW::PCXSTR
SkipWhiteSpaceLeft(CStringW::PCXSTR start
, CStringW::PCXSTR end
)
71 while( start
!=end
&& iswspace( *start
) )
78 // Skip all trailing whitespace, first char must NOT be white space
79 inline CStringW::PCXSTR
FastSkipWhiteSpaceRight(CStringW::PCXSTR start
, CStringW::PCXSTR end
)
81 while( iswspace( *--end
) );
85 inline CStringW::PCXSTR
FindChar(CStringW::PCXSTR start
, CStringW::PCXSTR end
, WCHAR c
)
87 while( start
!=end
&& *start
!=c
)
94 //////////////////////////////////////////////////////////////////////////////////////////////
98 CMyFont::CMyFont(const STSStyleBase
& style
)
101 memset(&lf
, 0, sizeof(lf
));
103 lf
.lfHeight
= (LONG
)(style
.fontSize
+0.5);
104 lf
.lfOutPrecision
= OUT_TT_PRECIS
;
105 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
106 lf
.lfQuality
= ANTIALIASED_QUALITY
;
107 lf
.lfPitchAndFamily
= DEFAULT_PITCH
|FF_DONTCARE
;
108 if(!CreateFontIndirect(&lf
))
110 _tcscpy(lf
.lfFaceName
, _T("Arial"));
111 CreateFontIndirect(&lf
);
113 HFONT hOldFont
= SelectFont(g_hDC
, *this);
115 GetTextMetrics(g_hDC
, &tm
);
116 m_ascent
= ((tm
.tmAscent
+ 4) >> 3);
117 m_descent
= ((tm
.tmDescent
+ 4) >> 3);
118 SelectFont(g_hDC
, hOldFont
);
123 CWord::CWord( const FwSTSStyle
& style
, const CStringW
& str
, int ktype
, int kstart
, int kend
124 , double target_scale_x
/*=1.0*/, double target_scale_y
/*=1.0*/
125 , bool round_to_whole_pixel_after_scale_to_target
/*=false*/)
126 : m_style(style
), m_str(new CStringW(str
))
127 , m_width(0), m_ascent(0), m_descent(0)
128 , m_ktype(ktype
), m_kstart(kstart
), m_kend(kend
)
129 , m_fLineBreak(false), m_fWhiteSpaceChar(false)
130 , m_target_scale_x(target_scale_x
), m_target_scale_y(target_scale_y
)
131 , m_round_to_whole_pixel_after_scale_to_target(round_to_whole_pixel_after_scale_to_target
)
132 //, m_pOpaqueBox(NULL)
134 if(m_str
.Get().IsEmpty())
136 m_fWhiteSpaceChar
= m_fLineBreak
= true;
141 CWord::CWord( const CWord
& src
):m_str(src
.m_str
)
143 m_fWhiteSpaceChar
= src
.m_fWhiteSpaceChar
;
144 m_fLineBreak
= src
.m_fLineBreak
;
145 m_style
= src
.m_style
;
146 m_pOpaqueBox
= src
.m_pOpaqueBox
;//allow since it is shared_ptr
147 m_ktype
= src
.m_ktype
;
148 m_kstart
= src
.m_kstart
;
150 m_width
= src
.m_width
;
151 m_ascent
= src
.m_ascent
;
152 m_descent
= src
.m_descent
;
153 m_target_scale_x
= src
.m_target_scale_x
;
154 m_target_scale_y
= src
.m_target_scale_y
;
155 m_round_to_whole_pixel_after_scale_to_target
= src
.m_round_to_whole_pixel_after_scale_to_target
;
160 //if(m_pOpaqueBox) delete m_pOpaqueBox;
163 bool CWord::Append(const SharedPtrCWord
& w
)
165 if(!(m_style
== w
->m_style
)
166 || m_fLineBreak
|| w
->m_fLineBreak
167 || w
->m_kstart
!= w
->m_kend
|| m_ktype
!= w
->m_ktype
) return(false);
168 m_fWhiteSpaceChar
= m_fWhiteSpaceChar
&& w
->m_fWhiteSpaceChar
;
169 CStringW
*str
= new CStringW();//Fix me: anyway to avoid this flyweight update?
172 *str
+= w
->m_str
.Get();
173 m_str
= XyFwStringW(str
);
174 m_width
+= w
->m_width
;
178 void CWord::PaintFromOverlay(const CPointCoor2
& p
, const CPointCoor2
& trans_org2
, OverlayKey
&subpixel_variance_key
, SharedPtrOverlay
& overlay
)
180 if( SubpixelPositionControler::GetGlobalControler().UseBilinearShift() )
182 CPoint psub
= SubpixelPositionControler::GetGlobalControler().GetSubpixel(p
);
183 if( (psub
.x
!=(p
.x
&SubpixelPositionControler::EIGHT_X_EIGHT_MASK
)
184 || psub
.y
!=(p
.y
&SubpixelPositionControler::EIGHT_X_EIGHT_MASK
)) )
186 overlay
.reset(overlay
->GetSubpixelVariance((p
.x
&SubpixelPositionControler::EIGHT_X_EIGHT_MASK
) - psub
.x
,
187 (p
.y
&SubpixelPositionControler::EIGHT_X_EIGHT_MASK
) - psub
.y
));
188 OverlayMruCache
* overlay_cache
= CacheManager::GetSubpixelVarianceCache();
189 overlay_cache
->UpdateCache(subpixel_variance_key
, overlay
);
194 void CWord::PaintFromNoneBluredOverlay(SharedPtrOverlay raterize_result
, const OverlayKey
& overlay_key
, SharedPtrOverlay
* overlay
)
196 if( Rasterizer::IsItReallyBlur(m_style
.get().fBlur
, m_style
.get().fGaussianBlur
) )
198 overlay
->reset(new Overlay());
199 if(!Rasterizer::Blur(*raterize_result
, m_style
.get().fBlur
, m_style
.get().fGaussianBlur
,
200 m_target_scale_x
, m_target_scale_y
, *overlay
))
202 *overlay
= raterize_result
;
207 *overlay
= raterize_result
;
209 OverlayMruCache
* overlay_cache
= CacheManager::GetOverlayMruCache();
210 overlay_cache
->UpdateCache(overlay_key
, *overlay
);
213 bool CWord::PaintFromScanLineData2(const CPointCoor2
& psub
, const ScanLineData2
& scan_line_data2
, const OverlayKey
& key
, SharedPtrOverlay
* overlay
)
215 SharedPtrOverlay
raterize_result(new Overlay());
216 if(!Rasterizer::Rasterize(scan_line_data2
, psub
.x
, psub
.y
, raterize_result
))
220 OverlayNoBlurMruCache
* overlay_no_blur_cache
= CacheManager::GetOverlayNoBlurMruCache();
221 overlay_no_blur_cache
->UpdateCache(key
, raterize_result
);
222 PaintFromNoneBluredOverlay(raterize_result
, key
, overlay
);
226 bool CWord::PaintFromPathData(const CPointCoor2
& psub
, const CPointCoor2
& trans_org
, const PathData
& path_data
, const OverlayKey
& key
, SharedPtrOverlay
* overlay
)
230 PathData
*path_data2
= new PathData(path_data
);//fix me: this copy operation can be saved if no transform is needed
231 SharedPtrConstPathData
shared_ptr_path_data2(path_data2
);
232 bool need_transform
= NeedTransform();
234 Transform(path_data2
, CPoint(trans_org
.x
*8, trans_org
.y
*8));
238 path_data2
->AlignLeftTop(&left_top
, &size
);
240 int border_x
= static_cast<int>(m_style
.get().outlineWidthX
*m_target_scale_x
+0.5);//fix me: rounding err
241 int border_y
= static_cast<int>(m_style
.get().outlineWidthY
*m_target_scale_y
+0.5);//fix me: rounding err
242 int wide_border
= border_x
>border_y
? border_x
:border_y
;
243 if (m_style
.get().borderStyle
==1)
245 border_x
= border_y
= 0;
248 OverlayNoOffsetMruCache
* overlay_key_cache
= CacheManager::GetOverlayNoOffsetMruCache();
249 OverlayNoOffsetKey
overlay_no_offset_key(shared_ptr_path_data2
, psub
.x
, psub
.y
, border_x
, border_y
);
250 overlay_no_offset_key
.UpdateHashValue();
251 POSITION pos_key
= overlay_key_cache
->Lookup(overlay_no_offset_key
);
254 OverlayNoBlurMruCache
* overlay_cache
= CacheManager::GetOverlayNoBlurMruCache();
257 OverlayNoBlurKey overlay_key
= overlay_key_cache
->GetAt(pos_key
);
258 pos
= overlay_cache
->Lookup(overlay_key
);
262 SharedPtrOverlay
raterize_result( new Overlay() );
263 *raterize_result
= *overlay_cache
->GetAt(pos
);
264 raterize_result
->mOffsetX
= left_top
.x
- psub
.x
- ((wide_border
+7)&~7);
265 raterize_result
->mOffsetY
= left_top
.y
- psub
.y
- ((wide_border
+7)&~7);
266 PaintFromNoneBluredOverlay(raterize_result
, key
, overlay
);
268 overlay_cache
->UpdateCache(key
, raterize_result
);
272 ScanLineDataMruCache
* scan_line_data_cache
= CacheManager::GetScanLineDataMruCache();
273 pos
= scan_line_data_cache
->Lookup(overlay_no_offset_key
);
274 SharedPtrConstScanLineData scan_line_data
;
277 scan_line_data
= scan_line_data_cache
->GetAt(pos
);
278 scan_line_data_cache
->UpdateCache(pos
);
282 ScanLineData
*tmp
= new ScanLineData();
283 scan_line_data
.reset(tmp
);
284 if(!tmp
->ScanConvert(*path_data2
, size
))
288 scan_line_data_cache
->UpdateCache(overlay_no_offset_key
, scan_line_data
);
290 ScanLineData2
*tmp
= new ScanLineData2(left_top
, scan_line_data
);
291 SharedPtrScanLineData2
scan_line_data2( tmp
);
292 if(m_style
.get().borderStyle
== 0 && (m_style
.get().outlineWidthX
+m_style
.get().outlineWidthY
> 0))
294 if(!tmp
->CreateWidenedRegion(border_x
, border_y
))
299 ScanLineData2MruCache
* scan_line_data2_cache
= CacheManager::GetScanLineData2MruCache();
300 scan_line_data2_cache
->UpdateCache(key
, scan_line_data2
);
301 result
= PaintFromScanLineData2(psub
, *tmp
, key
, overlay
);
307 overlay_key_cache
->UpdateCache(pos_key
, key
);
311 overlay_key_cache
->UpdateCache(overlay_no_offset_key
, key
);
317 bool CWord::PaintFromRawData( const CPointCoor2
& psub
, const CPointCoor2
& trans_org
, const OverlayKey
& key
, SharedPtrOverlay
* overlay
)
319 PathDataMruCache
* path_data_cache
= CacheManager::GetPathDataMruCache();
321 PathData
*tmp
=new PathData();
322 SharedPtrPathData
path_data(tmp
);
327 path_data_cache
->UpdateCache(key
, path_data
);
328 return PaintFromPathData(psub
, trans_org
, *tmp
, key
, overlay
);
331 bool CWord::DoPaint(const CPointCoor2
& psub
, const CPointCoor2
& trans_org
, SharedPtrOverlay
* overlay
, const OverlayKey
& key
)
334 OverlayNoBlurMruCache
* overlay_no_blur_cache
= CacheManager::GetOverlayNoBlurMruCache();
335 POSITION pos
= overlay_no_blur_cache
->Lookup(key
);
339 SharedPtrOverlay raterize_result
= overlay_no_blur_cache
->GetAt(pos
);
340 overlay_no_blur_cache
->UpdateCache( pos
);
341 PaintFromNoneBluredOverlay(raterize_result
, key
, overlay
);
345 ScanLineData2MruCache
* scan_line_data_cache
= CacheManager::GetScanLineData2MruCache();
346 pos
= scan_line_data_cache
->Lookup(key
);
349 SharedPtrConstScanLineData2 scan_line_data
= scan_line_data_cache
->GetAt(pos
);
350 scan_line_data_cache
->UpdateCache( pos
);
351 result
= PaintFromScanLineData2(psub
, *scan_line_data
, key
, overlay
);
355 PathDataMruCache
* path_data_cache
= CacheManager::GetPathDataMruCache();
356 POSITION pos_path
= path_data_cache
->Lookup(key
);
359 SharedPtrConstPathData path_data
= path_data_cache
->GetAt(pos_path
); //important! copy not ref
360 path_data_cache
->UpdateCache( pos_path
);
361 result
= PaintFromPathData(psub
, trans_org
, *path_data
, key
, overlay
);
365 result
= PaintFromRawData(psub
, trans_org
, key
, overlay
);
372 bool CWord::NeedTransform()
374 return (fabs(m_style
.get().fontScaleX
- 100) > 0.000001) ||
375 (fabs(m_style
.get().fontScaleY
- 100) > 0.000001) ||
376 (fabs(m_style
.get().fontAngleX
) > 0.000001) ||
377 (fabs(m_style
.get().fontAngleY
) > 0.000001) ||
378 (fabs(m_style
.get().fontAngleZ
) > 0.000001) ||
379 (fabs(m_style
.get().fontShiftX
) > 0.000001) ||
380 (fabs(m_style
.get().fontShiftY
) > 0.000001) ||
381 (fabs(m_target_scale_x
-1.0) > 0.000001) ||
382 (fabs(m_target_scale_y
-1.0) > 0.000001);
385 void CWord::Transform(PathData
* path_data
, const CPointCoor2
& org
)
388 //bool fSSE2 = !!(g_cpuid.m_flags & CCpuID::sse2);
390 //if(fSSE2) { // SSE code
391 // Transform_SSE2(path_data, org);
393 Transform_C(path_data
, org
);
396 void CWord::Transform_C(PathData
* path_data
, const CPointCoor2
&org
)
399 const STSStyle
& style
= m_style
.get();
401 double scalex
= style
.fontScaleX
/100;
402 double scaley
= style
.fontScaleY
/100;
404 double caz
= cos((3.1415/180)*style
.fontAngleZ
);
405 double saz
= sin((3.1415/180)*style
.fontAngleZ
);
406 double cax
= cos((3.1415/180)*style
.fontAngleX
);
407 double sax
= sin((3.1415/180)*style
.fontAngleX
);
408 double cay
= cos((3.1415/180)*style
.fontAngleY
);
409 double say
= sin((3.1415/180)*style
.fontAngleY
);
414 S0 = 0 targetScaleY 0
433 scalex scalex*fontShiftX -org.x/targetScaleX
434 A4 = scaley*fontShiftY scaley -org.y/targetScaleY
442 (x,y,z)' = (S0*A0*A1*A2*A3*A4 + B0) * (x y 1)'
444 x = x/z + tagetScaleX*org.x
445 y = y/z + tagetScaleY*org.y
449 ASSERT(m_target_scale_x
!=0 && m_target_scale_y
!=0);
450 double tmp1
= -org
.x
/m_target_scale_x
;
451 double tmp2
= -org
.y
/m_target_scale_y
;
453 xxx
[0][0] = caz
*scalex
+ saz
*scaley
*style
.fontShiftY
;
454 xxx
[0][1] = caz
*scalex
*style
.fontShiftX
+ saz
*scaley
;
455 xxx
[0][2] = caz
*tmp1
+ saz
*tmp2
;
457 xxx
[1][0] = -saz
*scalex
+ caz
*scaley
*style
.fontShiftY
;
458 xxx
[1][1] = -saz
*scalex
*style
.fontShiftX
+ caz
*scaley
;
459 xxx
[1][2] = -saz
*tmp1
+ caz
*tmp2
;
467 xxx
[2][0] = sax
*xxx
[1][0];
468 xxx
[2][1] = sax
*xxx
[1][1];
469 xxx
[2][2] = sax
*xxx
[1][2];
471 xxx
[1][0] = cax
*xxx
[1][0];
472 xxx
[1][1] = cax
*xxx
[1][1];
473 xxx
[1][2] = cax
*xxx
[1][2];
479 double tmp3
= xxx
[0][2];
480 xxx
[0][0] = cay
*tmp1
+ say
*xxx
[2][0];
481 xxx
[0][1] = cay
*tmp2
+ say
*xxx
[2][1];
482 xxx
[0][2] = cay
*tmp3
+ say
*xxx
[2][2];
484 xxx
[2][0] = say
*tmp1
- cay
*xxx
[2][0];
485 xxx
[2][1] = say
*tmp2
- cay
*xxx
[2][1];
486 xxx
[2][2] = say
*tmp3
- cay
*xxx
[2][2];
490 tmp1
= 20000*m_target_scale_x
;
495 tmp1
= 20000*m_target_scale_y
;
504 double scaled_org_x
= org
.x
+0.5;
505 double scaled_org_y
= org
.y
+0.5;
507 for (int i
= 0; i
< path_data
->mPathPoints
; i
++) {
510 xx
= path_data
->mpPathPoints
[i
].x
;
511 y
= path_data
->mpPathPoints
[i
].y
;
513 z
= xxx
[2][0] * xx
+ xxx
[2][1] * y
+ xxx
[2][2];
514 x
= xxx
[0][0] * xx
+ xxx
[0][1] * y
+ xxx
[0][2];
515 y
= xxx
[1][0] * xx
+ xxx
[1][1] * y
+ xxx
[1][2];
517 z
= z
> 1000 ? z
: 1000;
522 path_data
->mpPathPoints
[i
].x
= (long)(x
+ scaled_org_x
);
523 path_data
->mpPathPoints
[i
].y
= (long)(y
+ scaled_org_y
);
524 if (m_round_to_whole_pixel_after_scale_to_target
&& (m_target_scale_x
!=1.0 || m_target_scale_y
!=1.0))
526 path_data
->mpPathPoints
[i
].x
= (path_data
->mpPathPoints
[i
].x
+ 32)&~63;
527 path_data
->mpPathPoints
[i
].y
= (path_data
->mpPathPoints
[i
].y
+ 32)&~63;//fix me: readability
532 void CWord::Transform_SSE2(PathData
* path_data
, const CPointCoor2
&org
)
534 // __m128 union data type currently not supported with Intel C++ Compiler, so just call C version
539 // speed up ~1.5-1.7x
540 double scalex
= m_style
.get().fontScaleX
/100;
541 double scaley
= m_style
.get().fontScaleY
/100;
543 double caz
= cos((3.1415/180)*m_style
.get().fontAngleZ
);
544 double saz
= sin((3.1415/180)*m_style
.get().fontAngleZ
);
545 double cax
= cos((3.1415/180)*m_style
.get().fontAngleX
);
546 double sax
= sin((3.1415/180)*m_style
.get().fontAngleX
);
547 double cay
= cos((3.1415/180)*m_style
.get().fontAngleY
);
548 double say
= sin((3.1415/180)*m_style
.get().fontAngleY
);
550 __m128 __xshift
= _mm_set_ps1(m_style
.get().fontShiftX
);
551 __m128 __yshift
= _mm_set_ps1(m_style
.get().fontShiftY
);
553 __m128 __xorg
= _mm_set_ps1(org
.x
);
554 __m128 __yorg
= _mm_set_ps1(org
.y
);
556 __m128 __xscale
= _mm_set_ps1(scalex
);
557 __m128 __yscale
= _mm_set_ps1(scaley
);
560 // patch m003. random text points
561 double xrnd
= m_style
.get().mod_rand
.X
*100;
562 double yrnd
= m_style
.get().mod_rand
.Y
*100;
563 double zrnd
= m_style
.get().mod_rand
.Z
*100;
565 srand(m_style
.get().mod_rand
.Seed
);
567 __m128 __xsz
= _mm_setzero_ps();
568 __m128 __ysz
= _mm_setzero_ps();
570 __m128 __dst1x
, __dst1y
, __dst213x
, __dst213y
, __dst3x
, __dst3y
;
573 __m128 __minx
= _mm_set_ps(INT_MAX
, INT_MAX
, 0, 0);
574 __m128 __max
= _mm_set_ps(-INT_MAX
, -INT_MAX
, 1, 1);
576 bool is_dist
= m_style
.get().mod_distort
.enabled
;
578 for(int i
= 0; i
< path_data
->mPathPoints
; i
++) {
579 __m128 __point
= _mm_set_ps(path_data
->mpPathPoints
[i
].x
, path_data
->mpPathPoints
[i
].y
, 0, 0);
580 __minx
= _mm_min_ps(__minx
, __point
);
581 __max
= _mm_max_ps(__max
, __point
);
584 __m128 __zero
= _mm_setzero_ps();
585 __max
= _mm_sub_ps(__max
, __minx
); // xsz, ysz, 1, 1
586 __max
= _mm_max_ps(__max
, __zero
);
588 __xsz
= _mm_shuffle_ps(__max
, __max
, _MM_SHUFFLE(3,3,3,3));
589 __ysz
= _mm_shuffle_ps(__max
, __max
, _MM_SHUFFLE(2,2,2,2));
591 __miny
= _mm_shuffle_ps(__minx
, __minx
, _MM_SHUFFLE(2,2,2,2));
592 __minx
= _mm_shuffle_ps(__minx
, __minx
, _MM_SHUFFLE(3,3,3,3));
594 __dst1x
= _mm_set_ps1(m_style
.get().mod_distort
.pointsx
[0]);
595 __dst1y
= _mm_set_ps1(m_style
.get().mod_distort
.pointsy
[0]);
596 __dst3x
= _mm_set_ps1(m_style
.get().mod_distort
.pointsx
[2]);
597 __dst3y
= _mm_set_ps1(m_style
.get().mod_distort
.pointsy
[2]);
598 __dst213x
= _mm_set_ps1(m_style
.get().mod_distort
.pointsx
[1]); // 2 - 1 - 3
599 __dst213x
= _mm_sub_ps(__dst213x
, __dst1x
);
600 __dst213x
= _mm_sub_ps(__dst213x
, __dst3x
);
602 __dst213y
= _mm_set_ps1(m_style
.get().mod_distort
.pointsy
[1]);
603 __dst213x
= _mm_sub_ps(__dst213y
, __dst1y
);
604 __dst213x
= _mm_sub_ps(__dst213y
, __dst3y
);
608 __m128 __caz
= _mm_set_ps1(caz
);
609 __m128 __saz
= _mm_set_ps1(saz
);
610 __m128 __cax
= _mm_set_ps1(cax
);
611 __m128 __sax
= _mm_set_ps1(sax
);
612 __m128 __cay
= _mm_set_ps1(cay
);
613 __m128 __say
= _mm_set_ps1(say
);
615 // this can be paralleled for openmp
616 int mPathPointsD4
= path_data
->mPathPoints
/ 4;
617 int mPathPointsM4
= path_data
->mPathPoints
% 4;
619 for(ptrdiff_t i
= 0; i
< mPathPointsD4
+ 1; i
++) {
620 POINT
* const temp_points
= path_data
->mpPathPoints
+ 4 * i
;
622 __m128 __pointx
, __pointy
;
623 // we can't use load .-.
624 if(i
!= mPathPointsD4
) {
625 __pointx
= _mm_set_ps(temp_points
[0].x
, temp_points
[1].x
, temp_points
[2].x
, temp_points
[3].x
);
626 __pointy
= _mm_set_ps(temp_points
[0].y
, temp_points
[1].y
, temp_points
[2].y
, temp_points
[3].y
);
627 } else { // last cycle
628 switch(mPathPointsM4
) {
633 __pointx
= _mm_set_ps(temp_points
[0].x
, 0, 0, 0);
634 __pointy
= _mm_set_ps(temp_points
[0].y
, 0, 0, 0);
637 __pointx
= _mm_set_ps(temp_points
[0].x
, temp_points
[1].x
, 0, 0);
638 __pointy
= _mm_set_ps(temp_points
[0].y
, temp_points
[1].y
, 0, 0);
641 __pointx
= _mm_set_ps(temp_points
[0].x
, temp_points
[1].x
, temp_points
[2].x
, 0);
642 __pointy
= _mm_set_ps(temp_points
[0].y
, temp_points
[1].y
, temp_points
[2].y
, 0);
648 __m128 __pointz
= _mm_set_ps1(m_style
.get().mod_z
);
652 //P = P0 + (P1 - P0)u + (P3 - P0)v + (P0 + P2 - P1 - P3)uv
653 __m128 __u
= _mm_sub_ps(__pointx
, __minx
);
654 __m128 __v
= _mm_sub_ps(__pointy
, __miny
);
655 __m128 __1_xsz
= _mm_rcp_ps(__xsz
);
656 __m128 __1_ysz
= _mm_rcp_ps(__ysz
);
657 __u
= _mm_mul_ps(__u
, __1_xsz
);
658 __v
= _mm_mul_ps(__v
, __1_ysz
);
661 __pointx
= _mm_mul_ps(__dst213x
, __u
);
662 __pointx
= _mm_mul_ps(__pointx
, __v
);
664 __m128 __tmpx
= _mm_mul_ps(__dst3x
, __v
);
665 __pointx
= _mm_add_ps(__pointx
, __tmpx
);
666 __tmpx
= _mm_mul_ps(__dst1x
, __u
);
667 __pointx
= _mm_add_ps(__pointx
, __tmpx
);
669 __pointx
= _mm_mul_ps(__pointx
, __xsz
);
670 __pointx
= _mm_add_ps(__pointx
, __minx
);
673 __pointy
= _mm_mul_ps(__dst213y
, __u
);
674 __pointy
= _mm_mul_ps(__pointy
, __v
);
676 __m128 __tmpy
= _mm_mul_ps(__dst3y
, __v
);
677 __pointy
= _mm_add_ps(__pointy
, __tmpy
);
678 __tmpy
= _mm_mul_ps(__dst1y
, __u
);
679 __pointy
= _mm_add_ps(__pointy
, __tmpy
);
681 __pointy
= _mm_mul_ps(__pointy
, __ysz
);
682 __pointy
= _mm_add_ps(__pointy
, __miny
);
686 if(xrnd
!=0 || yrnd
!=0 || zrnd
!=0) {
687 __declspec(align(16)) float rx
[4], ry
[4], rz
[4];
688 for(int k
=0; k
<4; k
++) {
689 rx
[k
] = xrnd
> 0 ? (xrnd
- rand() % (int)(xrnd
* 2 + 1)) : 0;
690 ry
[k
] = yrnd
> 0 ? (yrnd
- rand() % (int)(yrnd
* 2 + 1)) : 0;
691 rz
[k
] = zrnd
> 0 ? (zrnd
- rand() % (int)(zrnd
* 2 + 1)) : 0;
693 __m128 __001
= _mm_set_ps1(0.01f
);
696 __m128 __rx
= _mm_load_ps(rx
);
697 __rx
= _mm_mul_ps(__rx
, __001
);
698 __pointx
= _mm_add_ps(__pointx
, __rx
);
702 __m128 __ry
= _mm_load_ps(ry
);
703 __ry
= _mm_mul_ps(__ry
, __001
);
704 __pointy
= _mm_add_ps(__pointy
, __ry
);
708 __m128 __rz
= _mm_load_ps(rz
);
709 __rz
= _mm_mul_ps(__rz
, __001
);
710 __pointz
= _mm_add_ps(__pointz
, __rz
);
714 __m128 __pointz
= _mm_set_ps1(0);
719 if(m_style
.get().fontShiftX
!=0) {
720 __tmpx
= _mm_mul_ps(__xshift
, __pointy
);
721 __tmpx
= _mm_add_ps(__tmpx
, __pointx
);
725 __tmpx
= _mm_mul_ps(__tmpx
, __xscale
);
726 __tmpx
= _mm_sub_ps(__tmpx
, __xorg
);
729 if(m_style
.get().fontShiftY
!=0) {
730 __tmpy
= _mm_mul_ps(__yshift
, __pointx
);
731 __tmpy
= _mm_add_ps(__tmpy
, __pointy
);
735 __tmpy
= _mm_mul_ps(__tmpy
, __yscale
);
736 __tmpy
= _mm_sub_ps(__tmpy
, __yorg
);
739 __m128 __xx
= _mm_mul_ps(__tmpx
, __caz
);
740 __m128 __yy
= _mm_mul_ps(__tmpy
, __saz
);
741 __pointx
= _mm_add_ps(__xx
, __yy
);
742 __xx
= _mm_mul_ps(__tmpx
, __saz
);
743 __yy
= _mm_mul_ps(__tmpy
, __caz
);
744 __pointy
= _mm_sub_ps(__yy
, __xx
);
746 __m128 __zz
= _mm_mul_ps(__pointz
, __sax
);
747 __yy
= _mm_mul_ps(__pointy
, __cax
);
748 __pointy
= _mm_add_ps(__yy
, __zz
);
749 __zz
= _mm_mul_ps(__pointz
, __cax
);
750 __yy
= _mm_mul_ps(__pointy
, __sax
);
751 __pointz
= _mm_sub_ps(__zz
, __yy
);
753 __xx
= _mm_mul_ps(__pointx
, __cay
);
754 __zz
= _mm_mul_ps(__pointz
, __say
);
755 __pointx
= _mm_add_ps(__xx
, __zz
);
756 __xx
= _mm_mul_ps(__pointx
, __say
);
757 __zz
= _mm_mul_ps(__pointz
, __cay
);
758 __pointz
= _mm_sub_ps(__xx
, __zz
);
760 __zz
= _mm_set_ps1(-19000);
761 __pointz
= _mm_max_ps(__pointz
, __zz
);
763 __m128 __20000
= _mm_set_ps1(20000);
764 __zz
= _mm_add_ps(__pointz
, __20000
);
765 __zz
= _mm_rcp_ps(__zz
);
767 __pointx
= _mm_mul_ps(__pointx
, __20000
);
768 __pointx
= _mm_mul_ps(__pointx
, __zz
);
770 __pointy
= _mm_mul_ps(__pointy
, __20000
);
771 __pointy
= _mm_mul_ps(__pointy
, __zz
);
773 __pointx
= _mm_add_ps(__pointx
, __xorg
);
774 __pointy
= _mm_add_ps(__pointy
, __yorg
);
776 __m128 __05
= _mm_set_ps1(0.5);
778 __pointx
= _mm_add_ps(__pointx
, __05
);
779 __pointy
= _mm_add_ps(__pointy
, __05
);
781 if(i
== mPathPointsD4
) { // last cycle
782 for(int k
=0; k
<mPathPointsM4
; k
++) {
783 temp_points
[k
].x
= static_cast<LONG
>(__pointx
.m128_f32
[3-k
]);
784 temp_points
[k
].y
= static_cast<LONG
>(__pointy
.m128_f32
[3-k
]);
787 for(int k
=0; k
<4; k
++) {
788 temp_points
[k
].x
= static_cast<LONG
>(__pointx
.m128_f32
[3-k
]);
789 temp_points
[k
].y
= static_cast<LONG
>(__pointy
.m128_f32
[3-k
]);
796 bool CWord::CreateOpaqueBox()
798 if(m_pOpaqueBox
) return(true);
799 STSStyle style
= m_style
.get();
800 style
.borderStyle
= 0;
801 style
.outlineWidthX
= style
.outlineWidthY
= 0;
802 style
.colors
[0] = m_style
.get().colors
[2];
803 style
.alpha
[0] = m_style
.get().alpha
[2];
804 int w
= (int)(m_style
.get().outlineWidthX
+ 0.5);
805 int h
= (int)(m_style
.get().outlineWidthY
+ 0.5);
807 str
.Format(L
"m %d %d l %d %d %d %d %d %d",
810 m_width
+w
, m_ascent
+m_descent
+h
,
811 -w
, m_ascent
+m_descent
+h
);
812 m_pOpaqueBox
.reset( new CPolygon(FwSTSStyle(style
), str
, 0, 0, 0, 1.0/8, 1.0/8, 0, m_target_scale_x
, m_target_scale_y
) );
813 return(!!m_pOpaqueBox
);
816 bool CWord::operator==( const CWord
& rhs
) const
818 return (this==&rhs
) || (
819 m_str
.GetId() == rhs
.m_str
.GetId() &&
820 m_fWhiteSpaceChar
== rhs
.m_fWhiteSpaceChar
&&
821 m_fLineBreak
== rhs
.m_fLineBreak
&&
822 m_style
== rhs
.m_style
&& //fix me:?
823 m_ktype
== rhs
.m_ktype
&&
824 m_kstart
== rhs
.m_kstart
&&
825 m_kend
== rhs
.m_kend
&&
826 m_width
== rhs
.m_width
&&
827 m_ascent
== rhs
.m_ascent
&&
828 m_descent
== rhs
.m_descent
&&
829 m_target_scale_x
== rhs
.m_target_scale_x
&&
830 m_target_scale_y
== rhs
.m_target_scale_y
);
837 CText::CText( const FwSTSStyle
& style
, const CStringW
& str
, int ktype
, int kstart
, int kend
838 , double target_scale_x
/*=1.0*/, double target_scale_y
/*=1.0*/ )
839 : CWord(style
, str
, ktype
, kstart
, kend
, target_scale_x
, target_scale_y
)
841 if(m_str
.Get() == L
" ")
843 m_fWhiteSpaceChar
= true;
845 SharedPtrTextInfo text_info
;
846 TextInfoCacheKey text_info_key
;
847 text_info_key
.m_str_id
= m_str
.GetId();
848 text_info_key
.m_style
= m_style
;
849 text_info_key
.UpdateHashValue();
850 TextInfoMruCache
* text_info_cache
= CacheManager::GetTextInfoCache();
851 POSITION pos
= text_info_cache
->Lookup(text_info_key
);
854 TextInfo
* tmp
=new TextInfo();
855 GetTextInfo(tmp
, m_style
, m_str
.Get());
856 text_info
.reset(tmp
);
857 text_info_cache
->UpdateCache(text_info_key
, text_info
);
861 text_info
= text_info_cache
->GetAt(pos
);
862 text_info_cache
->UpdateCache( pos
);
864 this->m_ascent
= text_info
->m_ascent
;
865 this->m_descent
= text_info
->m_descent
;
866 this->m_width
= text_info
->m_width
;
869 CText::CText( const CText
& src
):CWord(src
)
871 m_width
= src
.m_width
;
874 SharedPtrCWord
CText::Copy()
876 SharedPtrCWord
result(new CText(*this));
880 bool CText::Append(const SharedPtrCWord
& w
)
882 boost::shared_ptr
<CText
> p
= boost::dynamic_pointer_cast
<CText
>(w
);
883 return (p
&& CWord::Append(w
));
886 bool CText::CreatePath(PathData
* path_data
)
888 FwCMyFont
font(m_style
);
889 HFONT hOldFont
= SelectFont(g_hDC
, font
.get());
891 const CStringW
& str
= m_str
.Get();
892 if(m_style
.get().fontSpacing
|| (long)GetVersion() < 0)
894 bool bFirstPath
= true;
895 for(LPCWSTR s
= str
; *s
; s
++)
898 if(!GetTextExtentPoint32W(g_hDC
, s
, 1, &extent
)) {SelectFont(g_hDC
, hOldFont
); ASSERT(0); return(false);}
899 path_data
->PartialBeginPath(g_hDC
, bFirstPath
);
901 TextOutW(g_hDC
, 0, 0, s
, 1);
902 path_data
->PartialEndPath(g_hDC
, width
, 0);
903 width
+= extent
.cx
+ (int)m_style
.get().fontSpacing
;
909 if(!GetTextExtentPoint32W(g_hDC
, str
, str
.GetLength(), &extent
)) {SelectFont(g_hDC
, hOldFont
); ASSERT(0); return(false);}
910 path_data
->BeginPath(g_hDC
);
911 TextOutW(g_hDC
, 0, 0, str
, str
.GetLength());
912 path_data
->EndPath(g_hDC
);
914 SelectFont(g_hDC
, hOldFont
);
918 void CText::GetTextInfo(TextInfo
*output
, const FwSTSStyle
& style
, const CStringW
& str
)
920 FwCMyFont
font(style
);
921 output
->m_ascent
= (int)(style
.get().fontScaleY
/100*font
.get().m_ascent
);
922 output
->m_descent
= (int)(style
.get().fontScaleY
/100*font
.get().m_descent
);
924 HFONT hOldFont
= SelectFont(g_hDC
, font
.get());
925 if(style
.get().fontSpacing
|| (long)GetVersion() < 0)
927 bool bFirstPath
= true;
928 for(LPCWSTR s
= str
; *s
; s
++)
931 if(!GetTextExtentPoint32W(g_hDC
, s
, 1, &extent
)) {SelectFont(g_hDC
, hOldFont
); ASSERT(0); return;}
932 output
->m_width
+= extent
.cx
+ (int)style
.get().fontSpacing
;
934 // m_width -= (int)m_style.get().fontSpacing; // TODO: subtract only at the end of the line
939 if(!GetTextExtentPoint32W(g_hDC
, str
, wcslen(str
), &extent
)) {SelectFont(g_hDC
, hOldFont
); ASSERT(0); return;}
940 output
->m_width
+= extent
.cx
;
942 output
->m_width
= (int)(style
.get().fontScaleX
/100*output
->m_width
+ 4) >> 3;
943 SelectFont(g_hDC
, hOldFont
);
948 CPolygon::CPolygon( const FwSTSStyle
& style
, const CStringW
& str
, int ktype
, int kstart
, int kend
949 , double scalex
, double scaley
, int baseline
950 , double target_scale_x
/*=1.0*/, double target_scale_y
/*=1.0*/
951 , bool round_to_whole_pixel_after_scale_to_target
/*=false*/)
952 : CWord(style
, str
, ktype
, kstart
, kend
, target_scale_x
, target_scale_y
, round_to_whole_pixel_after_scale_to_target
)
953 , m_scalex(scalex
), m_scaley(scaley
), m_baseline(baseline
)
958 CPolygon::CPolygon(CPolygon
& src
) : CWord(src
)
960 m_scalex
= src
.m_scalex
;
961 m_scaley
= src
.m_scaley
;
962 m_baseline
= src
.m_baseline
;
963 m_width
= src
.m_width
;
964 m_ascent
= src
.m_ascent
;
965 m_descent
= src
.m_descent
;
966 m_pathTypesOrg
.Copy(src
.m_pathTypesOrg
);
967 m_pathPointsOrg
.Copy(src
.m_pathPointsOrg
);
970 CPolygon::~CPolygon()
974 SharedPtrCWord
CPolygon::Copy()
976 SharedPtrCWord
result(DEBUG_NEW
CPolygon(*this));
980 bool CPolygon::Append(const SharedPtrCWord
& w
)
986 bool CPolygon::Get6BitFixedPoint(CStringW
& str
, LONG
& ret
)
988 LPWSTR s
= (LPWSTR
)(LPCWSTR
)str
, e
= s
;
989 ret
= wcstod(str
, &e
) * 64;
995 bool CPolygon::GetPOINT(CStringW
& str
, POINT
& ret
)
997 return(Get6BitFixedPoint(str
, ret
.x
) && Get6BitFixedPoint(str
, ret
.y
));
1000 bool CPolygon::ParseStr()
1002 if(m_pathTypesOrg
.GetCount() > 0) return(true);
1004 int j
, lastsplinestart
= -1, firstmoveto
= -1, lastmoveto
= -1;
1005 CStringW str
= m_str
.Get();
1006 str
.SpanIncluding(L
"mnlbspc 0123456789");
1007 str
.Replace(L
"m", L
"*m");
1008 str
.Replace(L
"n", L
"*n");
1009 str
.Replace(L
"l", L
"*l");
1010 str
.Replace(L
"b", L
"*b");
1011 str
.Replace(L
"s", L
"*s");
1012 str
.Replace(L
"p", L
"*p");
1013 str
.Replace(L
"c", L
"*c");
1015 for(CStringW s
= str
.Tokenize(L
"*", k
); !s
.IsEmpty(); s
= str
.Tokenize(L
"*", k
))
1018 s
.TrimLeft(L
"mnlbspc ");
1022 lastmoveto
= m_pathTypesOrg
.GetCount();
1023 if(firstmoveto
== -1)
1024 firstmoveto
= lastmoveto
;
1025 while(GetPOINT(s
, p
)) {
1026 m_pathTypesOrg
.Add(PT_MOVETO
);
1027 m_pathPointsOrg
.Add(p
);
1031 while(GetPOINT(s
, p
)) {
1032 m_pathTypesOrg
.Add(PT_MOVETONC
);
1033 m_pathPointsOrg
.Add(p
);
1037 if (m_pathPointsOrg
.GetCount() < 1) {
1040 while(GetPOINT(s
, p
)) {
1041 m_pathTypesOrg
.Add(PT_LINETO
);
1042 m_pathPointsOrg
.Add(p
);
1046 j
= m_pathTypesOrg
.GetCount();
1050 while(GetPOINT(s
, p
)) {
1051 m_pathTypesOrg
.Add(PT_BEZIERTO
);
1052 m_pathPointsOrg
.Add(p
);
1055 j
= m_pathTypesOrg
.GetCount() - ((m_pathTypesOrg
.GetCount()-j
)%3);
1056 m_pathTypesOrg
.SetCount(j
);
1057 m_pathPointsOrg
.SetCount(j
);
1060 if (m_pathPointsOrg
.GetCount() < 1) {
1064 j
= lastsplinestart
= m_pathTypesOrg
.GetCount();
1066 while(i
-- && GetPOINT(s
, p
)) {
1067 m_pathTypesOrg
.Add(PT_BSPLINETO
);
1068 m_pathPointsOrg
.Add(p
);
1071 if(m_pathTypesOrg
.GetCount()-lastsplinestart
< 3) {
1072 m_pathTypesOrg
.SetCount(lastsplinestart
);
1073 m_pathPointsOrg
.SetCount(lastsplinestart
);
1074 lastsplinestart
= -1;
1079 if (m_pathPointsOrg
.GetCount() < 3) {
1082 while(GetPOINT(s
, p
)) {
1083 m_pathTypesOrg
.Add(PT_BSPLINEPATCHTO
);
1084 m_pathPointsOrg
.Add(p
);
1088 if(lastsplinestart
> 0)
1090 m_pathTypesOrg
.Add(PT_BSPLINEPATCHTO
);
1091 m_pathTypesOrg
.Add(PT_BSPLINEPATCHTO
);
1092 m_pathTypesOrg
.Add(PT_BSPLINEPATCHTO
);
1093 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)
1094 m_pathPointsOrg
.Add(p
);
1095 p
= m_pathPointsOrg
[lastsplinestart
];
1096 m_pathPointsOrg
.Add(p
);
1097 p
= m_pathPointsOrg
[lastsplinestart
+1];
1098 m_pathPointsOrg
.Add(p
);
1099 lastsplinestart
= -1;
1106 if(lastmoveto
== -1 || firstmoveto
> 0)
1108 m_pathTypesOrg
.RemoveAll();
1109 m_pathPointsOrg
.RemoveAll();
1112 int minx
= INT_MAX
, miny
= INT_MAX
, maxx
= -INT_MAX
, maxy
= -INT_MAX
;
1113 for(size_t i
= 0; i
< m_pathTypesOrg
.GetCount(); i
++)
1115 m_pathPointsOrg
[i
].x
= (int)(m_scalex
* m_pathPointsOrg
[i
].x
);
1116 m_pathPointsOrg
[i
].y
= (int)(m_scaley
* m_pathPointsOrg
[i
].y
);
1117 if(minx
> m_pathPointsOrg
[i
].x
) minx
= m_pathPointsOrg
[i
].x
;
1118 if(miny
> m_pathPointsOrg
[i
].y
) miny
= m_pathPointsOrg
[i
].y
;
1119 if(maxx
< m_pathPointsOrg
[i
].x
) maxx
= m_pathPointsOrg
[i
].x
;
1120 if(maxy
< m_pathPointsOrg
[i
].y
) maxy
= m_pathPointsOrg
[i
].y
;
1122 m_width
= max(maxx
- minx
, 0);
1123 m_ascent
= max(maxy
- miny
, 0);
1124 int baseline
= (int)(64 * m_scaley
* m_baseline
);
1125 m_descent
= baseline
;
1126 m_ascent
-= baseline
;
1127 m_width
= ((int)(m_style
.get().fontScaleX
/100 * m_width
) + 4) >> 3;
1128 m_ascent
= ((int)(m_style
.get().fontScaleY
/100 * m_ascent
) + 4) >> 3;
1129 m_descent
= ((int)(m_style
.get().fontScaleY
/100 * m_descent
) + 4) >> 3;
1133 bool CPolygon::CreatePath(PathData
* path_data
)
1135 int len
= m_pathTypesOrg
.GetCount();
1136 if(len
== 0) return(false);
1137 if(path_data
->mPathPoints
!= len
)
1139 path_data
->mpPathTypes
= (BYTE
*)realloc(path_data
->mpPathTypes
, len
*sizeof(BYTE
));
1140 path_data
->mpPathPoints
= (POINT
*)realloc(path_data
->mpPathPoints
, len
*sizeof(POINT
));
1141 if(!path_data
->mpPathTypes
|| !path_data
->mpPathPoints
) return(false);
1142 path_data
->mPathPoints
= len
;
1144 memcpy(path_data
->mpPathTypes
, m_pathTypesOrg
.GetData(), len
*sizeof(BYTE
));
1145 memcpy(path_data
->mpPathPoints
, m_pathPointsOrg
.GetData(), len
*sizeof(POINT
));
1151 CClipper::CClipper(CStringW str
, CSizeCoor2 size
, double scalex
, double scaley
, bool inverse
1152 , double target_scale_x
/*=1.0*/, double target_scale_y
/*=1.0*/)
1153 : m_polygon( new CPolygon(FwSTSStyle(), str
, 0, 0, 0, scalex
, scaley
, 0, target_scale_x
, target_scale_y
, true) )
1154 , m_size(size
), m_inverse(inverse
)
1155 , m_effectType(-1), m_painted(false)
1160 CClipper::~CClipper()
1164 GrayImage2
* CClipper::PaintSimpleClipper()
1166 GrayImage2
* result
= NULL
;
1167 if(m_size
.cx
< 0 || m_size
.cy
< 0)
1170 SharedPtrOverlay overlay
;
1171 CWordPaintMachine::PaintBody( m_polygon
, CPoint(0, 0), CPoint(0, 0), &overlay
);
1172 int w
= overlay
->mOverlayWidth
, h
= overlay
->mOverlayHeight
;
1173 int x
= (overlay
->mOffsetX
+4)>>3, y
= (overlay
->mOffsetY
+4)>>3;
1174 result
= new GrayImage2();
1177 result
->data
= overlay
->mBody
;
1178 result
->pitch
= overlay
->mOverlayPitch
;
1179 result
->size
.SetSize(w
, h
);
1180 result
->left_top
.SetPoint(x
, y
);
1184 GrayImage2
* CClipper::PaintBaseClipper()
1186 GrayImage2
* result
= NULL
;
1187 //m_pAlphaMask = NULL;
1188 if(m_size
.cx
< 0 || m_size
.cy
< 0)
1191 SharedPtrOverlay overlay
;
1192 CWordPaintMachine::PaintBody( m_polygon
, CPoint(0, 0), CPoint(0, 0), &overlay
);
1193 int w
= overlay
->mOverlayWidth
, h
= overlay
->mOverlayHeight
;
1194 int x
= (overlay
->mOffsetX
+4)>>3, y
= (overlay
->mOffsetY
+4)>>3;
1196 if(x
< 0) {xo
= -x
; w
-= -x
; x
= 0;}
1197 if(y
< 0) {yo
= -y
; h
-= -y
; y
= 0;}
1198 if(x
+w
> m_size
.cx
) w
= m_size
.cx
-x
;
1199 if(y
+h
> m_size
.cy
) h
= m_size
.cy
-y
;
1200 if(w
<= 0 || h
<= 0) return result
;
1202 result
= new GrayImage2();
1205 result
->data
.reset( reinterpret_cast<BYTE
*>(xy_malloc(m_size
.cx
*m_size
.cy
)), xy_free
);
1206 result
->pitch
= m_size
.cx
;
1207 result
->size
= m_size
;
1208 result
->left_top
.SetPoint(0, 0);
1210 BYTE
* result_data
= result
->data
.get();
1217 memset( result_data
, 0, m_size
.cx
*m_size
.cy
);
1219 const BYTE
* src
= overlay
->mBody
.get() + (overlay
->mOverlayPitch
* yo
+ xo
);
1220 BYTE
* dst
= result_data
+ m_size
.cx
* y
+ x
;
1223 //for(int wt=0; wt<w; ++wt)
1224 // dst[wt] = src[wt];
1225 memcpy(dst
, src
, w
);
1226 src
+= overlay
->mOverlayPitch
;
1231 BYTE
* dst
= result_data
;
1232 for(int i
= m_size
.cx
*m_size
.cy
; i
>0; --i
, ++dst
)
1233 *dst
= 0x40 - *dst
; // mask is 6 bit
1238 GrayImage2
* CClipper::PaintBannerClipper()
1242 int width
= static_cast<int>(m_effect
.param
[2] * m_polygon
->m_target_scale_x
);//fix me: rounding err
1243 int w
= m_size
.cx
, h
= m_size
.cy
;
1245 GrayImage2
* result
= PaintBaseClipper();
1249 int da
= (64<<8)/width
;
1250 BYTE
* am
= result
->data
.get();
1251 for(int j
= 0; j
< h
; j
++, am
+= w
)
1254 int k
= min(width
, w
);
1255 for(int i
= 0; i
< k
; i
++, a
+= da
)
1256 am
[i
] = (am
[i
]*a
)>>14;
1259 if(k
< 0) {a
-= -k
*da
; k
= 0;}
1260 for(int i
= k
; i
< w
; i
++, a
-= da
)
1261 am
[i
] = (am
[i
]*a
)>>14;
1266 GrayImage2
* CClipper::PaintScrollClipper()
1270 int height
= static_cast<int>(m_effect
.param
[4] * m_polygon
->m_target_scale_y
);//fix me: rounding err
1271 int w
= m_size
.cx
, h
= m_size
.cy
;
1273 GrayImage2
* result
= PaintBaseClipper();
1277 BYTE
* data
= result
->data
.get();
1279 int da
= (64<<8)/height
;
1281 int k
= (static_cast<int>(m_effect
.param
[0] * m_polygon
->m_target_scale_y
)>>3);//fix me: rounding err
1283 if(k
< 0) {a
+= -k
*da
; k
= 0;}
1287 BYTE
* am
= &data
[k
*w
];
1288 memset(data
, 0, am
- data
);
1289 for(int j
= k
; j
< l
; j
++, a
+= da
)
1291 for(int i
= 0; i
< w
; i
++, am
++)
1292 *am
= ((*am
)*a
)>>14;
1295 da
= -(64<<8)/height
;
1297 l
= (static_cast<int>(m_effect
.param
[1] * m_polygon
->m_target_scale_y
)>>3);//fix me: rounding err
1299 if(k
< 0) {a
+= -k
*da
; k
= 0;}
1303 BYTE
* am
= &data
[k
*w
];
1305 for(; j
< l
; j
++, a
+= da
)
1307 for(int i
= 0; i
< w
; i
++, am
++)
1308 *am
= ((*am
)*a
)>>14;
1310 memset(am
, 0, (h
-j
)*w
);
1315 GrayImage2
* CClipper::Paint()
1317 GrayImage2
* result
= NULL
;
1318 switch(m_effectType
)
1323 result
= PaintSimpleClipper();
1327 result
= PaintBaseClipper();
1331 result
= PaintBannerClipper();
1334 result
= PaintScrollClipper();
1340 void CClipper::SetEffect( const Effect
& effect
, int effectType
)
1342 m_effectType
= effectType
;
1346 SharedPtrGrayImage2
CClipper::GetAlphaMask( const SharedPtrCClipper
& clipper
)
1348 SharedPtrGrayImage2 result
;
1349 CClipperPaintMachine
paint_machine(clipper
);
1350 paint_machine
.Paint(&result
);
1358 //POSITION pos = GetHeadPosition();
1359 //while(pos) delete GetNext(pos);
1362 void CLine::Compact()
1364 POSITION pos
= GetHeadPosition();
1367 SharedPtrCWord w
= GetNext(pos
);
1368 if(!w
->m_fWhiteSpaceChar
) break;
1369 m_width
-= w
->m_width
;
1373 pos
= GetTailPosition();
1376 SharedPtrCWord w
= GetPrev(pos
);
1377 if(!w
->m_fWhiteSpaceChar
) break;
1378 m_width
-= w
->m_width
;
1382 if(IsEmpty()) return;
1384 l
.AddTailList(this);
1386 SharedPtrCWord last
;
1387 pos
= l
.GetHeadPosition();
1390 SharedPtrCWord w
= l
.GetNext(pos
);
1391 if(!last
|| !last
->Append(w
))
1392 AddTail(last
= w
->Copy());
1394 m_ascent
= m_descent
= m_borderX
= m_borderY
= 0;
1395 pos
= GetHeadPosition();
1398 SharedPtrCWord w
= GetNext(pos
);
1399 if(m_ascent
< w
->m_ascent
) m_ascent
= w
->m_ascent
;
1400 if(m_descent
< w
->m_descent
) m_descent
= w
->m_descent
;
1401 if(m_borderX
< w
->m_style
.get().outlineWidthX
) m_borderX
= (int)(w
->m_style
.get().outlineWidthX
+0.5);
1402 if(m_borderY
< w
->m_style
.get().outlineWidthY
) m_borderY
= (int)(w
->m_style
.get().outlineWidthY
+0.5);
1406 CRectCoor2
CLine::PaintAll( CompositeDrawItemList
* output
, const CRectCoor2
& clipRect
,
1407 const SharedPtrCClipperPaintMachine
&clipper
, CPoint p
, const CPoint
& org
, const int time
, const int alpha
)
1409 CRectCoor2
bbox(0, 0, 0, 0);
1410 POSITION pos
= GetHeadPosition();
1411 POSITION outputPos
= output
->GetHeadPosition();
1414 SharedPtrCWord w
= GetNext(pos
);
1415 CompositeDrawItem
& outputItem
= output
->GetNext(outputPos
);
1416 if(w
->m_fLineBreak
) return(bbox
); // should not happen since this class is just a line of text without any breaks
1417 CPointCoor2 shadowPos
, outlinePos
, bodyPos
, org_coor2
;
1419 double shadowPos_x
= p
.x
+ w
->m_style
.get().shadowDepthX
;
1420 double shadowPos_y
= p
.y
+ m_ascent
- w
->m_ascent
+ w
->m_style
.get().shadowDepthY
;
1421 outlinePos
= CPoint(p
.x
, p
.y
+ m_ascent
- w
->m_ascent
);
1422 bodyPos
= CPoint(p
.x
, p
.y
+ m_ascent
- w
->m_ascent
);
1424 shadowPos
.x
= static_cast<int>(shadowPos_x
* w
->m_target_scale_x
+ 0.5);
1425 shadowPos
.y
= static_cast<int>(shadowPos_y
* w
->m_target_scale_y
+ 0.5);
1426 outlinePos
.x
*= w
->m_target_scale_x
;
1427 outlinePos
.y
*= w
->m_target_scale_y
;
1428 bodyPos
.x
*= w
->m_target_scale_x
;
1429 bodyPos
.y
*= w
->m_target_scale_y
;
1430 org_coor2
.x
= org
.x
* w
->m_target_scale_x
;//fix me: move it out of this loop
1431 org_coor2
.y
= org
.y
* w
->m_target_scale_y
;
1433 bool hasShadow
= w
->m_style
.get().shadowDepthX
!= 0 || w
->m_style
.get().shadowDepthY
!= 0;
1434 bool hasOutline
= ((w
->m_style
.get().outlineWidthX
*w
->m_target_scale_x
+0.5>=1.0) ||
1435 (w
->m_style
.get().outlineWidthY
*w
->m_target_scale_y
+0.5)>=1.0) && !(w
->m_ktype
== 2 && time
< w
->m_kstart
);
1436 bool hasBody
= true;
1438 SharedPtrOverlayPaintMachine shadow_pm
, outline_pm
, body_pm
;
1439 CWordPaintMachine::CreatePaintMachines(w
, shadowPos
, outlinePos
, bodyPos
, org_coor2
,
1440 hasShadow
? &shadow_pm
: NULL
,
1441 hasOutline
? &outline_pm
: NULL
,
1442 hasBody
? &body_pm
: NULL
);
1447 DWORD a
= 0xff - w
->m_style
.get().alpha
[3];
1448 if(alpha
> 0) a
= MulDiv(a
, 0xff - alpha
, 0xff);
1449 COLORREF shadow
= revcolor(w
->m_style
.get().colors
[3]) | (a
<<24);
1450 DWORD sw
[6] = {shadow
, -1};
1451 sw
[0] = XySubRenderFrameCreater::GetDefaultCreater()->TransColor(sw
[0]);
1452 if(w
->m_style
.get().borderStyle
== 0)
1454 outputItem
.shadow
.reset(
1455 DrawItem::CreateDrawItem(shadow_pm
, clipRect
, clipper
, shadowPos
.x
, shadowPos
.y
, sw
,
1456 w
->m_ktype
> 0 || w
->m_style
.get().alpha
[0] < 0xff,
1460 else if(w
->m_style
.get().borderStyle
== 1)
1462 outputItem
.shadow
.reset(
1463 DrawItem::CreateDrawItem( shadow_pm
, clipRect
, clipper
, shadowPos
.x
, shadowPos
.y
, sw
, true, false)
1470 DWORD aoutline
= w
->m_style
.get().alpha
[2];
1471 if(alpha
> 0) aoutline
+= MulDiv(alpha
, 0xff - w
->m_style
.get().alpha
[2], 0xff);
1472 COLORREF outline
= revcolor(w
->m_style
.get().colors
[2]) | ((0xff-aoutline
)<<24);
1473 DWORD sw
[6] = {outline
, -1};
1474 sw
[0] = XySubRenderFrameCreater::GetDefaultCreater()->TransColor(sw
[0]);
1475 if(w
->m_style
.get().borderStyle
== 0)
1477 outputItem
.outline
.reset(
1478 DrawItem::CreateDrawItem(outline_pm
, clipRect
, clipper
, outlinePos
.x
, outlinePos
.y
, sw
,
1479 !w
->m_style
.get().alpha
[0] && !w
->m_style
.get().alpha
[1] && !alpha
, true)
1482 else if(w
->m_style
.get().borderStyle
== 1)
1484 outputItem
.outline
.reset(
1485 DrawItem::CreateDrawItem(outline_pm
, clipRect
, clipper
, outlinePos
.x
, outlinePos
.y
, sw
, true, false)
1493 DWORD aprimary
= w
->m_style
.get().alpha
[0];
1494 if(alpha
> 0) aprimary
+= MulDiv(alpha
, 0xff - w
->m_style
.get().alpha
[0], 0xff);
1495 COLORREF primary
= revcolor(w
->m_style
.get().colors
[0]) | ((0xff-aprimary
)<<24);
1496 DWORD asecondary
= w
->m_style
.get().alpha
[1];
1497 if(alpha
> 0) asecondary
+= MulDiv(alpha
, 0xff - w
->m_style
.get().alpha
[1], 0xff);
1498 COLORREF secondary
= revcolor(w
->m_style
.get().colors
[1]) | ((0xff-asecondary
)<<24);
1499 DWORD sw
[6] = {primary
, 0, secondary
};
1502 if(w
->m_ktype
== 0 || w
->m_ktype
== 2)
1504 t
= time
< w
->m_kstart
? 0 : 1;
1506 else if(w
->m_ktype
== 1)
1508 if(time
< w
->m_kstart
) t
= 0;
1509 else if(time
< w
->m_kend
)
1511 t
= 1.0 * (time
- w
->m_kstart
) / (w
->m_kend
- w
->m_kstart
);
1512 double angle
= fmod(w
->m_style
.get().fontAngleZ
, 360.0);
1513 if(angle
> 90 && angle
< 270)
1516 COLORREF tmp
= sw
[0];
1527 sw
[3] = (int)( (w
->m_style
.get().outlineWidthX
+ t
*w
->m_width
)*w
->m_target_scale_x
) >> 3;
1530 sw
[0] = XySubRenderFrameCreater::GetDefaultCreater()->TransColor(sw
[0]);
1531 sw
[2] = XySubRenderFrameCreater::GetDefaultCreater()->TransColor(sw
[2]);
1532 sw
[4] = XySubRenderFrameCreater::GetDefaultCreater()->TransColor(sw
[4]);
1533 outputItem
.body
.reset(
1534 DrawItem::CreateDrawItem(body_pm
, clipRect
, clipper
, bodyPos
.x
, bodyPos
.y
, sw
, true, false)
1537 bbox
|= CompositeDrawItem::GetDirtyRect(outputItem
);
1543 void CLine::AddWord2Tail( SharedPtrCWord words
)
1545 __super::AddTail(words
);
1548 bool CLine::IsEmpty()
1550 return __super::IsEmpty();
1553 int CLine::GetWordCount()
1560 CSubtitle::CSubtitle()
1562 memset(m_effects
, 0, sizeof(Effect
*)*EF_NUMBEROFEFFECTS
);
1563 m_clipInverse
= false;
1564 m_scalex
= m_scaley
= 1;
1565 m_fAnimated2
= false;
1567 m_target_scale_x
= m_target_scale_y
= 1.0;
1570 CSubtitle::~CSubtitle()
1575 void CSubtitle::Empty()
1577 POSITION pos
= GetHeadPosition();
1578 while(pos
) delete GetNext(pos
);
1579 // pos = m_words.GetHeadPosition();
1580 // while(pos) delete m_words.GetNext(pos);
1581 for(int i
= 0; i
< EF_NUMBEROFEFFECTS
; i
++) {if(m_effects
[i
]) delete m_effects
[i
];}
1582 memset(m_effects
, 0, sizeof(Effect
*)*EF_NUMBEROFEFFECTS
);
1585 int CSubtitle::GetFullWidth()
1588 POSITION pos
= m_words
.GetHeadPosition();
1589 while(pos
) width
+= m_words
.GetNext(pos
)->m_width
;
1593 int CSubtitle::GetFullLineWidth(POSITION pos
)
1598 SharedPtrCWord w
= m_words
.GetNext(pos
);
1599 if(w
->m_fLineBreak
) break;
1600 width
+= w
->m_width
;
1605 int CSubtitle::GetWrapWidth(POSITION pos
, int maxwidth
)
1607 if(m_wrapStyle
== 0 || m_wrapStyle
== 3)
1611 // int fullwidth = GetFullWidth();
1612 int fullwidth
= GetFullLineWidth(pos
);
1613 int minwidth
= fullwidth
/ ((abs(fullwidth
) / maxwidth
) + 1);
1614 int width
= 0, wordwidth
= 0;
1615 while(pos
&& width
< minwidth
)
1617 SharedPtrCWord w
= m_words
.GetNext(pos
);
1618 wordwidth
= w
->m_width
;
1619 if(abs(width
+ wordwidth
) < abs(maxwidth
)) width
+= wordwidth
;
1622 if(m_wrapStyle
== 3 && pos
) maxwidth
-= wordwidth
;
1625 else if(m_wrapStyle
== 1)
1627 // maxwidth = maxwidth;
1629 else if(m_wrapStyle
== 2)
1636 CLine
* CSubtitle::GetNextLine(POSITION
& pos
, int maxwidth
)
1638 if(pos
== NULL
) return(NULL
);
1639 CLine
* ret
= new CLine();
1640 if(!ret
) return(NULL
);
1641 ret
->m_width
= ret
->m_ascent
= ret
->m_descent
= ret
->m_borderX
= ret
->m_borderY
= 0;
1642 maxwidth
= GetWrapWidth(pos
, maxwidth
);
1643 bool fEmptyLine
= true;
1646 SharedPtrCWord w
= m_words
.GetNext(pos
);
1647 if(ret
->m_ascent
< w
->m_ascent
) ret
->m_ascent
= w
->m_ascent
;
1648 if(ret
->m_descent
< w
->m_descent
) ret
->m_descent
= w
->m_descent
;
1649 if(ret
->m_borderX
< w
->m_style
.get().outlineWidthX
) ret
->m_borderX
= (int)(w
->m_style
.get().outlineWidthX
+0.5);
1650 if(ret
->m_borderY
< w
->m_style
.get().outlineWidthY
) ret
->m_borderY
= (int)(w
->m_style
.get().outlineWidthY
+0.5);
1653 if(fEmptyLine
) {ret
->m_ascent
/= 2; ret
->m_descent
/= 2; ret
->m_borderX
= ret
->m_borderY
= 0;}
1658 bool fWSC
= w
->m_fWhiteSpaceChar
;
1659 int width
= w
->m_width
;
1660 POSITION pos2
= pos
;
1663 if(m_words
.GetAt(pos2
)->m_fWhiteSpaceChar
!= fWSC
1664 || m_words
.GetAt(pos2
)->m_fLineBreak
) break;
1665 SharedPtrCWord w2
= m_words
.GetNext(pos2
);
1666 width
+= w2
->m_width
;
1668 if((ret
->m_width
+= width
) <= maxwidth
|| ret
->IsEmpty())
1670 ret
->AddWord2Tail(w
);
1673 ret
->AddWord2Tail(m_words
.GetNext(pos
));
1679 if(pos
) m_words
.GetPrev(pos
);
1680 else pos
= m_words
.GetTailPosition();
1681 ret
->m_width
-= width
;
1689 void CSubtitle::CreateClippers( CSize size1
, const CSizeCoor2
& size_scale_to
)
1693 if(m_effects
[EF_BANNER
] && m_effects
[EF_BANNER
]->param
[2])
1695 int w
= size1
.cx
, h
= size1
.cy
;
1699 str
.Format(L
"m %d %d l %d %d %d %d %d %d", 0, 0, w
, 0, w
, h
, 0, h
);
1700 m_pClipper
.reset( new CClipper(str
, size_scale_to
, 1, 1, false, m_target_scale_x
, m_target_scale_y
) );
1701 if(!m_pClipper
) return;
1703 m_pClipper
->SetEffect( *m_effects
[EF_BANNER
], EF_BANNER
);
1705 else if(m_effects
[EF_SCROLL
] && m_effects
[EF_SCROLL
]->param
[4])
1707 int height
= m_effects
[EF_SCROLL
]->param
[4];
1708 int w
= size1
.cx
, h
= size1
.cy
;
1712 str
.Format(L
"m %d %d l %d %d %d %d %d %d", 0, 0, w
, 0, w
, h
, 0, h
);
1713 m_pClipper
.reset( new CClipper(str
, size_scale_to
, 1, 1, false, m_target_scale_x
, m_target_scale_y
) );
1714 if(!m_pClipper
) return;
1716 m_pClipper
->SetEffect(*m_effects
[EF_SCROLL
], EF_SCROLL
);
1720 void CSubtitle::MakeLines(CSize size
, CRect marginRect
)
1722 CSize
spaceNeeded(0, 0);
1723 bool fFirstLine
= true;
1724 m_topborder
= m_bottomborder
= 0;
1726 POSITION pos
= m_words
.GetHeadPosition();
1729 l
= GetNextLine(pos
, size
.cx
- marginRect
.left
- marginRect
.right
);
1731 if(fFirstLine
) {m_topborder
= l
->m_borderY
; fFirstLine
= false;}
1732 spaceNeeded
.cx
= max(l
->m_width
+l
->m_borderX
, spaceNeeded
.cx
);
1733 spaceNeeded
.cy
+= l
->m_ascent
+ l
->m_descent
;
1736 if(l
) m_bottomborder
= l
->m_borderY
;
1738 CPoint((m_scrAlignment
%3) == 1 ? marginRect
.left
1739 : (m_scrAlignment
%3) == 2 ? (marginRect
.left
+ (size
.cx
- marginRect
.right
) - spaceNeeded
.cx
+ 1) / 2
1740 : (size
.cx
- marginRect
.right
- spaceNeeded
.cx
),
1741 m_scrAlignment
<= 3 ? (size
.cy
- marginRect
.bottom
- spaceNeeded
.cy
)
1742 : m_scrAlignment
<= 6 ? (marginRect
.top
+ (size
.cy
- marginRect
.bottom
) - spaceNeeded
.cy
+ 1) / 2
1747 POSITION
CSubtitle::GetHeadLinePosition()
1749 return __super::GetHeadPosition();
1752 CLine
* CSubtitle::GetNextLine( POSITION
& pos
)
1754 return __super::GetNext(pos
);
1757 // CScreenLayoutAllocator
1759 void CScreenLayoutAllocator::Empty()
1761 m_subrects
.RemoveAll();
1764 void CScreenLayoutAllocator::AdvanceToSegment(int segment
, const CAtlArray
<int>& sa
)
1766 POSITION pos
= m_subrects
.GetHeadPosition();
1769 POSITION prev
= pos
;
1770 SubRect
& sr
= m_subrects
.GetNext(pos
);
1771 bool fFound
= false;
1772 if(abs(sr
.segment
- segment
) <= 1) // using abs() makes it possible to play the subs backwards, too :)
1774 for(size_t i
= 0; i
< sa
.GetCount() && !fFound
; i
++)
1776 if(sa
[i
] == sr
.entry
)
1778 sr
.segment
= segment
;
1783 if(!fFound
) m_subrects
.RemoveAt(prev
);
1787 CRect
CScreenLayoutAllocator::AllocRect(CSubtitle
* s
, int segment
, int entry
, int layer
, int collisions
)
1789 // TODO: handle collisions == 1 (reversed collisions)
1790 POSITION pos
= m_subrects
.GetHeadPosition();
1793 SubRect
& sr
= m_subrects
.GetNext(pos
);
1794 if(sr
.segment
== segment
&& sr
.entry
== entry
)
1796 return(sr
.r
+ CRect(0, -s
->m_topborder
, 0, -s
->m_bottomborder
));
1799 CRect r
= s
->m_rect
+ CRect(0, s
->m_topborder
, 0, s
->m_bottomborder
);
1800 bool fSearchDown
= s
->m_scrAlignment
> 3;
1805 pos
= m_subrects
.GetHeadPosition();
1808 SubRect
& sr
= m_subrects
.GetNext(pos
);
1809 if(layer
== sr
.layer
&& !(r
& sr
.r
).IsRectEmpty())
1813 r
.bottom
= sr
.r
.bottom
+ r
.Height();
1814 r
.top
= sr
.r
.bottom
;
1818 r
.top
= sr
.r
.top
- r
.Height();
1819 r
.bottom
= sr
.r
.top
;
1828 sr
.segment
= segment
;
1831 m_subrects
.AddTail(sr
);
1832 return(sr
.r
+ CRect(0, -s
->m_topborder
, 0, -s
->m_bottomborder
));
1835 // CRenderedTextSubtitle
1837 CAtlMap
<CStringW
, CRenderedTextSubtitle::AssCmdType
, CStringElementTraits
<CStringW
>> CRenderedTextSubtitle::m_cmdMap
;
1839 CRenderedTextSubtitle::CRenderedTextSubtitle(CCritSec
* pLock
)
1840 : CSubPicProviderImpl(pLock
)
1841 , m_target_scale_x(1.0), m_target_scale_y(1.0)
1843 if( m_cmdMap
.IsEmpty() )
1847 m_size
= CSize(0, 0);
1848 if(g_hDC_refcnt
== 0)
1850 g_hDC
= CreateCompatibleDC(NULL
);
1851 SetBkMode(g_hDC
, TRANSPARENT
);
1852 SetTextColor(g_hDC
, 0xffffff);
1853 SetMapMode(g_hDC
, MM_TEXT
);
1858 CRenderedTextSubtitle::~CRenderedTextSubtitle()
1862 if(g_hDC_refcnt
== 0) DeleteDC(g_hDC
);
1865 void CRenderedTextSubtitle::InitCmdMap()
1867 if( m_cmdMap
.IsEmpty() )
1869 m_cmdMap
.SetAt(L
"1c", CMD_1c
);
1870 m_cmdMap
.SetAt(L
"2c", CMD_2c
);
1871 m_cmdMap
.SetAt(L
"3c", CMD_3c
);
1872 m_cmdMap
.SetAt(L
"4c", CMD_4c
);
1873 m_cmdMap
.SetAt(L
"1a", CMD_1a
);
1874 m_cmdMap
.SetAt(L
"2a", CMD_2a
);
1875 m_cmdMap
.SetAt(L
"3a", CMD_3a
);
1876 m_cmdMap
.SetAt(L
"4a", CMD_4a
);
1877 m_cmdMap
.SetAt(L
"alpha", CMD_alpha
);
1878 m_cmdMap
.SetAt(L
"an", CMD_an
);
1879 m_cmdMap
.SetAt(L
"a", CMD_a
);
1880 m_cmdMap
.SetAt(L
"blur", CMD_blur
);
1881 m_cmdMap
.SetAt(L
"bord", CMD_bord
);
1882 m_cmdMap
.SetAt(L
"be", CMD_be
);
1883 m_cmdMap
.SetAt(L
"b", CMD_b
);
1884 m_cmdMap
.SetAt(L
"clip", CMD_clip
);
1885 m_cmdMap
.SetAt(L
"iclip", CMD_iclip
);
1886 m_cmdMap
.SetAt(L
"c", CMD_c
);
1887 m_cmdMap
.SetAt(L
"fade", CMD_fade
);
1888 m_cmdMap
.SetAt(L
"fad", CMD_fad
);
1889 m_cmdMap
.SetAt(L
"fax", CMD_fax
);
1890 m_cmdMap
.SetAt(L
"fay", CMD_fay
);
1891 m_cmdMap
.SetAt(L
"fe", CMD_fe
);
1892 m_cmdMap
.SetAt(L
"fn", CMD_fn
);
1893 m_cmdMap
.SetAt(L
"frx", CMD_frx
);
1894 m_cmdMap
.SetAt(L
"fry", CMD_fry
);
1895 m_cmdMap
.SetAt(L
"frz", CMD_frz
);
1896 m_cmdMap
.SetAt(L
"fr", CMD_fr
);
1897 m_cmdMap
.SetAt(L
"fscx", CMD_fscx
);
1898 m_cmdMap
.SetAt(L
"fscy", CMD_fscy
);
1899 m_cmdMap
.SetAt(L
"fsc", CMD_fsc
);
1900 m_cmdMap
.SetAt(L
"fsp", CMD_fsp
);
1901 m_cmdMap
.SetAt(L
"fs", CMD_fs
);
1902 m_cmdMap
.SetAt(L
"i", CMD_i
);
1903 m_cmdMap
.SetAt(L
"kt", CMD_kt
);
1904 m_cmdMap
.SetAt(L
"kf", CMD_kf
);
1905 m_cmdMap
.SetAt(L
"K", CMD_K
);
1906 m_cmdMap
.SetAt(L
"ko", CMD_ko
);
1907 m_cmdMap
.SetAt(L
"k", CMD_k
);
1908 m_cmdMap
.SetAt(L
"move", CMD_move
);
1909 m_cmdMap
.SetAt(L
"org", CMD_org
);
1910 m_cmdMap
.SetAt(L
"pbo", CMD_pbo
);
1911 m_cmdMap
.SetAt(L
"pos", CMD_pos
);
1912 m_cmdMap
.SetAt(L
"p", CMD_p
);
1913 m_cmdMap
.SetAt(L
"q", CMD_q
);
1914 m_cmdMap
.SetAt(L
"r", CMD_r
);
1915 m_cmdMap
.SetAt(L
"shad", CMD_shad
);
1916 m_cmdMap
.SetAt(L
"s", CMD_s
);
1917 m_cmdMap
.SetAt(L
"t", CMD_t
);
1918 m_cmdMap
.SetAt(L
"u", CMD_u
);
1919 m_cmdMap
.SetAt(L
"xbord", CMD_xbord
);
1920 m_cmdMap
.SetAt(L
"xshad", CMD_xshad
);
1921 m_cmdMap
.SetAt(L
"ybord", CMD_ybord
);
1922 m_cmdMap
.SetAt(L
"yshad", CMD_yshad
);
1926 void CRenderedTextSubtitle::Copy(CSimpleTextSubtitle
& sts
)
1929 m_size
= CSize(0, 0);
1930 if(CRenderedTextSubtitle
* pRTS
= dynamic_cast<CRenderedTextSubtitle
*>(&sts
))
1932 m_size
= pRTS
->m_size
;
1936 void CRenderedTextSubtitle::Empty()
1942 void CRenderedTextSubtitle::OnChanged()
1944 __super::OnChanged();
1945 POSITION pos
= m_subtitleCache
.GetStartPosition();
1950 m_subtitleCache
.GetNextAssoc(pos
, i
, s
);
1953 m_subtitleCache
.RemoveAll();
1958 bool CRenderedTextSubtitle::Init( const SIZECoor2
& size_scale_to
, const SIZE
& size1
, const CRect
& video_rect
)
1961 m_size_scale_to
= CSize(size_scale_to
.cx
*8, size_scale_to
.cy
*8);//fix me?
1962 m_size
= CSize(size1
.cx
*8, size1
.cy
*8);
1963 m_vidrect
= CRect(video_rect
.left
*8, video_rect
.top
*8, video_rect
.right
*8, video_rect
.bottom
*8);
1965 ASSERT(size1
.cx
!=0 && size1
.cy
!=0);
1967 m_target_scale_x
= size_scale_to
.cx
* 1.0 / size1
.cx
;
1968 m_target_scale_y
= size_scale_to
.cy
* 1.0 / size1
.cy
;
1973 void CRenderedTextSubtitle::Deinit()
1975 POSITION pos
= m_subtitleCache
.GetStartPosition();
1980 m_subtitleCache
.GetNextAssoc(pos
, i
, s
);
1983 m_subtitleCache
.RemoveAll();
1986 m_size_scale_to
= CSize(0, 0);
1987 m_size
= CSize(0, 0);
1988 m_vidrect
.SetRectEmpty();
1990 m_target_scale_x
= m_target_scale_y
= 1.0;
1992 CacheManager::GetBitmapMruCache()->RemoveAll();
1994 CacheManager::GetClipperAlphaMaskMruCache()->RemoveAll();
1995 CacheManager::GetTextInfoCache()->RemoveAll();
1996 CacheManager::GetAssTagListMruCache()->RemoveAll();
1998 CacheManager::GetScanLineDataMruCache()->RemoveAll();
1999 CacheManager::GetOverlayNoOffsetMruCache()->RemoveAll();
2001 CacheManager::GetSubpixelVarianceCache()->RemoveAll();
2002 CacheManager::GetOverlayMruCache()->RemoveAll();
2003 CacheManager::GetOverlayNoBlurMruCache()->RemoveAll();
2004 CacheManager::GetScanLineData2MruCache()->RemoveAll();
2005 CacheManager::GetPathDataMruCache()->RemoveAll();
2008 void CRenderedTextSubtitle::ParseEffect(CSubtitle
* sub
, const CStringW
& str
)
2010 CStringW::PCXSTR str_start
= str
.GetString();
2011 CStringW::PCXSTR str_end
= str_start
+ str
.GetLength();
2012 str_start
= SkipWhiteSpaceLeft(str_start
, str_end
);
2014 if(!sub
|| *str_start
==0)
2017 str_end
= FastSkipWhiteSpaceRight(str_start
, str_end
);
2019 const WCHAR
* s
= FindChar(str_start
, str_end
, L
';');
2024 const CStringW
effect(str_start
, s
-str_start
);
2025 if(!effect
.CompareNoCase( L
"Banner;" ) )
2027 int delay
, lefttoright
= 0, fadeawaywidth
= 0;
2028 if(swscanf(s
, L
"%d;%d;%d", &delay
, &lefttoright
, &fadeawaywidth
) < 1) return;
2029 Effect
* e
= new Effect
;
2031 sub
->m_effects
[e
->type
= EF_BANNER
] = e
;
2032 e
->param
[0] = (int)(max(1.0*delay
/sub
->m_scalex
, 1));
2033 e
->param
[1] = lefttoright
;
2034 e
->param
[2] = (int)(sub
->m_scalex
*fadeawaywidth
);
2035 sub
->m_wrapStyle
= 2;
2037 else if(!effect
.CompareNoCase(L
"Scroll up;") || !effect
.CompareNoCase(L
"Scroll down;"))
2039 int top
, bottom
, delay
, fadeawayheight
= 0;
2040 if(swscanf(s
, L
"%d;%d;%d;%d", &top
, &bottom
, &delay
, &fadeawayheight
) < 3) return;
2041 if(top
> bottom
) {int tmp
= top
; top
= bottom
; bottom
= tmp
;}
2042 Effect
* e
= new Effect
;
2044 sub
->m_effects
[e
->type
= EF_SCROLL
] = e
;
2045 e
->param
[0] = (int)(sub
->m_scaley
*top
*8);
2046 e
->param
[1] = (int)(sub
->m_scaley
*bottom
*8);
2047 e
->param
[2] = (int)(max(1.0*delay
/sub
->m_scaley
, 1));
2048 e
->param
[3] = (effect
.GetLength() == 12);
2049 e
->param
[4] = (int)(sub
->m_scaley
*fadeawayheight
);
2053 void CRenderedTextSubtitle::ParseString(CSubtitle
* sub
, CStringW str
, const FwSTSStyle
& style
)
2056 str
.Replace(L
"\\N", L
"\n");
2057 str
.Replace(L
"\\n", (sub
->m_wrapStyle
< 2 || sub
->m_wrapStyle
== 3) ? L
" " : L
"\n");
2058 str
.Replace(L
"\\h", L
"\x00A0");
2059 for(int ite
= 0, j
= 0, len
= str
.GetLength(); j
<= len
; j
++)
2062 if(c
!= L
'\n' && c
!= L
' ' && c
!= 0)
2066 if(PCWord tmp_ptr
= new CText(style
, str
.Mid(ite
, j
-ite
), m_ktype
, m_kstart
, m_kend
2067 , m_target_scale_x
, m_target_scale_y
))
2069 SharedPtrCWord
w(tmp_ptr
);
2070 sub
->m_words
.AddTail(w
);
2074 ///TODO: overflow handling
2080 if(PCWord tmp_ptr
= new CText(style
, CStringW(), m_ktype
, m_kstart
, m_kend
2081 , m_target_scale_x
, m_target_scale_y
))
2083 SharedPtrCWord
w(tmp_ptr
);
2084 sub
->m_words
.AddTail(w
);
2088 ///TODO: overflow handling
2094 if(PCWord tmp_ptr
= new CText(style
, CStringW(c
), m_ktype
, m_kstart
, m_kend
2095 , m_target_scale_x
, m_target_scale_y
))
2097 SharedPtrCWord
w(tmp_ptr
);
2098 sub
->m_words
.AddTail(w
);
2102 ///TODO: overflow handling
2111 void CRenderedTextSubtitle::ParsePolygon(CSubtitle
* sub
, const CStringW
& str
, const FwSTSStyle
& style
)
2113 if(!sub
|| !str
.GetLength() || !m_nPolygon
) return;
2115 if(PCWord tmp_ptr
= new CPolygon(style
, str
, m_ktype
, m_kstart
, m_kend
, sub
->m_scalex
/(1<<(m_nPolygon
-1))
2116 , sub
->m_scaley
/(1<<(m_nPolygon
-1)), m_polygonBaselineOffset
2117 , m_target_scale_x
, m_target_scale_y
))
2119 SharedPtrCWord
w(tmp_ptr
);
2121 //if( PCWord w_cache = m_wordCache.lookup(*w) )
2123 // sub->m_words.AddTail(w_cache);
2128 sub
->m_words
.AddTail(w
);
2134 bool CRenderedTextSubtitle::ParseSSATag( AssTagList
*assTags
, const CStringW
& str
)
2136 if(!assTags
) return(false);
2137 int nTags
= 0, nUnrecognizedTags
= 0;
2138 for(int i
= 0, j
; (j
= str
.Find(L
'\\', i
)) >= 0; i
= j
)
2140 POSITION pos
= assTags
->AddTail();
2141 AssTag
& assTag
= assTags
->GetAt(pos
);
2142 assTag
.cmdType
= CMD_COUNT
;
2145 CStringW::PCXSTR str_start
= str
.GetString() + j
;
2146 CStringW::PCXSTR pc
= str_start
;
2147 while( iswspace(*pc
) )
2153 while( *pc
&& *pc
!= L
'(' && *pc
!= L
'\\' )
2158 if( pc
-str_start
>0 )
2160 while( iswspace(*--pc
) );
2164 const CStringW
cmd(str_start
, pc
-str_start
);
2165 if(cmd
.IsEmpty()) continue;
2167 CAtlArray
<CStringW
>& params
= assTag
.strParams
;
2171 CStringW::PCXSTR str_start
= str
.GetString() + j
;
2172 CStringW::PCXSTR pc
= str_start
;
2173 while( iswspace(*pc
) )
2179 while( *pc
&& *pc
!= L
')' )
2184 if( pc
-str_start
>0 )
2186 while( iswspace(*--pc
) );
2190 CStringW::PCXSTR param_start
= str_start
;
2191 CStringW::PCXSTR param_end
= pc
;
2192 while( param_start
<param_end
)
2194 param_start
= SkipWhiteSpaceLeft(param_start
, param_end
);
2196 CStringW::PCXSTR newstart
= FindChar(param_start
, param_end
, L
',');
2197 CStringW::PCXSTR newend
= FindChar(param_start
, param_end
, L
'\\');
2198 if(newstart
> param_start
&& newstart
< newend
)
2200 newstart
= FastSkipWhiteSpaceRight(param_start
, newstart
);
2201 CStringW
s(param_start
, newstart
- param_start
);
2203 if(!s
.IsEmpty()) params
.Add(s
);
2204 param_start
= newstart
+ 1;
2206 else if(param_start
<param_end
)
2208 CStringW
s(param_start
, param_end
- param_start
);
2211 param_start
= param_end
;
2216 AssCmdType cmd_type
= CMD_COUNT
;
2217 int cmd_length
= min(MAX_CMD_LENGTH
, cmd
.GetLength());
2218 for( ;cmd_length
>=MIN_CMD_LENGTH
;cmd_length
-- )
2220 if( m_cmdMap
.Lookup(cmd
.Left(cmd_length
), cmd_type
) )
2223 if(cmd_length
<MIN_CMD_LENGTH
)
2224 cmd_type
= CMD_COUNT
;
2264 params
.Add(cmd
.Mid(cmd_length
));
2276 params
.Add(cmd
.Mid(cmd_length
).Trim(L
"&H"));
2287 if (!params
.IsEmpty() && params
.GetCount()<=4)
2288 ParseSSATag(&assTag
.embeded
, params
[params
.GetCount()-1]);
2291 nUnrecognizedTags
++;
2295 assTag
.cmdType
= cmd_type
;
2302 bool CRenderedTextSubtitle::ParseSSATag( CSubtitle
* sub
, const AssTagList
& assTags
, STSStyle
& style
, const STSStyle
& org
, bool fAnimate
/*= false*/ )
2304 if(!sub
) return(false);
2306 POSITION pos
= assTags
.GetHeadPosition();
2309 const AssTag
& assTag
= assTags
.GetNext(pos
);
2310 AssCmdType cmd_type
= assTag
.cmdType
;
2311 const CAtlArray
<CStringW
>& params
= assTag
.strParams
;
2313 // TODO: call ParseStyleModifier(cmd, params, ..) and move the rest there
2314 const CStringW
& p
= params
.GetCount() > 0 ? params
[0] : CStringW("");
2322 const int i
= cmd_type
==CMD_1c
? 0 :
2323 cmd_type
==CMD_2c
? 1 :
2324 cmd_type
==CMD_3c
? 2 :
2325 /*cmd_type==CMD_4c ?*/ 3;
2326 DWORD c
= wcstol(p
, NULL
, 16);
2327 style
.colors
[i
] = !p
.IsEmpty()
2328 ? (((int)CalcAnimation(c
&0xff, style
.colors
[i
]&0xff, fAnimate
))&0xff
2329 |((int)CalcAnimation(c
&0xff00, style
.colors
[i
]&0xff00, fAnimate
))&0xff00
2330 |((int)CalcAnimation(c
&0xff0000, style
.colors
[i
]&0xff0000, fAnimate
))&0xff0000)
2339 const int i
= cmd_type
==CMD_1a
? 0 :
2340 cmd_type
==CMD_2a
? 1 :
2341 cmd_type
==CMD_3a
? 2 :
2342 /*cmd_type==CMD_4a ?*/ 3;
2343 style
.alpha
[i
] = !p
.IsEmpty()
2344 ? (BYTE
)CalcAnimation(wcstol(p
, NULL
, 16), style
.alpha
[i
], fAnimate
)
2350 for(int i
= 0; i
< 4; i
++)
2352 style
.alpha
[i
] = !p
.IsEmpty()
2353 ? (BYTE
)CalcAnimation(wcstol(p
, NULL
, 16), style
.alpha
[i
], fAnimate
)
2360 int n
= wcstol(p
, NULL
, 10);
2361 if(sub
->m_scrAlignment
< 0)
2362 sub
->m_scrAlignment
= (n
> 0 && n
< 10) ? n
: org
.scrAlignment
;
2367 int n
= wcstol(p
, NULL
, 10);
2368 if(sub
->m_scrAlignment
< 0)
2369 sub
->m_scrAlignment
= (n
> 0 && n
< 12) ? ((((n
-1)&3)+1)+((n
&4)?6:0)+((n
&8)?3:0)) : org
.scrAlignment
;
2374 double n
= CalcAnimation(wcstod(p
, NULL
), style
.fGaussianBlur
, fAnimate
);
2375 style
.fGaussianBlur
= !p
.IsEmpty()
2377 : org
.fGaussianBlur
;
2382 double dst
= wcstod(p
, NULL
);
2383 double nx
= CalcAnimation(dst
, style
.outlineWidthX
, fAnimate
);
2384 style
.outlineWidthX
= !p
.IsEmpty()
2386 : org
.outlineWidthX
;
2387 double ny
= CalcAnimation(dst
, style
.outlineWidthY
, fAnimate
);
2388 style
.outlineWidthY
= !p
.IsEmpty()
2390 : org
.outlineWidthY
;
2395 double d
= CalcAnimation(wcstod(p
, NULL
), style
.fBlur
, fAnimate
);
2396 style
.fBlur
= !p
.IsEmpty()
2403 int n
= wcstol(p
, NULL
, 10);
2404 style
.fontWeight
= !p
.IsEmpty()
2405 ? (n
== 0 ? FW_NORMAL
: n
== 1 ? FW_BOLD
: n
>= 100 ? n
: org
.fontWeight
)
2412 bool invert
= (cmd_type
== CMD_iclip
);
2413 if(params
.GetCount() == 1 && !sub
->m_pClipper
)
2415 sub
->m_pClipper
.reset( new CClipper(params
[0], CSize(m_size_scale_to
.cx
>>3, m_size_scale_to
.cy
>>3), sub
->m_scalex
, sub
->m_scaley
, invert
, m_target_scale_x
, m_target_scale_y
) );
2417 else if(params
.GetCount() == 2 && !sub
->m_pClipper
)
2419 int scale
= max(wcstol(p
, NULL
, 10), 1);
2420 sub
->m_pClipper
.reset( new CClipper(params
[1], CSize(m_size_scale_to
.cx
>>3, m_size_scale_to
.cy
>>3), sub
->m_scalex
/(1<<(scale
-1)), sub
->m_scaley
/(1<<(scale
-1)), invert
, m_target_scale_x
, m_target_scale_y
) );
2422 else if(params
.GetCount() == 4)
2425 sub
->m_clipInverse
= invert
;
2427 wcstod(params
[0], NULL
)+0.5,
2428 wcstod(params
[1], NULL
)+0.5,
2429 wcstod(params
[2], NULL
)+0.5,
2430 wcstod(params
[3], NULL
)+0.5);
2432 if(sub
->m_relativeTo
== 1) // TODO: this should also apply to the other two clippings above
2434 o
.x
= m_vidrect
.left
>>3;
2435 o
.y
= m_vidrect
.top
>>3;
2437 sub
->m_clip
.SetRect(
2438 (int)CalcAnimation(sub
->m_scalex
*r
.left
+ o
.x
, sub
->m_clip
.left
, fAnimate
),
2439 (int)CalcAnimation(sub
->m_scaley
*r
.top
+ o
.y
, sub
->m_clip
.top
, fAnimate
),
2440 (int)CalcAnimation(sub
->m_scalex
*r
.right
+ o
.x
, sub
->m_clip
.right
, fAnimate
),
2441 (int)CalcAnimation(sub
->m_scaley
*r
.bottom
+ o
.y
, sub
->m_clip
.bottom
, fAnimate
));
2447 DWORD c
= wcstol(p
, NULL
, 16);
2448 style
.colors
[0] = !p
.IsEmpty()
2449 ? (((int)CalcAnimation(c
&0xff, style
.colors
[0]&0xff, fAnimate
))&0xff
2450 |((int)CalcAnimation(c
&0xff00, style
.colors
[0]&0xff00, fAnimate
))&0xff00
2451 |((int)CalcAnimation(c
&0xff0000, style
.colors
[0]&0xff0000, fAnimate
))&0xff0000)
2458 sub
->m_fAnimated2
= true;
2459 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])
2461 if(Effect
* e
= new Effect
)
2463 for(int i
= 0; i
< 3; i
++)
2464 e
->param
[i
] = wcstol(params
[i
], NULL
, 10);
2465 for(int i
= 0; i
< 4; i
++)
2466 e
->t
[i
] = wcstol(params
[3+i
], NULL
, 10);
2467 sub
->m_effects
[EF_FADE
] = e
;
2470 else if(params
.GetCount() == 2 && !sub
->m_effects
[EF_FADE
]) // {\fad(t1=t[1], t2=t[2])
2472 if(Effect
* e
= new Effect
)
2474 e
->param
[0] = e
->param
[2] = 0xff;
2476 for(int i
= 1; i
< 3; i
++)
2477 e
->t
[i
] = wcstol(params
[i
-1], NULL
, 10);
2478 e
->t
[0] = e
->t
[3] = -1; // will be substituted with "start" and "end"
2479 sub
->m_effects
[EF_FADE
] = e
;
2486 style
.fontShiftX
= !p
.IsEmpty()
2487 ? CalcAnimation(wcstod(p
, NULL
), style
.fontShiftX
, fAnimate
)
2493 style
.fontShiftY
= !p
.IsEmpty()
2494 ? CalcAnimation(wcstod(p
, NULL
), style
.fontShiftY
, fAnimate
)
2500 int n
= wcstol(p
, NULL
, 10);
2501 style
.charSet
= !p
.IsEmpty()
2508 if(!p
.IsEmpty() && p
!= L
'0')
2509 style
.fontName
= CString(p
).Trim();
2511 style
.fontName
= org
.fontName
;
2516 style
.fontAngleX
= !p
.IsEmpty()
2517 ? CalcAnimation(wcstod(p
, NULL
), style
.fontAngleX
, fAnimate
)
2523 style
.fontAngleY
= !p
.IsEmpty()
2524 ? CalcAnimation(wcstod(p
, NULL
), style
.fontAngleY
, fAnimate
)
2531 style
.fontAngleZ
= !p
.IsEmpty()
2532 ? CalcAnimation(wcstod(p
, NULL
), style
.fontAngleZ
, fAnimate
)
2538 double n
= CalcAnimation(wcstod(p
, NULL
), style
.fontScaleX
, fAnimate
);
2539 style
.fontScaleX
= !p
.IsEmpty()
2546 double n
= CalcAnimation(wcstod(p
, NULL
), style
.fontScaleY
, fAnimate
);
2547 style
.fontScaleY
= !p
.IsEmpty()
2554 style
.fontScaleX
= org
.fontScaleX
;
2555 style
.fontScaleY
= org
.fontScaleY
;
2560 style
.fontSpacing
= !p
.IsEmpty()
2561 ? CalcAnimation(wcstod(p
, NULL
), style
.fontSpacing
, fAnimate
)
2569 if(p
[0] == L
'-' || p
[0] == L
'+')
2571 double n
= CalcAnimation(style
.fontSize
+ style
.fontSize
*wcstod(p
, NULL
)/10, style
.fontSize
, fAnimate
);
2572 style
.fontSize
= (n
> 0) ? n
: org
.fontSize
;
2576 double n
= CalcAnimation(wcstod(p
, NULL
), style
.fontSize
, fAnimate
);
2577 style
.fontSize
= (n
> 0) ? n
: org
.fontSize
;
2582 style
.fontSize
= org
.fontSize
;
2588 int n
= wcstol(p
, NULL
, 10);
2589 style
.fItalic
= !p
.IsEmpty()
2590 ? (n
== 0 ? false : n
== 1 ? true : org
.fItalic
)
2596 m_kstart
= !p
.IsEmpty()
2597 ? wcstod(p
, NULL
)*10
2600 sub
->m_fAnimated2
= true;//fix me: define m_fAnimated m_fAnimated2 strictly
2608 m_kend
+= !p
.IsEmpty()
2609 ? wcstod(p
, NULL
)*10
2611 sub
->m_fAnimated2
= true;//fix me: define m_fAnimated m_fAnimated2 strictly
2618 m_kend
+= !p
.IsEmpty()
2619 ? wcstod(p
, NULL
)*10
2621 sub
->m_fAnimated2
= true;//fix me: define m_fAnimated m_fAnimated2 strictly
2628 m_kend
+= !p
.IsEmpty()
2629 ? wcstod(p
, NULL
)*10
2631 sub
->m_fAnimated2
= true;//fix me: define m_fAnimated m_fAnimated2 strictly
2634 case CMD_move
: // {\move(x1=param[0], y1=param[1], x2=param[2], y2=param[3][, t1=t[0], t2=t[1]])}
2636 if((params
.GetCount() == 4 || params
.GetCount() == 6) && !sub
->m_effects
[EF_MOVE
])
2638 if(Effect
* e
= new Effect
)
2640 e
->param
[0] = (int)(sub
->m_scalex
*wcstod(params
[0], NULL
)*8);
2641 e
->param
[1] = (int)(sub
->m_scaley
*wcstod(params
[1], NULL
)*8);
2642 e
->param
[2] = (int)(sub
->m_scalex
*wcstod(params
[2], NULL
)*8);
2643 e
->param
[3] = (int)(sub
->m_scaley
*wcstod(params
[3], NULL
)*8);
2644 e
->t
[0] = e
->t
[1] = -1;
2645 if(params
.GetCount() == 6)
2647 for(int i
= 0; i
< 2; i
++)
2648 e
->t
[i
] = wcstol(params
[4+i
], NULL
, 10);
2650 sub
->m_effects
[EF_MOVE
] = e
;
2651 sub
->m_fAnimated2
= true;
2656 case CMD_org
: // {\org(x=param[0], y=param[1])}
2658 if(params
.GetCount() == 2 && !sub
->m_effects
[EF_ORG
])
2660 if(Effect
* e
= new Effect
)
2662 e
->param
[0] = (int)(sub
->m_scalex
*wcstod(params
[0], NULL
)*8);
2663 e
->param
[1] = (int)(sub
->m_scaley
*wcstod(params
[1], NULL
)*8);
2664 sub
->m_effects
[EF_ORG
] = e
;
2671 m_polygonBaselineOffset
= wcstol(p
, NULL
, 10);
2676 if(params
.GetCount() == 2 && !sub
->m_effects
[EF_MOVE
])
2678 if(Effect
* e
= new Effect
)
2680 e
->param
[0] = e
->param
[2] = (int)(sub
->m_scalex
*wcstod(params
[0], NULL
)*8);
2681 e
->param
[1] = e
->param
[3] = (int)(sub
->m_scaley
*wcstod(params
[1], NULL
)*8);
2682 e
->t
[0] = e
->t
[1] = 0;
2683 sub
->m_effects
[EF_MOVE
] = e
;
2690 int n
= wcstol(p
, NULL
, 10);
2691 m_nPolygon
= (n
<= 0 ? 0 : n
);
2696 int n
= wcstol(p
, NULL
, 10);
2697 sub
->m_wrapStyle
= !p
.IsEmpty() && (0 <= n
&& n
<= 3)
2699 : m_defaultWrapStyle
;
2705 style
= (!p
.IsEmpty() && m_styles
.Lookup(WToT(p
), val
) && val
) ? *val
: org
;
2710 double dst
= wcstod(p
, NULL
);
2711 double nx
= CalcAnimation(dst
, style
.shadowDepthX
, fAnimate
);
2712 style
.shadowDepthX
= !p
.IsEmpty()
2715 double ny
= CalcAnimation(dst
, style
.shadowDepthY
, fAnimate
);
2716 style
.shadowDepthY
= !p
.IsEmpty()
2723 int n
= wcstol(p
, NULL
, 10);
2724 style
.fStrikeOut
= !p
.IsEmpty()
2725 ? (n
== 0 ? false : n
== 1 ? true : org
.fStrikeOut
)
2729 case CMD_t
: // \t([<t1>,<t2>,][<accel>,]<style modifiers>)
2732 m_animStart
= m_animEnd
= 0;
2734 if(params
.GetCount() == 1)
2738 else if(params
.GetCount() == 2)
2740 m_animAccel
= wcstod(params
[0], NULL
);
2743 else if(params
.GetCount() == 3)
2745 m_animStart
= (int)wcstod(params
[0], NULL
);
2746 m_animEnd
= (int)wcstod(params
[1], NULL
);
2749 else if(params
.GetCount() == 4)
2751 m_animStart
= wcstol(params
[0], NULL
, 10);
2752 m_animEnd
= wcstol(params
[1], NULL
, 10);
2753 m_animAccel
= wcstod(params
[2], NULL
);
2756 ParseSSATag(sub
, assTag
.embeded
, style
, org
, true);
2757 sub
->m_fAnimated
= true;
2758 sub
->m_fAnimated2
= true;
2763 int n
= wcstol(p
, NULL
, 10);
2764 style
.fUnderline
= !p
.IsEmpty()
2765 ? (n
== 0 ? false : n
== 1 ? true : org
.fUnderline
)
2771 double dst
= wcstod(p
, NULL
);
2772 double nx
= CalcAnimation(dst
, style
.outlineWidthX
, fAnimate
);
2773 style
.outlineWidthX
= !p
.IsEmpty()
2775 : org
.outlineWidthX
;
2780 double dst
= wcstod(p
, NULL
);
2781 double nx
= CalcAnimation(dst
, style
.shadowDepthX
, fAnimate
);
2782 style
.shadowDepthX
= !p
.IsEmpty()
2789 double dst
= wcstod(p
, NULL
);
2790 double ny
= CalcAnimation(dst
, style
.outlineWidthY
, fAnimate
);
2791 style
.outlineWidthY
= !p
.IsEmpty()
2793 : org
.outlineWidthY
;
2798 double dst
= wcstod(p
, NULL
);
2799 double ny
= CalcAnimation(dst
, style
.shadowDepthY
, fAnimate
);
2800 style
.shadowDepthY
= !p
.IsEmpty()
2812 bool CRenderedTextSubtitle::ParseSSATag(CSubtitle
* sub
, const CStringW
& str
, STSStyle
& style
, const STSStyle
& org
, bool fAnimate
)
2814 if(!sub
) return(false);
2816 SharedPtrConstAssTagList assTags
;
2817 AssTagListMruCache
*ass_tag_cache
= CacheManager::GetAssTagListMruCache();
2818 POSITION pos
= ass_tag_cache
->Lookup(str
);
2821 AssTagList
*tmp
= new AssTagList();
2822 ParseSSATag(tmp
, str
);
2824 ass_tag_cache
->UpdateCache(str
, assTags
);
2828 assTags
= ass_tag_cache
->GetAt(pos
);
2829 ass_tag_cache
->UpdateCache( pos
);
2831 return ParseSSATag(sub
, *assTags
, style
, org
, fAnimate
);
2834 bool CRenderedTextSubtitle::ParseHtmlTag(CSubtitle
* sub
, CStringW str
, STSStyle
& style
, STSStyle
& org
)
2836 if(str
.Find(L
"!--") == 0)
2838 bool fClosing
= str
[0] == L
'/';
2840 int i
= str
.Find(L
' ');
2841 if(i
< 0) i
= str
.GetLength();
2842 CStringW tag
= str
.Left(i
).MakeLower();
2843 str
= str
.Mid(i
).Trim();
2844 CAtlArray
<CStringW
> attribs
, params
;
2845 while((i
= str
.Find(L
'=')) > 0)
2847 attribs
.Add(str
.Left(i
).Trim().MakeLower());
2849 for(i
= 0; _istspace(str
[i
]); i
++);
2851 if(str
[0] == L
'\"') {str
= str
.Mid(1); i
= str
.Find(L
'\"');}
2852 else i
= str
.Find(L
' ');
2853 if(i
< 0) i
= str
.GetLength();
2854 params
.Add(str
.Left(i
).Trim().MakeLower());
2859 else if(tag
== L
"b" || tag
== L
"strong")
2860 style
.fontWeight
= !fClosing
? FW_BOLD
: org
.fontWeight
;
2861 else if(tag
== L
"i" || tag
== L
"em")
2862 style
.fItalic
= !fClosing
? true : org
.fItalic
;
2863 else if(tag
== L
"u")
2864 style
.fUnderline
= !fClosing
? true : org
.fUnderline
;
2865 else if(tag
== L
"s" || tag
== L
"strike" || tag
== L
"del")
2866 style
.fStrikeOut
= !fClosing
? true : org
.fStrikeOut
;
2867 else if(tag
== L
"font")
2871 for(size_t i
= 0; i
< attribs
.GetCount(); i
++)
2873 if(params
[i
].IsEmpty()) continue;
2875 if(attribs
[i
] == L
"face")
2877 style
.fontName
= params
[i
];
2879 else if(attribs
[i
] == L
"size")
2881 if(params
[i
][0] == L
'+')
2882 style
.fontSize
+= wcstol(params
[i
], NULL
, 10);
2883 else if(params
[i
][0] == L
'-')
2884 style
.fontSize
-= wcstol(params
[i
], NULL
, 10);
2886 style
.fontSize
= wcstol(params
[i
], NULL
, 10);
2888 else if(attribs
[i
] == L
"color")
2892 else if(attribs
[i
] == L
"outline-color")
2896 else if(attribs
[i
] == L
"outline-level")
2898 style
.outlineWidthX
= style
.outlineWidthY
= wcstol(params
[i
], NULL
, 10);
2900 else if(attribs
[i
] == L
"shadow-color")
2904 else if(attribs
[i
] == L
"shadow-level")
2906 style
.shadowDepthX
= style
.shadowDepthY
= wcstol(params
[i
], NULL
, 10);
2908 if(nColor
>= 0 && nColor
< 4)
2910 CString key
= WToT(params
[i
]).TrimLeft(L
'#');
2912 if(g_colors
.Lookup(key
, val
))
2913 style
.colors
[nColor
] = val
;
2914 else if((style
.colors
[nColor
] = _tcstol(key
, NULL
, 16)) == 0)
2915 style
.colors
[nColor
] = 0x00ffffff; // default is white
2916 style
.colors
[nColor
] = ((style
.colors
[nColor
]>>16)&0xff)|((style
.colors
[nColor
]&0xff)<<16)|(style
.colors
[nColor
]&0x00ff00);
2922 style
.fontName
= org
.fontName
;
2923 style
.fontSize
= org
.fontSize
;
2924 memcpy(style
.colors
, org
.colors
, sizeof(style
.colors
));
2927 else if(tag
== L
"k" && attribs
.GetCount() == 1 && attribs
[0] == L
"t")
2931 m_kend
+= wcstol(params
[0], NULL
, 10);
2938 double CRenderedTextSubtitle::CalcAnimation(double dst
, double src
, bool fAnimate
)
2940 int s
= m_animStart
? m_animStart
: 0;
2941 int e
= m_animEnd
? m_animEnd
: m_delay
;
2942 if(fabs(dst
-src
) >= 0.0001 && fAnimate
)
2944 if(m_time
< s
) dst
= src
;
2945 else if(s
<= m_time
&& m_time
< e
)
2947 double t
= pow(1.0 * (m_time
- s
) / (e
- s
), m_animAccel
);
2948 dst
= (1 - t
) * src
+ t
* dst
;
2955 CSubtitle
* CRenderedTextSubtitle::GetSubtitle(int entry
)
2958 if(m_subtitleCache
.Lookup(entry
, sub
))
2960 if(sub
->m_fAnimated
) {delete sub
; sub
= NULL
;}
2963 sub
= new CSubtitle();
2964 if(!sub
) return(NULL
);
2965 CStringW str
= GetStrW(entry
, true);
2966 STSStyle stss
, orgstss
;
2967 GetStyle(entry
, &stss
);
2968 if (stss
.fontScaleX
== stss
.fontScaleY
&& m_dPARCompensation
!= 1.0)
2970 switch(m_ePARCompensationType
)
2973 if (m_dPARCompensation
< 1.0)
2974 stss
.fontScaleY
/= m_dPARCompensation
;
2976 stss
.fontScaleX
*= m_dPARCompensation
;
2979 if (m_dPARCompensation
< 1.0)
2980 stss
.fontScaleX
*= m_dPARCompensation
;
2982 stss
.fontScaleY
/= m_dPARCompensation
;
2984 case EPCTAccurateSize
:
2985 stss
.fontScaleX
*= m_dPARCompensation
;
2990 sub
->m_clip
.SetRect(0, 0, m_size
.cx
>>3, m_size
.cy
>>3);
2991 sub
->m_scrAlignment
= -stss
.scrAlignment
;
2992 sub
->m_wrapStyle
= m_defaultWrapStyle
;
2993 sub
->m_fAnimated
= false;
2994 sub
->m_relativeTo
= stss
.relativeTo
;
2995 sub
->m_scalex
= m_dstScreenSize
.cx
> 0 ? 1.0 * (stss
.relativeTo
== 1 ? m_vidrect
.Width() : m_size
.cx
) / (m_dstScreenSize
.cx
*8) : 1.0;
2996 sub
->m_scaley
= m_dstScreenSize
.cy
> 0 ? 1.0 * (stss
.relativeTo
== 1 ? m_vidrect
.Height() : m_size
.cy
) / (m_dstScreenSize
.cy
*8) : 1.0;
2998 sub
->m_target_scale_x
= m_target_scale_x
;
2999 sub
->m_target_scale_y
= m_target_scale_y
;
3001 m_animStart
= m_animEnd
= 0;
3003 m_ktype
= m_kstart
= m_kend
= 0;
3005 m_polygonBaselineOffset
= 0;
3006 ParseEffect(sub
, m_entries
.GetAt(entry
).effect
);
3007 while(!str
.IsEmpty())
3009 bool fParsed
= false;
3011 if(str
[0] == L
'{' && (i
= str
.Find(L
'}')) > 0)
3013 fParsed
= ParseSSATag(sub
, str
.Mid(1, i
-1), stss
, orgstss
);
3017 else if(str
[0] == L
'<' && (i
= str
.Find(L
'>')) > 0)
3019 fParsed
= ParseHtmlTag(sub
, str
.Mid(1, i
-1), stss
, orgstss
);
3025 i
= str
.FindOneOf(L
"{<");
3026 if(i
< 0) i
= str
.GetLength();
3027 if(i
== 0) continue;
3031 i
= str
.Mid(1).FindOneOf(L
"{<");
3032 if(i
< 0) i
= str
.GetLength()-1;
3035 STSStyle tmp
= stss
;
3036 tmp
.fontSize
= sub
->m_scaley
*tmp
.fontSize
*64;
3037 tmp
.fontSpacing
= sub
->m_scalex
*tmp
.fontSpacing
*64;
3038 tmp
.outlineWidthX
*= (m_fScaledBAS
? sub
->m_scalex
: 1) * 8;
3039 tmp
.outlineWidthY
*= (m_fScaledBAS
? sub
->m_scaley
: 1) * 8;
3040 tmp
.shadowDepthX
*= (m_fScaledBAS
? sub
->m_scalex
: 1) * 8;
3041 tmp
.shadowDepthY
*= (m_fScaledBAS
? sub
->m_scaley
: 1) * 8;
3042 FwSTSStyle
fw_tmp(tmp
);
3045 ParsePolygon(sub
, str
.Left(i
), fw_tmp
);
3049 ParseString(sub
, str
.Left(i
), fw_tmp
);
3053 if( sub
->m_effects
[EF_BANNER
] || sub
->m_effects
[EF_SCROLL
] )
3054 sub
->m_fAnimated2
= true;
3055 // just a "work-around" solution... in most cases nobody will want to use \org together with moving but without rotating the subs
3056 if(sub
->m_effects
[EF_ORG
] && (sub
->m_effects
[EF_MOVE
] || sub
->m_effects
[EF_BANNER
] || sub
->m_effects
[EF_SCROLL
]))
3057 sub
->m_fAnimated
= true;
3058 sub
->m_scrAlignment
= abs(sub
->m_scrAlignment
);
3059 STSEntry stse
= m_entries
.GetAt(entry
);
3060 CRect marginRect
= stse
.marginRect
;
3061 if(marginRect
.left
== 0) marginRect
.left
= orgstss
.marginRect
.get().left
;
3062 if(marginRect
.top
== 0) marginRect
.top
= orgstss
.marginRect
.get().top
;
3063 if(marginRect
.right
== 0) marginRect
.right
= orgstss
.marginRect
.get().right
;
3064 if(marginRect
.bottom
== 0) marginRect
.bottom
= orgstss
.marginRect
.get().bottom
;
3065 marginRect
.left
= (int)(sub
->m_scalex
*marginRect
.left
*8);
3066 marginRect
.top
= (int)(sub
->m_scaley
*marginRect
.top
*8);
3067 marginRect
.right
= (int)(sub
->m_scalex
*marginRect
.right
*8);
3068 marginRect
.bottom
= (int)(sub
->m_scaley
*marginRect
.bottom
*8);
3069 if(stss
.relativeTo
== 1)
3071 marginRect
.left
+= m_vidrect
.left
;
3072 marginRect
.top
+= m_vidrect
.top
;
3073 marginRect
.right
+= m_size
.cx
- m_vidrect
.right
;
3074 marginRect
.bottom
+= m_size
.cy
- m_vidrect
.bottom
;
3076 sub
->CreateClippers(m_size
, m_size_scale_to
);
3077 sub
->MakeLines(m_size
, marginRect
);
3078 m_subtitleCache
[entry
] = sub
;
3084 STDMETHODIMP
CRenderedTextSubtitle::NonDelegatingQueryInterface(REFIID riid
, void** ppv
)
3086 CheckPointer(ppv
, E_POINTER
);
3091 QI(ISubPicProviderEx2
)
3093 QI(ISubPicProviderEx
)
3094 __super::NonDelegatingQueryInterface(riid
, ppv
);
3099 STDMETHODIMP_(POSITION
) CRenderedTextSubtitle::GetStartPosition(REFERENCE_TIME rt
, double fps
)
3104 m_period
= 1000/m_fps
;
3112 //Todo: fix me. max has been defined as a macro. Use #define NOMINMAX to fix it.
3113 //std::numeric_limits<int>::max();
3118 int subIndex
= 1;//If a segment has animate effect then it corresponds to several subpics.
3119 //subIndex, 1 based, indicates which subpic the result corresponds to.
3121 const STSSegment
*stss
= SearchSubs((int)rt
, fps
, &iSegment
, NULL
);
3124 else if(stss
->animated
)
3126 int start
= TranslateSegmentStart(iSegment
, fps
);
3128 subIndex
= (rt
-start
)/m_period
+ 1;
3130 //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));
3131 return (POSITION
)(subIndex
| (iSegment
<<RTS_POS_SEGMENT_INDEX_BITS
));
3132 //if(iSegment < 0) iSegment = 0;
3133 //return(GetNext((POSITION)iSegment));
3136 STDMETHODIMP_(POSITION
) CRenderedTextSubtitle::GetNext(POSITION pos
)
3138 int iSegment
= ((int)pos
>>RTS_POS_SEGMENT_INDEX_BITS
);
3139 int subIndex
= ((int)pos
& RTS_POS_SUB_INDEX_MASK
);
3140 const STSSegment
*stss
= GetSegment(iSegment
);
3141 ASSERT(stss
!=NULL
&& stss
->subs
.GetCount()>0);
3142 //DbgLog((LOG_TRACE, 3, "stss:%x count:%d", stss, stss->subs.GetCount()));
3151 TranslateSegmentStartEnd(iSegment
, m_fps
, start
, end
);
3152 if(start
+m_period
*subIndex
< end
)
3160 if(GetSegment(iSegment
) != NULL
)
3162 ASSERT(GetSegment(iSegment
)->subs
.GetCount()>0);
3163 return (POSITION
)(subIndex
| (iSegment
<<RTS_POS_SEGMENT_INDEX_BITS
));
3169 //@return: <0 if segment not found
3170 STDMETHODIMP_(REFERENCE_TIME
) CRenderedTextSubtitle::GetStart(POSITION pos
, double fps
)
3172 //return(10000i64 * TranslateSegmentStart((int)pos-1, fps));
3173 int iSegment
= ((int)pos
>>RTS_POS_SEGMENT_INDEX_BITS
);
3174 int subIndex
= ((int)pos
& RTS_POS_SUB_INDEX_MASK
);
3175 int start
= TranslateSegmentStart(iSegment
, fps
);
3176 const STSSegment
*stss
= GetSegment(iSegment
);
3179 return (start
+ (subIndex
-1)*m_period
)*10000i64
;
3187 //@return: <0 if segment not found
3188 STDMETHODIMP_(REFERENCE_TIME
) CRenderedTextSubtitle::GetStop(POSITION pos
, double fps
)
3190 // return(10000i64 * TranslateSegmentEnd((int)pos-1, fps));
3191 int iSegment
= ((int)pos
>>RTS_POS_SEGMENT_INDEX_BITS
);
3192 int subIndex
= ((int)pos
& RTS_POS_SUB_INDEX_MASK
);
3193 int start
, end
, ret
;
3194 TranslateSegmentStartEnd(iSegment
, fps
, start
, end
);
3195 const STSSegment
*stss
= GetSegment(iSegment
);
3202 ret
= start
+subIndex
*m_period
;
3206 return ret
*10000i64
;
3212 //@start, @stop: -1 if segment not found; @stop may < @start if subIndex exceed uppper bound
3213 STDMETHODIMP_(VOID
) CRenderedTextSubtitle::GetStartStop(POSITION pos
, double fps
, /*out*/REFERENCE_TIME
&start
, /*out*/REFERENCE_TIME
&stop
)
3215 int iSegment
= ((int)pos
>>RTS_POS_SEGMENT_INDEX_BITS
);
3216 int subIndex
= ((int)pos
& RTS_POS_SUB_INDEX_MASK
);
3217 int tempStart
, tempEnd
;
3218 TranslateSegmentStartEnd(iSegment
, fps
, tempStart
, tempEnd
);
3221 const STSSegment
*stss
= GetSegment(iSegment
);
3226 start
+= (subIndex
-1)*m_period
;
3227 if(start
+m_period
< stop
)
3228 stop
= start
+m_period
;
3230 //DbgLog((LOG_TRACE, 3, "animated:%d seg:%d idx:%d start:%d stop:%lu", stss->animated, iSegment, subIndex, (ULONG)start, (ULONG)stop));
3241 STDMETHODIMP_(bool) CRenderedTextSubtitle::IsAnimated(POSITION pos
)
3243 unsigned int iSegment
= ((unsigned int)pos
>>RTS_POS_SEGMENT_INDEX_BITS
);
3244 if(iSegment
<m_segments
.GetCount())
3245 return m_segments
[iSegment
].animated
;
3251 struct LSub
{int idx
, layer
, readorder
;};
3253 static int lscomp(const void* ls1
, const void* ls2
)
3255 int ret
= ((LSub
*)ls1
)->layer
- ((LSub
*)ls2
)->layer
;
3256 if(!ret
) ret
= ((LSub
*)ls1
)->readorder
- ((LSub
*)ls2
)->readorder
;
3260 HRESULT
CRenderedTextSubtitle::ParseScript(REFERENCE_TIME rt
, double fps
, CSubtitle2List
*outputSub2List
)
3262 //fix me: check input and log error
3263 int t
= (int)(rt
/ 10000);
3266 STSSegment
* stss
= SearchSubs2(t
, fps
, &segment
);
3267 if(!stss
) return S_FALSE
;
3268 // clear any cached subs not in the range of +/-90secs measured from the segment's bounds
3270 POSITION pos
= m_subtitleCache
.GetStartPosition();
3275 m_subtitleCache
.GetNextAssoc(pos
, key
, value
);
3276 STSEntry
& stse
= m_entries
.GetAt(key
);
3277 if(stse
.end
<= (t
-90000) || stse
.start
> (t
+90000))
3280 m_subtitleCache
.RemoveKey(key
);
3281 pos
= m_subtitleCache
.GetStartPosition();
3285 m_sla
.AdvanceToSegment(segment
, stss
->subs
);
3286 CAtlArray
<LSub
> subs
;
3287 for(int i
= 0, j
= stss
->subs
.GetCount(); i
< j
; i
++)
3290 ls
.idx
= stss
->subs
[i
];
3291 ls
.layer
= m_entries
.GetAt(stss
->subs
[i
]).layer
;
3292 ls
.readorder
= m_entries
.GetAt(stss
->subs
[i
]).readorder
;
3295 qsort(subs
.GetData(), subs
.GetCount(), sizeof(LSub
), lscomp
);
3297 for(int i
= 0, j
= subs
.GetCount(); i
< j
; i
++)
3299 int entry
= subs
[i
].idx
;
3300 STSEntry stse
= m_entries
.GetAt(entry
);
3302 int start
= TranslateStart(entry
, fps
);
3304 m_delay
= TranslateEnd(entry
, fps
) - start
;
3306 CSubtitle
* s
= GetSubtitle(entry
);
3308 stss
->animated
|= s
->m_fAnimated2
;
3309 CRect clipRect
= s
->m_clip
& CRect(0,0, (m_size
.cx
>>3), (m_size
.cy
>>3));
3310 CRect r
= s
->m_rect
;
3311 CSize spaceNeeded
= r
.Size();
3312 // apply the effects
3313 bool fPosOverride
= false, fOrgOverride
= false;
3316 for(int k
= 0; k
< EF_NUMBEROFEFFECTS
; k
++)
3318 if(!s
->m_effects
[k
]) continue;
3321 case EF_MOVE
: // {\move(x1=param[0], y1=param[1], x2=param[2], y2=param[3], t1=t[0], t2=t[1])}
3324 CPoint
p1(s
->m_effects
[k
]->param
[0], s
->m_effects
[k
]->param
[1]);
3325 CPoint
p2(s
->m_effects
[k
]->param
[2], s
->m_effects
[k
]->param
[3]);
3326 int t1
= s
->m_effects
[k
]->t
[0];
3327 int t2
= s
->m_effects
[k
]->t
[1];
3328 if(t2
< t1
) {int t
= t1
; t1
= t2
; t2
= t
;}
3329 if(t1
<= 0 && t2
<= 0) {t1
= 0; t2
= m_delay
;}
3330 if(m_time
<= t1
) p
= p1
;
3331 else if (p1
== p2
) p
= p1
;
3332 else if(t1
< m_time
&& m_time
< t2
)
3334 double t
= 1.0*(m_time
-t1
)/(t2
-t1
);
3335 p
.x
= (int)((1-t
)*p1
.x
+ t
*p2
.x
);
3336 p
.y
= (int)((1-t
)*p1
.y
+ t
*p2
.y
);
3340 CPoint((s
->m_scrAlignment
%3) == 1 ? p
.x
: (s
->m_scrAlignment
%3) == 0 ? p
.x
- spaceNeeded
.cx
: p
.x
- (spaceNeeded
.cx
+1)/2,
3341 s
->m_scrAlignment
<= 3 ? p
.y
- spaceNeeded
.cy
: s
->m_scrAlignment
<= 6 ? p
.y
- (spaceNeeded
.cy
+1)/2 : p
.y
),
3343 if(s
->m_relativeTo
== 1)
3344 r
.OffsetRect(m_vidrect
.TopLeft());
3345 fPosOverride
= true;
3348 case EF_ORG
: // {\org(x=param[0], y=param[1])}
3350 org2
= CPoint(s
->m_effects
[k
]->param
[0], s
->m_effects
[k
]->param
[1]);
3351 fOrgOverride
= true;
3354 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])
3356 int t1
= s
->m_effects
[k
]->t
[0];
3357 int t2
= s
->m_effects
[k
]->t
[1];
3358 int t3
= s
->m_effects
[k
]->t
[2];
3359 int t4
= s
->m_effects
[k
]->t
[3];
3360 if(t1
== -1 && t4
== -1) {t1
= 0; t3
= m_delay
-t3
; t4
= m_delay
;}
3361 if(m_time
< t1
) alpha
= s
->m_effects
[k
]->param
[0];
3362 else if(m_time
>= t1
&& m_time
< t2
)
3364 double t
= 1.0 * (m_time
- t1
) / (t2
- t1
);
3365 alpha
= (int)(s
->m_effects
[k
]->param
[0]*(1-t
) + s
->m_effects
[k
]->param
[1]*t
);
3367 else if(m_time
>= t2
&& m_time
< t3
) alpha
= s
->m_effects
[k
]->param
[1];
3368 else if(m_time
>= t3
&& m_time
< t4
)
3370 double t
= 1.0 * (m_time
- t3
) / (t4
- t3
);
3371 alpha
= (int)(s
->m_effects
[k
]->param
[1]*(1-t
) + s
->m_effects
[k
]->param
[2]*t
);
3373 else if(m_time
>= t4
) alpha
= s
->m_effects
[k
]->param
[2];
3376 case EF_BANNER
: // Banner;delay=param[0][;leftoright=param[1];fadeawaywidth=param[2]]
3378 int left
= s
->m_relativeTo
== 1 ? m_vidrect
.left
: 0,
3379 right
= s
->m_relativeTo
== 1 ? m_vidrect
.right
: m_size
.cx
;
3380 r
.left
= !!s
->m_effects
[k
]->param
[1]
3381 ? (left
/*marginRect.left*/ - spaceNeeded
.cx
) + (int)(m_time
*8.0/s
->m_effects
[k
]->param
[0])
3382 : (right
/*- marginRect.right*/) - (int)(m_time
*8.0/s
->m_effects
[k
]->param
[0]);
3383 r
.right
= r
.left
+ spaceNeeded
.cx
;
3384 clipRect
&= CRect(left
>>3, clipRect
.top
, right
>>3, clipRect
.bottom
);
3385 fPosOverride
= true;
3388 case EF_SCROLL
: // Scroll up/down(toptobottom=param[3]);top=param[0];bottom=param[1];delay=param[2][;fadeawayheight=param[4]]
3390 r
.top
= !!s
->m_effects
[k
]->param
[3]
3391 ? s
->m_effects
[k
]->param
[0] + (int)(m_time
*8.0/s
->m_effects
[k
]->param
[2]) - spaceNeeded
.cy
3392 : s
->m_effects
[k
]->param
[1] - (int)(m_time
*8.0/s
->m_effects
[k
]->param
[2]);
3393 r
.bottom
= r
.top
+ spaceNeeded
.cy
;
3394 CRect
cr(0, (s
->m_effects
[k
]->param
[0] + 4) >> 3, (m_size
.cx
>>3), (s
->m_effects
[k
]->param
[1] + 4) >> 3);
3395 if(s
->m_relativeTo
== 1)
3396 r
.top
+= m_vidrect
.top
,
3397 r
.bottom
+= m_vidrect
.top
,
3398 cr
.top
+= m_vidrect
.top
>>3,
3399 cr
.bottom
+= m_vidrect
.top
>>3;
3401 fPosOverride
= true;
3408 if(!fPosOverride
&& !fOrgOverride
&& !s
->m_fAnimated
)
3409 r
= m_sla
.AllocRect(s
, segment
, entry
, stse
.layer
, m_collisions
);
3411 org
.x
= (s
->m_scrAlignment
%3) == 1 ? r
.left
: (s
->m_scrAlignment
%3) == 2 ? r
.CenterPoint().x
: r
.right
;
3412 org
.y
= s
->m_scrAlignment
<= 3 ? r
.bottom
: s
->m_scrAlignment
<= 6 ? r
.CenterPoint().y
: r
.top
;
3413 if(!fOrgOverride
) org2
= org
;
3414 CPoint
p2(0, r
.top
);
3415 // Rectangles for inverse clip
3417 CRectCoor2 clipRect_coor2
;
3418 clipRect_coor2
.left
= clipRect
.left
* m_target_scale_x
;
3419 clipRect_coor2
.right
= clipRect
.right
* m_target_scale_x
;
3420 clipRect_coor2
.top
= clipRect
.top
* m_target_scale_y
;
3421 clipRect_coor2
.bottom
= clipRect
.bottom
* m_target_scale_y
;
3422 CSubtitle2
& sub2
= outputSub2List
->GetAt(outputSub2List
->AddTail( CSubtitle2(s
, clipRect_coor2
, org
, org2
, p2
, alpha
, m_time
) ));
3425 return (subs
.GetCount()) ? S_OK
: S_FALSE
;
3428 STDMETHODIMP
CRenderedTextSubtitle::RenderEx(SubPicDesc
& spd
, REFERENCE_TIME rt
, double fps
, CAtlList
<CRectCoor2
>& rectList
)
3430 CSize output_size
= CSize(spd
.w
,spd
.h
);
3431 rectList
.RemoveAll();
3433 CComPtr
<IXySubRenderFrame
> sub_render_frame
;
3434 HRESULT hr
= RenderEx(&sub_render_frame
, spd
.type
, output_size
, output_size
, spd
.vidrect
, rt
, fps
);
3435 if (SUCCEEDED(hr
) && sub_render_frame
)
3438 hr
= sub_render_frame
->GetBitmapCount(&count
);
3444 hr
= sub_render_frame
->GetXyColorSpace(&color_space
);
3449 for (int i
=0;i
<count
;i
++)
3455 hr
= sub_render_frame
->GetBitmap(i
, NULL
, &pos
, &size
, &pixels
, &pitch
);
3460 rectList
.AddTail(CRect(pos
, size
));
3461 if (color_space
==XY_CS_AYUV_PLANAR
)
3463 XyPlannerFormatExtra plans
;
3464 hr
= sub_render_frame
->GetBitmapExtra(i
, &plans
);
3469 XyBitmap::AlphaBltPlannar(spd
, pos
, size
, plans
, pitch
);
3473 XyBitmap::AlphaBltPack(spd
, pos
, size
, pixels
, pitch
);
3477 return (!rectList
.IsEmpty()) ? S_OK
: S_FALSE
;
3480 STDMETHODIMP
CRenderedTextSubtitle::RenderEx( IXySubRenderFrame
**subRenderFrame
, int spd_type
,
3481 const SIZECoor2
& size_scale_to
, const SIZE
& size1
, const CRect
& video_rect
,
3482 REFERENCE_TIME rt
, double fps
)
3484 if (!subRenderFrame
)
3489 XyColorSpace color_space
= XY_CS_ARGB
;
3492 case MSP_AYUV_PLANAR
:
3493 color_space
= XY_CS_AYUV_PLANAR
;
3496 color_space
= XY_CS_AUYV
;
3499 color_space
= XY_CS_AYUV
;
3502 color_space
= XY_CS_ARGB
;
3506 XySubRenderFrameCreater
*render_frame_creater
= XySubRenderFrameCreater::GetDefaultCreater();
3507 render_frame_creater
->SetColorSpace(color_space
);
3509 if( m_size_scale_to
!= CSize(size_scale_to
.cx
*8, size_scale_to
.cy
*8)
3510 || m_size
!= CSize(size1
.cx
*8, size1
.cy
*8)
3511 || m_vidrect
!= CRect(video_rect
.left
*8, video_rect
.top
*8, video_rect
.right
*8, video_rect
.bottom
*8))
3513 Init(size_scale_to
, size1
, video_rect
);
3514 render_frame_creater
->SetOutputRect(CRect(0, 0, size_scale_to
.cx
, size_scale_to
.cy
));
3515 render_frame_creater
->SetClipRect(CRect(0, 0, size_scale_to
.cx
, size_scale_to
.cy
));
3518 CSubtitle2List sub2List
;
3519 HRESULT hr
= ParseScript(rt
, fps
, &sub2List
);
3525 CompositeDrawItemListList compDrawItemListList
;
3526 DoRender(size_scale_to
, sub2List
, &compDrawItemListList
);
3528 XySubRenderFrame
*sub_render_frame
;
3529 CompositeDrawItem::Draw(&sub_render_frame
, compDrawItemListList
);
3530 (*subRenderFrame
= sub_render_frame
)->AddRef();
3535 void CRenderedTextSubtitle::DoRender( const SIZECoor2
& output_size
, const CSubtitle2List
& sub2List
,
3536 CompositeDrawItemListList
*compDrawItemListList
/*output*/)
3538 //check input and log error
3539 POSITION pos
=sub2List
.GetHeadPosition();
3542 const CSubtitle2
& sub2
= sub2List
.GetNext(pos
);
3543 CompositeDrawItemList
& compDrawItemList
= compDrawItemListList
->GetAt(compDrawItemListList
->AddTail());
3544 RenderOneSubtitle(output_size
, sub2
, &compDrawItemList
);
3548 void CRenderedTextSubtitle::RenderOneSubtitle( const SIZECoor2
& output_size
, const CSubtitle2
& sub2
,
3549 CompositeDrawItemList
* compDrawItemList
/*output*/)
3551 CSubtitle
* s
= sub2
.s
;
3552 const CRect
& clipRect
= sub2
.clipRect
;
3553 const CPoint
& org
= sub2
.org
;
3554 const CPoint
& org2
= sub2
.org2
;
3555 const CPoint
& p2
= sub2
.p
;
3556 int alpha
= sub2
.alpha
;
3557 int time
= sub2
.time
;
3560 SharedPtrCClipperPaintMachine
clipper( new CClipperPaintMachine(s
->m_pClipper
) );
3563 iclipRect
[0] = CRect(0, 0, output_size
.cx
, clipRect
.top
);
3564 iclipRect
[1] = CRect(0, clipRect
.top
, clipRect
.left
, clipRect
.bottom
);
3565 iclipRect
[2] = CRect(clipRect
.right
, clipRect
.top
, output_size
.cx
, clipRect
.bottom
);
3566 iclipRect
[3] = CRect(0, clipRect
.bottom
, output_size
.cx
, output_size
.cy
);
3567 CRect
bbox2(0,0,0,0);
3568 POSITION pos
= s
->GetHeadLinePosition();
3572 CLine
* l
= s
->GetNextLine(pos
);
3573 p
.x
= (s
->m_scrAlignment
%3) == 1 ? org
.x
3574 : (s
->m_scrAlignment
%3) == 0 ? org
.x
- l
->m_width
3575 : org
.x
- (l
->m_width
/2);
3577 CompositeDrawItemList tmpCompDrawItemList
;
3578 if (s
->m_clipInverse
)
3580 CompositeDrawItemList tmp1
,tmp2
,tmp3
,tmp4
;
3581 for (int i
=0;i
<l
->GetWordCount();i
++)
3588 bbox2
|= l
->PaintAll(&tmp1
, iclipRect
[0], clipper
, p
, org2
, time
, alpha
);
3589 bbox2
|= l
->PaintAll(&tmp2
, iclipRect
[1], clipper
, p
, org2
, time
, alpha
);
3590 bbox2
|= l
->PaintAll(&tmp3
, iclipRect
[2], clipper
, p
, org2
, time
, alpha
);
3591 bbox2
|= l
->PaintAll(&tmp4
, iclipRect
[3], clipper
, p
, org2
, time
, alpha
);
3592 tmpCompDrawItemList
.AddTailList(&tmp1
);
3593 tmpCompDrawItemList
.AddTailList(&tmp2
);
3594 tmpCompDrawItemList
.AddTailList(&tmp3
);
3595 tmpCompDrawItemList
.AddTailList(&tmp4
);
3599 for (int i
=0;i
<l
->GetWordCount();i
++)
3601 tmpCompDrawItemList
.AddTail();
3603 bbox2
|= l
->PaintAll(&tmpCompDrawItemList
, clipRect
, clipper
, p
, org2
, time
, alpha
);
3605 compDrawItemList
->AddTailList(&tmpCompDrawItemList
);
3606 p
.y
+= l
->m_ascent
+ l
->m_descent
;
3610 STDMETHODIMP
CRenderedTextSubtitle::Render(SubPicDesc
& spd
, REFERENCE_TIME rt
, double fps
, RECTCoor2
& bbox
)
3612 CAtlList
<CRect
> rectList
;
3613 HRESULT result
= RenderEx(spd
, rt
, fps
, rectList
);
3614 POSITION pos
= rectList
.GetHeadPosition();
3615 CRect
bbox2(0,0,0,0);
3618 bbox2
|= rectList
.GetNext(pos
);
3626 STDMETHODIMP
CRenderedTextSubtitle::GetClassID(CLSID
* pClassID
)
3628 return pClassID
? *pClassID
= __uuidof(this), S_OK
: E_POINTER
;
3633 STDMETHODIMP_(int) CRenderedTextSubtitle::GetStreamCount()
3638 STDMETHODIMP
CRenderedTextSubtitle::GetStreamInfo(int iStream
, WCHAR
** ppName
, LCID
* pLCID
)
3640 if(iStream
!= 0) return E_INVALIDARG
;
3643 *ppName
= (WCHAR
*)CoTaskMemAlloc((m_name
.GetLength()+1)*sizeof(WCHAR
));
3645 return E_OUTOFMEMORY
;
3646 wcscpy(*ppName
, CStringW(m_name
));
3655 STDMETHODIMP_(int) CRenderedTextSubtitle::GetStream()
3660 STDMETHODIMP
CRenderedTextSubtitle::SetStream(int iStream
)
3662 return iStream
== 0 ? S_OK
: E_FAIL
;
3665 STDMETHODIMP
CRenderedTextSubtitle::Reload()
3668 if(!CFile::GetStatus(m_path
, s
)) return E_FAIL
;
3669 return !m_path
.IsEmpty() && Open(m_path
, DEFAULT_CHARSET
) ? S_OK
: E_FAIL
;
3672 STDMETHODIMP_(bool) CRenderedTextSubtitle::IsColorTypeSupported( int type
)
3674 return type
==MSP_AYUV_PLANAR
||
3676 type
==MSP_XY_AUYV
||
3680 STDMETHODIMP
CRenderedTextSubtitle::Lock()
3682 return CSubPicProviderImpl::Lock();
3685 STDMETHODIMP
CRenderedTextSubtitle::Unlock()
3687 return CSubPicProviderImpl::Unlock();