1/*
2 * Copyright (C) 2014 Cable Television Labs Inc. All rights reserved.
3 * Copyright (C) 2014 Apple Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28
29#if ENABLE(VIDEO_TRACK)
30#include "DataCue.h"
31
32#include "Logging.h"
33#include "TextTrack.h"
34#include "TextTrackCueList.h"
35#include <JavaScriptCore/JSCInlines.h>
36#include <JavaScriptCore/Protect.h>
37#include <wtf/IsoMallocInlines.h>
38
39namespace WebCore {
40using namespace JSC;
41
42WTF_MAKE_ISO_ALLOCATED_IMPL(DataCue);
43
44DataCue::DataCue(ScriptExecutionContext& context, const MediaTime& start, const MediaTime& end, ArrayBuffer& data, const String& type)
45 : TextTrackCue(context, start, end)
46 , m_type(type)
47{
48 setData(data);
49}
50
51DataCue::DataCue(ScriptExecutionContext& context, const MediaTime& start, const MediaTime& end, const void* data, unsigned length)
52 : TextTrackCue(context, start, end)
53 , m_data(ArrayBuffer::create(data, length))
54{
55}
56
57DataCue::DataCue(ScriptExecutionContext& context, const MediaTime& start, const MediaTime& end, RefPtr<SerializedPlatformRepresentation>&& platformValue, const String& type)
58 : TextTrackCue(context, start, end)
59 , m_type(type)
60 , m_platformValue(WTFMove(platformValue))
61{
62}
63
64DataCue::DataCue(ScriptExecutionContext& context, const MediaTime& start, const MediaTime& end, JSC::JSValue value, const String& type)
65 : TextTrackCue(context, start, end)
66 , m_type(type)
67 , m_value(value)
68{
69 if (m_value)
70 JSC::gcProtect(m_value);
71}
72
73DataCue::~DataCue()
74{
75 if (m_value)
76 JSC::gcUnprotect(m_value);
77}
78
79RefPtr<ArrayBuffer> DataCue::data() const
80{
81 if (m_platformValue)
82 return m_platformValue->data();
83
84 if (!m_data)
85 return nullptr;
86
87 return ArrayBuffer::create(*m_data);
88}
89
90void DataCue::setData(ArrayBuffer& data)
91{
92 m_platformValue = nullptr;
93 if (m_value)
94 JSC::gcUnprotect(m_value);
95 m_value = JSC::JSValue();
96
97 m_data = ArrayBuffer::create(data);
98}
99
100DataCue* toDataCue(TextTrackCue* cue)
101{
102 ASSERT_WITH_SECURITY_IMPLICATION(cue->cueType() == TextTrackCue::Data);
103 return static_cast<DataCue*>(cue);
104}
105
106const DataCue* toDataCue(const TextTrackCue* cue)
107{
108 ASSERT_WITH_SECURITY_IMPLICATION(cue->cueType() == TextTrackCue::Data);
109 return static_cast<const DataCue*>(cue);
110}
111
112bool DataCue::cueContentsMatch(const TextTrackCue& cue) const
113{
114 if (cue.cueType() != TextTrackCue::Data)
115 return false;
116
117 const DataCue* dataCue = toDataCue(&cue);
118 RefPtr<ArrayBuffer> otherData = dataCue->data();
119 if ((otherData && !m_data) || (!otherData && m_data))
120 return false;
121 if (m_data && m_data->byteLength() != otherData->byteLength())
122 return false;
123 if (m_data && m_data->data() && memcmp(m_data->data(), otherData->data(), m_data->byteLength()))
124 return false;
125
126 const SerializedPlatformRepresentation* otherPlatformValue = dataCue->platformValue();
127 if ((otherPlatformValue && !m_platformValue) || (!otherPlatformValue && m_platformValue))
128 return false;
129 if (m_platformValue && !m_platformValue->isEqual(*otherPlatformValue))
130 return false;
131
132 JSC::JSValue thisValue = valueOrNull();
133 JSC::JSValue otherValue = dataCue->valueOrNull();
134 if ((otherValue && !thisValue) || (!otherValue && thisValue))
135 return false;
136 if (!JSC::JSValue::strictEqual(nullptr, thisValue, otherValue))
137 return false;
138
139 return true;
140}
141
142bool DataCue::isEqual(const TextTrackCue& cue, TextTrackCue::CueMatchRules match) const
143{
144 if (!TextTrackCue::isEqual(cue, match))
145 return false;
146
147 if (cue.cueType() != TextTrackCue::Data)
148 return false;
149
150 return cueContentsMatch(cue);
151}
152
153bool DataCue::doesExtendCue(const TextTrackCue& cue) const
154{
155 if (!cueContentsMatch(cue))
156 return false;
157
158 return TextTrackCue::doesExtendCue(cue);
159}
160
161JSC::JSValue DataCue::value(JSC::ExecState& state) const
162{
163 if (m_platformValue)
164 return m_platformValue->deserialize(&state);
165
166 if (m_value)
167 return m_value;
168
169 return JSC::jsNull();
170}
171
172void DataCue::setValue(JSC::ExecState&, JSC::JSValue value)
173{
174 // FIXME: this should use a SerializedScriptValue.
175 if (m_value)
176 JSC::gcUnprotect(m_value);
177 m_value = value;
178 if (m_value)
179 JSC::gcProtect(m_value);
180
181 m_platformValue = nullptr;
182 m_data = nullptr;
183}
184
185JSValue DataCue::valueOrNull() const
186{
187 if (m_value)
188 return m_value;
189
190 return jsNull();
191}
192
193String DataCue::toJSONString() const
194{
195 auto object = JSON::Object::create();
196
197 TextTrackCue::toJSON(object.get());
198
199 if (!m_type.isEmpty())
200 object->setString("type"_s, m_type);
201
202 return object->toJSONString();
203}
204
205} // namespace WebCore
206
207#endif
208