a5437cf6e6ec5488966ff3051e5537833da86175
[WebKit-https.git] / Source / WebCore / platform / graphics / avfoundation / InbandTextTrackPrivateAVF.cpp
1 /*
2  * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27
28 #if ENABLE(VIDEO) && (USE(AVFOUNDATION) || PLATFORM(IOS))
29
30 #include "InbandTextTrackPrivateAVF.h"
31
32 #include "InbandTextTrackPrivateClient.h"
33 #include "Logging.h"
34 #include "SoftLinking.h"
35 #include <CoreMedia/CoreMedia.h>
36 #include <wtf/PassOwnPtr.h>
37 #include <wtf/text/CString.h>
38 #include <wtf/text/WTFString.h>
39 #include <wtf/unicode/CharacterNames.h>
40
41 #if !PLATFORM(WIN)
42 #define SOFT_LINK_AVF_FRAMEWORK(Lib) SOFT_LINK_FRAMEWORK_OPTIONAL(Lib)
43 #define SOFT_LINK_AVF_POINTER(Lib, Name, Type) SOFT_LINK_POINTER_OPTIONAL(Lib, Name, Type)
44 #else
45 #ifdef DEBUG_ALL
46 #define SOFT_LINK_AVF_FRAMEWORK(Lib) SOFT_LINK_DEBUG_LIBRARY(Lib)
47 #else
48 #define SOFT_LINK_AVF_FRAMEWORK(Lib) SOFT_LINK_LIBRARY(Lib)
49 #endif
50
51 #define SOFT_LINK_AVF_POINTER(Lib, Name, Type) SOFT_LINK_VARIABLE_DLL_IMPORT_OPTIONAL(Lib, Name, Type)
52 #endif
53
54 SOFT_LINK_AVF_FRAMEWORK(CoreMedia)
55
56 SOFT_LINK_AVF_POINTER(CoreMedia, kCMTextMarkupAttribute_Alignment, CFStringRef)
57 SOFT_LINK_AVF_POINTER(CoreMedia, kCMTextMarkupAlignmentType_Start, CFStringRef)
58 SOFT_LINK_AVF_POINTER(CoreMedia, kCMTextMarkupAlignmentType_Middle, CFStringRef)
59 SOFT_LINK_AVF_POINTER(CoreMedia, kCMTextMarkupAlignmentType_End, CFStringRef)
60 SOFT_LINK_AVF_POINTER(CoreMedia, kCMTextMarkupAttribute_BoldStyle, CFStringRef)
61 SOFT_LINK_AVF_POINTER(CoreMedia, kCMTextMarkupAttribute_ItalicStyle, CFStringRef)
62 SOFT_LINK_AVF_POINTER(CoreMedia, kCMTextMarkupAttribute_UnderlineStyle, CFStringRef)
63 SOFT_LINK_AVF_POINTER(CoreMedia, kCMTextMarkupAttribute_TextPositionPercentageRelativeToWritingDirection, CFStringRef)
64 SOFT_LINK_AVF_POINTER(CoreMedia, kCMTextMarkupAttribute_WritingDirectionSizePercentage, CFStringRef)
65 SOFT_LINK_AVF_POINTER(CoreMedia, kCMTextMarkupAttribute_OrthogonalLinePositionPercentageRelativeToWritingDirection, CFStringRef)
66 SOFT_LINK_AVF_POINTER(CoreMedia, kCMTextMarkupAttribute_VerticalLayout, CFStringRef)
67 SOFT_LINK_AVF_POINTER(CoreMedia, kCMTextVerticalLayout_LeftToRight, CFStringRef)
68 SOFT_LINK_AVF_POINTER(CoreMedia, kCMTextVerticalLayout_RightToLeft, CFStringRef)
69 SOFT_LINK_AVF_POINTER(CoreMedia, kCMTextMarkupAttribute_BaseFontSizePercentageRelativeToVideoHeight, CFStringRef)
70 SOFT_LINK_AVF_POINTER(CoreMedia, kCMTextMarkupAttribute_RelativeFontSize, CFStringRef)
71 SOFT_LINK_AVF_POINTER(CoreMedia, kCMTextMarkupAttribute_FontFamilyName, CFStringRef)
72 SOFT_LINK_AVF_POINTER(CoreMedia, kCMTextMarkupAttribute_ForegroundColorARGB, CFStringRef)
73 SOFT_LINK_AVF_POINTER(CoreMedia, kCMTextMarkupAttribute_BackgroundColorARGB, CFStringRef)
74 SOFT_LINK_AVF_POINTER(CoreMedia, kCMTextMarkupAttribute_CharacterBackgroundColorARGB, CFStringRef)
75
76 #define kCMTextMarkupAttribute_Alignment getkCMTextMarkupAttribute_Alignment()
77 #define kCMTextMarkupAlignmentType_Start getkCMTextMarkupAlignmentType_Start()
78 #define kCMTextMarkupAlignmentType_Middle getkCMTextMarkupAlignmentType_Middle()
79 #define kCMTextMarkupAlignmentType_End getkCMTextMarkupAlignmentType_End()
80 #define kCMTextMarkupAttribute_BoldStyle getkCMTextMarkupAttribute_BoldStyle()
81 #define kCMTextMarkupAttribute_ItalicStyle getkCMTextMarkupAttribute_ItalicStyle()
82 #define kCMTextMarkupAttribute_UnderlineStyle getkCMTextMarkupAttribute_UnderlineStyle()
83 #define kCMTextMarkupAttribute_TextPositionPercentageRelativeToWritingDirection getkCMTextMarkupAttribute_TextPositionPercentageRelativeToWritingDirection()
84 #define kCMTextMarkupAttribute_WritingDirectionSizePercentage getkCMTextMarkupAttribute_WritingDirectionSizePercentage()
85 #define kCMTextMarkupAttribute_OrthogonalLinePositionPercentageRelativeToWritingDirection getkCMTextMarkupAttribute_OrthogonalLinePositionPercentageRelativeToWritingDirection()
86 #define kCMTextMarkupAttribute_VerticalLayout getkCMTextMarkupAttribute_VerticalLayout()
87 #define kCMTextVerticalLayout_LeftToRight getkCMTextVerticalLayout_LeftToRight()
88 #define kCMTextVerticalLayout_RightToLeft getkCMTextVerticalLayout_RightToLeft()
89 #define kCMTextMarkupAttribute_BaseFontSizePercentageRelativeToVideoHeight getkCMTextMarkupAttribute_BaseFontSizePercentageRelativeToVideoHeight()
90 #define kCMTextMarkupAttribute_RelativeFontSize getkCMTextMarkupAttribute_RelativeFontSize()
91 #define kCMTextMarkupAttribute_FontFamilyName getkCMTextMarkupAttribute_FontFamilyName()
92 #define kCMTextMarkupAttribute_ForegroundColorARGB getkCMTextMarkupAttribute_ForegroundColorARGB()
93 #define kCMTextMarkupAttribute_BackgroundColorARGB getkCMTextMarkupAttribute_BackgroundColorARGB()
94 #define kCMTextMarkupAttribute_CharacterBackgroundColorARGB getkCMTextMarkupAttribute_CharacterBackgroundColorARGB()
95
96 namespace WebCore {
97
98 AVFInbandTrackParent::~AVFInbandTrackParent()
99 {
100 }
101
102 InbandTextTrackPrivateAVF::InbandTextTrackPrivateAVF(AVFInbandTrackParent* owner)
103     : InbandTextTrackPrivate(Generic)
104     , m_owner(owner)
105     , m_pendingCueStatus(None)
106     , m_index(0)
107     , m_hasBeenReported(false)
108     , m_seeking(false)
109 {
110 }
111
112 InbandTextTrackPrivateAVF::~InbandTextTrackPrivateAVF()
113 {
114     disconnect();
115 }
116
117 static bool makeRGBA32FromARGBCFArray(CFArrayRef colorArray, RGBA32& color)
118 {
119     if (CFArrayGetCount(colorArray) < 4)
120         return false;
121
122     float componentArray[4];
123     for (int i = 0; i < 4; i++) {
124         CFNumberRef value = static_cast<CFNumberRef>(CFArrayGetValueAtIndex(colorArray, i));
125         if (CFGetTypeID(value) != CFNumberGetTypeID())
126             return false;
127
128         float component;
129         CFNumberGetValue(value, kCFNumberFloatType, &component);
130         componentArray[i] = component;
131     }
132
133     color = makeRGBA32FromFloats(componentArray[1], componentArray[2], componentArray[3], componentArray[0]);
134     return true;
135 }
136
137 void InbandTextTrackPrivateAVF::processCueAttributes(CFAttributedStringRef attributedString, GenericCueData* cueData)
138 {
139     // Some of the attributes we translate into per-cue WebVTT settings are are repeated on each part of an attributed string so only
140     // process the first instance of each.
141     enum AttributeFlags {
142         Line = 1 << 0,
143         Position = 1 << 1,
144         Size = 1 << 2,
145         Vertical = 1 << 3,
146         Align = 1 << 4,
147         FontName = 1 << 5
148     };
149     unsigned processed = 0;
150
151     StringBuilder content;
152     String attributedStringValue = CFAttributedStringGetString(attributedString);
153     CFIndex length = attributedStringValue.length();
154     if (!length)
155         return;
156
157     CFRange effectiveRange = CFRangeMake(0, 0);
158     while ((effectiveRange.location + effectiveRange.length) < length) {
159
160         CFDictionaryRef attributes = CFAttributedStringGetAttributes(attributedString, effectiveRange.location + effectiveRange.length, &effectiveRange);
161         if (!attributes)
162             continue;
163
164         StringBuilder tagStart;
165         CFStringRef valueString;
166         String tagEnd;
167         CFIndex attributeCount = CFDictionaryGetCount(attributes);
168         Vector<const void*> keys(attributeCount);
169         Vector<const void*> values(attributeCount);
170         CFDictionaryGetKeysAndValues(attributes, keys.data(), values.data());
171
172         for (CFIndex i = 0; i < attributeCount; ++i) {
173             CFStringRef key = static_cast<CFStringRef>(keys[i]);
174             CFTypeRef value = values[i];
175             if (CFGetTypeID(key) != CFStringGetTypeID() || !CFStringGetLength(key))
176                 continue;
177
178             if (CFStringCompare(key, kCMTextMarkupAttribute_Alignment, 0) == kCFCompareEqualTo) {
179                 valueString = static_cast<CFStringRef>(value);
180                 if (CFGetTypeID(valueString) != CFStringGetTypeID() || !CFStringGetLength(valueString))
181                     continue;
182                 if (processed & Align)
183                     continue;
184                 processed |= Align;
185
186                 if (CFStringCompare(valueString, kCMTextMarkupAlignmentType_Start, 0) == kCFCompareEqualTo)
187                     cueData->setAlign(GenericCueData::Start);
188                 else if (CFStringCompare(valueString, kCMTextMarkupAlignmentType_Middle, 0) == kCFCompareEqualTo)
189                     cueData->setAlign(GenericCueData::Middle);
190                 else if (CFStringCompare(valueString, kCMTextMarkupAlignmentType_End, 0) == kCFCompareEqualTo)
191                     cueData->setAlign(GenericCueData::End);
192                 else
193                     ASSERT_NOT_REACHED();
194
195                 continue;
196             }
197
198             if (CFStringCompare(key, kCMTextMarkupAttribute_BoldStyle, 0) == kCFCompareEqualTo) {
199                 if (static_cast<CFBooleanRef>(value) != kCFBooleanTrue)
200                     continue;
201
202                 tagStart.append("<b>");
203                 tagEnd = "</b>" + tagEnd;
204                 continue;
205             }
206
207             if (CFStringCompare(key, kCMTextMarkupAttribute_ItalicStyle, 0) == kCFCompareEqualTo) {
208                 if (static_cast<CFBooleanRef>(value) != kCFBooleanTrue)
209                     continue;
210
211                 tagStart.append("<i>");
212                 tagEnd = "</i>" + tagEnd;
213                 continue;
214             }
215
216             if (CFStringCompare(key, kCMTextMarkupAttribute_UnderlineStyle, 0) == kCFCompareEqualTo) {
217                 if (static_cast<CFBooleanRef>(value) != kCFBooleanTrue)
218                     continue;
219
220                 tagStart.append("<u>");
221                 tagEnd = "</u>" + tagEnd;
222                 continue;
223             }
224
225             if (CFStringCompare(key, kCMTextMarkupAttribute_OrthogonalLinePositionPercentageRelativeToWritingDirection, 0) == kCFCompareEqualTo) {
226                 if (CFGetTypeID(value) != CFNumberGetTypeID())
227                     continue;
228                 if (processed & Line)
229                     continue;
230                 processed |= Line;
231
232                 CFNumberRef valueNumber = static_cast<CFNumberRef>(value);
233                 double line;
234                 CFNumberGetValue(valueNumber, kCFNumberFloat64Type, &line);
235                 cueData->setLine(line);
236                 continue;
237             }
238
239             if (CFStringCompare(key, kCMTextMarkupAttribute_TextPositionPercentageRelativeToWritingDirection, 0) == kCFCompareEqualTo) {
240                 if (CFGetTypeID(value) != CFNumberGetTypeID())
241                     continue;
242                 if (processed & Position)
243                     continue;
244                 processed |= Position;
245
246                 CFNumberRef valueNumber = static_cast<CFNumberRef>(value);
247                 double position;
248                 CFNumberGetValue(valueNumber, kCFNumberFloat64Type, &position);
249                 cueData->setPosition(position);
250                 continue;
251             }
252
253             if (CFStringCompare(key, kCMTextMarkupAttribute_WritingDirectionSizePercentage, 0) == kCFCompareEqualTo) {
254                 if (CFGetTypeID(value) != CFNumberGetTypeID())
255                     continue;
256                 if (processed & Size)
257                     continue;
258                 processed |= Size;
259
260                 CFNumberRef valueNumber = static_cast<CFNumberRef>(value);
261                 double size;
262                 CFNumberGetValue(valueNumber, kCFNumberFloat64Type, &size);
263                 cueData->setSize(size);
264                 continue;
265             }
266
267             if (CFStringCompare(key, kCMTextMarkupAttribute_VerticalLayout, 0) == kCFCompareEqualTo) {
268                 valueString = static_cast<CFStringRef>(value);
269                 if (CFGetTypeID(valueString) != CFStringGetTypeID() || !CFStringGetLength(valueString))
270                     continue;
271                 
272                 if (CFStringCompare(valueString, kCMTextVerticalLayout_LeftToRight, 0) == kCFCompareEqualTo)
273                     tagStart.append(leftToRightMark);
274                 else if (CFStringCompare(valueString, kCMTextVerticalLayout_RightToLeft, 0) == kCFCompareEqualTo)
275                     tagStart.append(rightToLeftMark);
276                 continue;
277             }
278
279             if (CFStringCompare(key, kCMTextMarkupAttribute_BaseFontSizePercentageRelativeToVideoHeight, 0) == kCFCompareEqualTo) {
280                 if (CFGetTypeID(value) != CFNumberGetTypeID())
281                     continue;
282                 
283                 CFNumberRef valueNumber = static_cast<CFNumberRef>(value);
284                 double baseFontSize;
285                 CFNumberGetValue(valueNumber, kCFNumberFloat64Type, &baseFontSize);
286                 cueData->setBaseFontSize(baseFontSize);
287                 continue;
288             }
289
290             if (CFStringCompare(key, kCMTextMarkupAttribute_RelativeFontSize, 0) == kCFCompareEqualTo) {
291                 if (CFGetTypeID(value) != CFNumberGetTypeID())
292                     continue;
293                 
294                 CFNumberRef valueNumber = static_cast<CFNumberRef>(value);
295                 double relativeFontSize;
296                 CFNumberGetValue(valueNumber, kCFNumberFloat64Type, &relativeFontSize);
297                 cueData->setRelativeFontSize(relativeFontSize);
298                 continue;
299             }
300
301             if (CFStringCompare(key, kCMTextMarkupAttribute_FontFamilyName, 0) == kCFCompareEqualTo) {
302                 valueString = static_cast<CFStringRef>(value);
303                 if (CFGetTypeID(valueString) != CFStringGetTypeID() || !CFStringGetLength(valueString))
304                     continue;
305                 if (processed & FontName)
306                     continue;
307                 processed |= FontName;
308                 
309                 cueData->setFontName(valueString);
310                 continue;
311             }
312
313             if (CFStringCompare(key, kCMTextMarkupAttribute_ForegroundColorARGB, 0) == kCFCompareEqualTo) {
314                 CFArrayRef arrayValue = static_cast<CFArrayRef>(value);
315                 if (CFGetTypeID(arrayValue) != CFArrayGetTypeID())
316                     continue;
317                 
318                 RGBA32 color;
319                 if (!makeRGBA32FromARGBCFArray(arrayValue, color))
320                     continue;
321                 cueData->setForegroundColor(color);
322             }
323             
324             if (CFStringCompare(key, kCMTextMarkupAttribute_BackgroundColorARGB, 0) == kCFCompareEqualTo) {
325                 CFArrayRef arrayValue = static_cast<CFArrayRef>(value);
326                 if (CFGetTypeID(arrayValue) != CFArrayGetTypeID())
327                     continue;
328                 
329                 RGBA32 color;
330                 if (!makeRGBA32FromARGBCFArray(arrayValue, color))
331                     continue;
332                 cueData->setBackgroundColor(color);
333             }
334
335             if (CFStringCompare(key, kCMTextMarkupAttribute_CharacterBackgroundColorARGB, 0) == kCFCompareEqualTo) {
336                 CFArrayRef arrayValue = static_cast<CFArrayRef>(value);
337                 if (CFGetTypeID(arrayValue) != CFArrayGetTypeID())
338                     continue;
339                 
340                 RGBA32 color;
341                 if (!makeRGBA32FromARGBCFArray(arrayValue, color))
342                     continue;
343                 cueData->setHighlightColor(color);
344             }
345         }
346
347         content.append(tagStart);
348         content.append(attributedStringValue.substring(effectiveRange.location, effectiveRange.length));
349         content.append(tagEnd);
350     }
351
352     if (content.length())
353         cueData->setContent(content.toString());
354 }
355
356 void InbandTextTrackPrivateAVF::processCue(CFArrayRef attributedStrings, double time)
357 {
358     if (!client())
359         return;
360
361     LOG(Media, "InbandTextTrackPrivateAVF::processCue - %li cues at time %.2f\n", attributedStrings ? CFArrayGetCount(attributedStrings) : 0, time);
362
363     Vector<RefPtr<GenericCueData>> arrivingCues;
364     if (attributedStrings) {
365         CFIndex count = CFArrayGetCount(attributedStrings);
366         for (CFIndex i = 0; i < count; i++) {
367             CFAttributedStringRef attributedString = static_cast<CFAttributedStringRef>(CFArrayGetValueAtIndex(attributedStrings, i));
368             
369             if (!attributedString || !CFAttributedStringGetLength(attributedString))
370                 continue;
371             
372             RefPtr<GenericCueData> cueData = GenericCueData::create();
373             processCueAttributes(attributedString, cueData.get());
374             if (!cueData->content().length())
375                 continue;
376             
377             arrivingCues.append(cueData);
378             
379             cueData->setStartTime(time);
380             cueData->setEndTime(std::numeric_limits<double>::infinity());
381             
382             // AVFoundation cue "position" is to the center of the text so adjust relative to the edge because we will use it to
383             // set CSS "left".
384             if (cueData->position() >= 0 && cueData->size() > 0)
385                 cueData->setPosition(cueData->position() - cueData->size() / 2);
386             
387             LOG(Media, "InbandTextTrackPrivateAVF::processCue(%p) - considering cue (\"%s\") for time = %.2f, position =  %.2f, line =  %.2f", this, cueData->content().utf8().data(), cueData->startTime(), cueData->position(), cueData->line());
388             
389             cueData->setStatus(GenericCueData::Partial);
390         }
391     }
392
393     if (m_pendingCueStatus != None) {
394         // Cues do not have an explicit duration, they are displayed until the next "cue" (which might be empty) is emitted.
395         m_currentCueEndTime = time;
396
397         if (m_currentCueEndTime >= m_currentCueStartTime) {
398             for (auto& cueData : m_cues) {
399                 // See if one of the newly-arrived cues is an extension of this cue.
400                 Vector<RefPtr<GenericCueData>> nonExtensionCues;
401                 for (auto& arrivingCue : arrivingCues) {
402                     if (!arrivingCue->doesExtendCueData(*cueData))
403                         nonExtensionCues.append(arrivingCue);
404                     else
405                         LOG(Media, "InbandTextTrackPrivateAVF::processCue(%p) - found an extension cue (\"%s\") for time = %.2f, position =  %.2f, line =  %.2f", this, arrivingCue->content().utf8().data(), arrivingCue->startTime(), arrivingCue->position(), arrivingCue->line());
406                 }
407
408                 bool currentCueIsExtended = (arrivingCues.size() != nonExtensionCues.size());
409
410                 arrivingCues = nonExtensionCues;
411                 
412                 if (currentCueIsExtended)
413                     continue;
414
415                 if (m_pendingCueStatus == Valid) {
416                     cueData->setEndTime(m_currentCueEndTime);
417                     cueData->setStatus(GenericCueData::Complete);
418
419                     LOG(Media, "InbandTextTrackPrivateAVF::processCue(%p) - updating cue: start=%.2f, end=%.2f, content=\"%s\"", this, cueData->startTime(), m_currentCueEndTime, cueData->content().utf8().data());
420                     client()->updateGenericCue(this, cueData.get());
421                 } else {
422                     // We have to assume that the implicit duration is invalid for cues delivered during a seek because the AVF decode pipeline may not
423                     // see every cue, so DO NOT update cue duration while seeking.
424                     LOG(Media, "InbandTextTrackPrivateAVF::processCue(%p) - ignoring cue delivered during seek: start=%.2f, end=%.2f, content=\"%s\"", this, cueData->startTime(), m_currentCueEndTime, cueData->content().utf8().data());
425                 }
426             }
427         } else
428             LOG(Media, "InbandTextTrackPrivateAVF::processCue negative length cue(s) ignored: start=%.2f, end=%.2f\n", m_currentCueStartTime, m_currentCueEndTime);
429
430         removeCompletedCues();
431     }
432
433     if (arrivingCues.isEmpty())
434         return;
435
436     m_currentCueStartTime = time;
437
438     for (auto& cueData : arrivingCues) {
439
440         m_cues.append(cueData);
441         
442         LOG(Media, "InbandTextTrackPrivateAVF::processCue(%p) - adding cue for time = %.2f, position =  %.2f, line =  %.2f", this, cueData->startTime(), cueData->position(), cueData->line());
443
444         client()->addGenericCue(this, cueData.release());
445
446         m_pendingCueStatus = seeking() ? DeliveredDuringSeek : Valid;
447     }
448 }
449
450 void InbandTextTrackPrivateAVF::beginSeeking()
451 {
452     // Forget any partially accumulated cue data as the seek could be to a time outside of the cue's
453     // range, which will mean that the next cue delivered will result in the current cue getting the
454     // incorrect duration.
455     resetCueValues();
456     m_seeking = true;
457 }
458
459 void InbandTextTrackPrivateAVF::disconnect()
460 {
461     m_owner = 0;
462     m_index = 0;
463 }
464
465 void InbandTextTrackPrivateAVF::removeCompletedCues()
466 {
467     if (client()) {
468         long currentCue = m_cues.size() - 1;
469         for (; currentCue > 0; --currentCue) {
470             if (m_cues[currentCue]->status() != GenericCueData::Complete)
471                 continue;
472
473             LOG(Media, "InbandTextTrackPrivateAVF::removeCompletedCues(%p) - removing cue (\"%s\") for time = %.2f, position =  %.2f, line =  %.2f", this, m_cues[currentCue]->content().utf8().data(), m_cues[currentCue]->startTime(), m_cues[currentCue]->position(), m_cues[currentCue]->line());
474             client()->removeGenericCue(this, m_cues[currentCue].get());
475             m_cues.remove(currentCue);
476         }
477     }
478
479     if (m_cues.isEmpty())
480         m_pendingCueStatus = None;
481
482     m_currentCueStartTime = 0;
483     m_currentCueEndTime = 0;
484 }
485
486 void InbandTextTrackPrivateAVF::resetCueValues()
487 {
488     if (m_currentCueEndTime && m_cues.size())
489         LOG(Media, "InbandTextTrackPrivateAVF::resetCueValues flushing data for cues: start=%.2f\n", m_currentCueStartTime);
490
491     if (client()) {
492         for (size_t i = 0; i < m_cues.size(); i++)
493             client()->removeGenericCue(this, m_cues[i].get());
494     }
495
496     m_cues.resize(0);
497     m_pendingCueStatus = None;
498     m_currentCueStartTime = 0;
499     m_currentCueEndTime = 0;
500 }
501
502 void InbandTextTrackPrivateAVF::setMode(InbandTextTrackPrivate::Mode newMode)
503 {
504     if (!m_owner)
505         return;
506
507     InbandTextTrackPrivate::Mode oldMode = mode();
508     InbandTextTrackPrivate::setMode(newMode);
509
510     if (oldMode == newMode)
511         return;
512
513     m_owner->trackModeChanged();
514 }
515
516 } // namespace WebCore
517
518 #endif // ENABLE(VIDEO) && (USE(AVFOUNDATION) || PLATFORM(IOS))