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 <runtime/Protect.h>
36
37namespace WebCore {
38
39DataCue::DataCue(ScriptExecutionContext& context, double start, double end, ArrayBuffer* data, const String& type, ExceptionCode& ec)
40    : TextTrackCue(context, start, end)
41    , m_type(type)
42{
43    setData(data, ec);
44}
45
46DataCue::DataCue(ScriptExecutionContext& context, double start, double end, const void* data, unsigned length)
47    : TextTrackCue(context, start, end)
48{
49    m_data = ArrayBuffer::create(data, length);
50}
51
52#if ENABLE(DATACUE_VALUE)
53DataCue::DataCue(ScriptExecutionContext& context, double start, double end, PassRefPtr<SerializedPlatformRepresentation> platformValue, const String& type)
54    : TextTrackCue(context, start, end)
55    , m_type(type)
56    , m_platformValue(platformValue)
57{
58}
59
60DataCue::DataCue(ScriptExecutionContext& context, double start, double end, JSC::JSValue value, const String& type)
61    : TextTrackCue(context, start, end)
62    , m_type(type)
63    , m_value(value)
64{
65}
66#endif
67
68DataCue::~DataCue()
69{
70#if ENABLE(DATACUE_VALUE)
71    if (m_value)
72        JSC::gcUnprotect(m_value);
73#endif
74}
75
76PassRefPtr<ArrayBuffer> DataCue::data() const
77{
78#if ENABLE(DATACUE_VALUE)
79    if (m_platformValue)
80        return m_platformValue->data();
81#endif
82
83    if (!m_data)
84        return nullptr;
85
86    return ArrayBuffer::create(m_data.get());
87}
88
89void DataCue::setData(ArrayBuffer* data, ExceptionCode& ec)
90{
91    if (!data) {
92        ec = TypeError;
93        return;
94    }
95
96#if ENABLE(DATACUE_VALUE)
97    m_platformValue = nullptr;
98    m_value = JSC::JSValue();
99#endif
100
101    m_data = ArrayBuffer::create(data);
102}
103
104#if !ENABLE(DATACUE_VALUE)
105String DataCue::text(bool& isNull) const
106{
107    isNull = true;
108    return String();
109}
110#endif
111
112DataCue* toDataCue(TextTrackCue* cue)
113{
114    ASSERT_WITH_SECURITY_IMPLICATION(cue->cueType() == TextTrackCue::Data);
115    return static_cast<DataCue*>(cue);
116}
117
118const DataCue* toDataCue(const TextTrackCue* cue)
119{
120    ASSERT_WITH_SECURITY_IMPLICATION(cue->cueType() == TextTrackCue::Data);
121    return static_cast<const DataCue*>(cue);
122}
123
124bool DataCue::cueContentsMatch(const TextTrackCue& cue) const
125{
126    if (cue.cueType() != TextTrackCue::Data)
127        return false;
128
129    const DataCue* dataCue = toDataCue(&cue);
130    RefPtr<ArrayBuffer> otherData = dataCue->data();
131    if ((otherData && !m_data) || (!otherData && m_data))
132        return false;
133    if (m_data && m_data->byteLength() != otherData->byteLength())
134        return false;
135    if (m_data && m_data->data() && memcmp(m_data->data(), otherData->data(), m_data->byteLength()))
136        return false;
137
138#if ENABLE(DATACUE_VALUE)
139    RefPtr<SerializedPlatformRepresentation> otherPlatformValue = dataCue->platformValue();
140    if ((otherPlatformValue && !m_platformValue) || (!otherPlatformValue && m_platformValue))
141        return false;
142    if (m_platformValue && !m_platformValue->isEqual(*otherPlatformValue.get()))
143        return false;
144
145    JSC::JSValue thisValue = value(nullptr);
146    JSC::JSValue otherValue = dataCue->value(nullptr);
147    if ((otherValue && !thisValue) || (!otherValue && thisValue))
148        return false;
149    if (!JSC::JSValue::strictEqual(nullptr, thisValue, otherValue))
150        return false;
151#endif
152
153    return true;
154}
155
156bool DataCue::isEqual(const TextTrackCue& cue, TextTrackCue::CueMatchRules match) const
157{
158    if (!TextTrackCue::isEqual(cue, match))
159        return false;
160
161    if (cue.cueType() != TextTrackCue::Data)
162        return false;
163
164    return cueContentsMatch(cue);
165}
166
167bool DataCue::doesExtendCue(const TextTrackCue& cue) const
168{
169    if (!cueContentsMatch(cue))
170        return false;
171
172    return TextTrackCue::doesExtendCue(cue);
173}
174
175#if ENABLE(DATACUE_VALUE)
176JSC::JSValue DataCue::value(JSC::ExecState* exec) const
177{
178    if (exec && m_platformValue)
179        return m_platformValue->deserialize(exec);
180
181    if (m_value)
182        return m_value;
183
184    return JSC::jsNull();
185}
186
187void DataCue::setValue(JSC::ExecState*, JSC::JSValue value)
188{
189    // FIXME: this should use a SerializedScriptValue.
190    if (m_value)
191        JSC::gcUnprotect(m_value);
192    m_value = value;
193    if (m_value)
194        JSC::gcProtect(m_value);
195
196    m_platformValue = nullptr;
197    m_data = nullptr;
198}
199#endif
200
201} // namespace WebCore
202
203#endif
204