import { AribSubtitle , AribSubtitleRegion } from './arib-subtitle' ; import { VTTStyleManager } from './vtt-style-manager' ; import { escapeHTML , isFireFox , isSafari } from './utils' ; export default class VTTScreen { private subtitle : AribSubtitle ; private _undetermined : boolean ; private _guessDuration : number ; private _cues : VTTCue [ ] ; public constructor ( aribSubtitle ) { this . subtitle = aribSubtitle ; this . _undetermined = ( this . subtitle . duration === 0 ) ; this . _guessDuration = 0 ; this . _cues = [ ] ; } public dispose ( ) { this . subtitle = null ; this . _cues . length = 0 ; } public isAlive ( time ) { if ( time >= this . startTime && time < this . endTime ) { return true ; } return false ; } public get startTime ( ) : number { return this . subtitle . pts ; } public get endTime ( ) : number { return this . subtitle . pts + this . duration ; } public get duration ( ) : number { if ( this . _undetermined ) { return this . _guessDuration ; } return this . subtitle . duration ; } public set duration ( value ) { this . _undetermined = false ; this . _guessDuration = 0 ; this . subtitle . duration = value ; let endTime = this . subtitle . pts + value ; for ( let cue of this . _cues ) { cue . endTime = endTime / 1000 ; } } public get undetermined ( ) : boolean { return this . _undetermined ; } public get cues ( ) : VTTCue [ ] { return this . _cues ; } public render ( styleManager ) { let subtitle = this . subtitle ; let text = subtitle . rubylessText ( ) ; let id = subtitle . hashCode ( ) . toString ( ) ; if ( this . _undetermined ) { this . _guessDuration = Math . round ( text . length / 3 ) * 1000 ; } let orderedRegions = this . rearrangeRegions ( subtitle ) ; if ( ( window as any ) . VTTCue ) { let line = - 5 + orderedRegions . length ; for ( let regionLine of orderedRegions . reverse ( ) ) { let cueText = '' ; for ( let region of regionLine ) { let colorTag = styleManager . applyColor ( region . fontColor ) ; cueText += `<${ colorTag }>${ escapeHTML ( region . text ) }</v>` ; } let cue = new VTTCue ( this . startTime / 1000 , this . endTime / 1000 , cueText ) ; cue . id = id ; cue . snapToLines = true ; cue . lineAlign = 'start' ; cue . line = line -- ; cue . positionAlign = 'center' ; this . _cues . push ( cue ) ; } } else if ( ( window as any ) . TextTrackCue ) { for ( let regionLine of orderedRegions ) { let cueText = '' ; for ( let region of regionLine ) { cueText += region . text ; } let cue = new TextTrackCue ( this . startTime / 1000 , this . endTime / 1000 , escapeHTML ( cueText ) ) as VTTCue ; cue . id = id ; this . _cues . push ( cue ) ; } } return this . _cues ; } private rearrangeRegions ( subtitle ) { let map = new Map ( ) ; for ( let region of subtitle . regions ) { if ( region . fontHeight === 18 && region . fontWidth === 18 ) { continue ; } let regionArray = map . get ( region . charBottom ) ; if ( regionArray ) { regionArray . push ( region ) ; } else { map . set ( region . charBottom , [ region ] ) ; } } let newRegions = [ ] ; map . forEach ( ( regions , charBottom ) => { regions . sort ( ( a , b ) : number => { return a . charLeft - b . charLeft ; } ) ; newRegions . push ( regions ) ; } ) ; newRegions . sort ( ( a , b ) : number => { return a [ 0 ] . charBottom - b [ 0 ] . charBottom ; } ) ; return newRegions ; } }