1 | /* |
2 | * Copyright (C) 2011, 2013 Google Inc. All rights reserved. |
3 | * Copyright (C) 2011-2017 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 are |
7 | * met: |
8 | * |
9 | * * Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. |
11 | * * Redistributions in binary form must reproduce the above |
12 | * copyright notice, this list of conditions and the following disclaimer |
13 | * in the documentation and/or other materials provided with the |
14 | * distribution. |
15 | * * Neither the name of Google Inc. nor the names of its |
16 | * contributors may be used to endorse or promote products derived from |
17 | * this software without specific prior written permission. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
23 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
25 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
26 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
27 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | #include "config.h" |
33 | #include "TextTrackCue.h" |
34 | |
35 | #if ENABLE(VIDEO_TRACK) |
36 | |
37 | #include "CSSPropertyNames.h" |
38 | #include "CSSValueKeywords.h" |
39 | #include "Event.h" |
40 | #include "Logging.h" |
41 | #include "NodeTraversal.h" |
42 | #include "Text.h" |
43 | #include "TextTrack.h" |
44 | #include "TextTrackCueList.h" |
45 | #include "VTTCue.h" |
46 | #include "VTTRegionList.h" |
47 | #include <wtf/HexNumber.h> |
48 | #include <wtf/IsoMallocInlines.h> |
49 | #include <wtf/MathExtras.h> |
50 | #include <wtf/NeverDestroyed.h> |
51 | #include <wtf/text/StringConcatenateNumbers.h> |
52 | |
53 | namespace WebCore { |
54 | |
55 | WTF_MAKE_ISO_ALLOCATED_IMPL(TextTrackCue); |
56 | |
57 | const AtomicString& TextTrackCue::cueShadowPseudoId() |
58 | { |
59 | static NeverDestroyed<const AtomicString> cue("cue" , AtomicString::ConstructFromLiteral); |
60 | return cue; |
61 | } |
62 | |
63 | TextTrackCue::TextTrackCue(ScriptExecutionContext& context, const MediaTime& start, const MediaTime& end) |
64 | : m_startTime(start) |
65 | , m_endTime(end) |
66 | , m_scriptExecutionContext(context) |
67 | , m_isActive(false) |
68 | , m_pauseOnExit(false) |
69 | { |
70 | ASSERT(m_scriptExecutionContext.isDocument()); |
71 | } |
72 | |
73 | void TextTrackCue::willChange() |
74 | { |
75 | if (++m_processingCueChanges > 1) |
76 | return; |
77 | |
78 | if (m_track) |
79 | m_track->cueWillChange(this); |
80 | } |
81 | |
82 | void TextTrackCue::didChange() |
83 | { |
84 | ASSERT(m_processingCueChanges); |
85 | if (--m_processingCueChanges) |
86 | return; |
87 | |
88 | if (m_track) |
89 | m_track->cueDidChange(this); |
90 | } |
91 | |
92 | TextTrack* TextTrackCue::track() const |
93 | { |
94 | return m_track; |
95 | } |
96 | |
97 | void TextTrackCue::setTrack(TextTrack* track) |
98 | { |
99 | m_track = track; |
100 | } |
101 | |
102 | void TextTrackCue::setId(const String& id) |
103 | { |
104 | if (m_id == id) |
105 | return; |
106 | |
107 | willChange(); |
108 | m_id = id; |
109 | didChange(); |
110 | } |
111 | |
112 | void TextTrackCue::setStartTime(double value) |
113 | { |
114 | // TODO(93143): Add spec-compliant behavior for negative time values. |
115 | if (m_startTime.toDouble() == value || value < 0) |
116 | return; |
117 | |
118 | setStartTime(MediaTime::createWithDouble(value)); |
119 | } |
120 | |
121 | void TextTrackCue::setStartTime(const MediaTime& value) |
122 | { |
123 | willChange(); |
124 | m_startTime = value; |
125 | didChange(); |
126 | } |
127 | |
128 | void TextTrackCue::setEndTime(double value) |
129 | { |
130 | // TODO(93143): Add spec-compliant behavior for negative time values. |
131 | if (m_endTime.toDouble() == value || value < 0) |
132 | return; |
133 | |
134 | setEndTime(MediaTime::createWithDouble(value)); |
135 | } |
136 | |
137 | void TextTrackCue::setEndTime(const MediaTime& value) |
138 | { |
139 | willChange(); |
140 | m_endTime = value; |
141 | didChange(); |
142 | } |
143 | |
144 | void TextTrackCue::setPauseOnExit(bool value) |
145 | { |
146 | if (m_pauseOnExit == value) |
147 | return; |
148 | |
149 | m_pauseOnExit = value; |
150 | } |
151 | |
152 | void TextTrackCue::dispatchEvent(Event& event) |
153 | { |
154 | // When a TextTrack's mode is disabled: no cues are active, no events fired. |
155 | if (!track() || track()->mode() == TextTrack::Mode::Disabled) |
156 | return; |
157 | |
158 | EventTarget::dispatchEvent(event); |
159 | } |
160 | |
161 | bool TextTrackCue::isActive() |
162 | { |
163 | return m_isActive && track() && track()->mode() != TextTrack::Mode::Disabled; |
164 | } |
165 | |
166 | void TextTrackCue::setIsActive(bool active) |
167 | { |
168 | m_isActive = active; |
169 | } |
170 | |
171 | bool TextTrackCue::isOrderedBefore(const TextTrackCue* other) const |
172 | { |
173 | return startMediaTime() < other->startMediaTime() || (startMediaTime() == other->startMediaTime() && endMediaTime() > other->endMediaTime()); |
174 | } |
175 | |
176 | bool TextTrackCue::cueContentsMatch(const TextTrackCue& cue) const |
177 | { |
178 | if (cueType() != cue.cueType()) |
179 | return false; |
180 | |
181 | if (id() != cue.id()) |
182 | return false; |
183 | |
184 | return true; |
185 | } |
186 | |
187 | bool TextTrackCue::isEqual(const TextTrackCue& cue, TextTrackCue::CueMatchRules match) const |
188 | { |
189 | if (cueType() != cue.cueType()) |
190 | return false; |
191 | |
192 | if (match != IgnoreDuration && endMediaTime() != cue.endMediaTime()) |
193 | return false; |
194 | if (!hasEquivalentStartTime(cue)) |
195 | return false; |
196 | if (!cueContentsMatch(cue)) |
197 | return false; |
198 | |
199 | return true; |
200 | } |
201 | |
202 | bool TextTrackCue::hasEquivalentStartTime(const TextTrackCue& cue) const |
203 | { |
204 | MediaTime startTimeVariance = MediaTime::zeroTime(); |
205 | if (track()) |
206 | startTimeVariance = track()->startTimeVariance(); |
207 | else if (cue.track()) |
208 | startTimeVariance = cue.track()->startTimeVariance(); |
209 | |
210 | return abs(abs(startMediaTime()) - abs(cue.startMediaTime())) <= startTimeVariance; |
211 | } |
212 | |
213 | bool TextTrackCue::doesExtendCue(const TextTrackCue& cue) const |
214 | { |
215 | if (!cueContentsMatch(cue)) |
216 | return false; |
217 | |
218 | if (endMediaTime() != cue.startMediaTime()) |
219 | return false; |
220 | |
221 | return true; |
222 | } |
223 | |
224 | void TextTrackCue::toJSON(JSON::Object& value) const |
225 | { |
226 | ASCIILiteral type = "Generic"_s ; |
227 | switch (cueType()) { |
228 | case TextTrackCue::Generic: |
229 | type = "Generic"_s ; |
230 | break; |
231 | case TextTrackCue::WebVTT: |
232 | type = "WebVTT"_s ; |
233 | break; |
234 | case TextTrackCue::Data: |
235 | type = "Data"_s ; |
236 | break; |
237 | } |
238 | |
239 | value.setString("type"_s , type); |
240 | value.setDouble("startTime"_s , startTime()); |
241 | value.setDouble("endTime"_s , endTime()); |
242 | } |
243 | |
244 | String TextTrackCue::toJSONString() const |
245 | { |
246 | auto object = JSON::Object::create(); |
247 | |
248 | toJSON(object.get()); |
249 | |
250 | return object->toJSONString(); |
251 | } |
252 | |
253 | String TextTrackCue::debugString() const |
254 | { |
255 | String text; |
256 | if (isRenderable()) |
257 | text = toVTTCue(this)->text(); |
258 | return makeString("0x" , hex(reinterpret_cast<uintptr_t>(this)), " id=" , id(), " interval=" , startTime(), "-->" , endTime(), " cue=" , text, ')'); |
259 | } |
260 | |
261 | } // namespace WebCore |
262 | |
263 | #endif |
264 | |