1 | /* |
2 | * Copyright (C) 2011-2017 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 | #include "TrackBase.h" |
28 | |
29 | #include "Logging.h" |
30 | #include <wtf/Language.h> |
31 | #include <wtf/text/StringBuilder.h> |
32 | |
33 | #if ENABLE(VIDEO_TRACK) |
34 | |
35 | #include "HTMLMediaElement.h" |
36 | |
37 | namespace WebCore { |
38 | |
39 | static int s_uniqueId = 0; |
40 | |
41 | #if !RELEASE_LOG_DISABLED |
42 | static const void* nextLogIdentifier() |
43 | { |
44 | static uint64_t logIdentifier = cryptographicallyRandomNumber(); |
45 | return reinterpret_cast<const void*>(++logIdentifier); |
46 | } |
47 | |
48 | static RefPtr<Logger>& nullLogger() |
49 | { |
50 | static NeverDestroyed<RefPtr<Logger>> logger; |
51 | return logger; |
52 | } |
53 | #endif |
54 | |
55 | TrackBase::TrackBase(Type type, const AtomicString& id, const AtomicString& label, const AtomicString& language) |
56 | : m_uniqueId(++s_uniqueId) |
57 | , m_id(id) |
58 | , m_label(label) |
59 | , m_language(language) |
60 | , m_validBCP47Language(language) |
61 | { |
62 | ASSERT(type != BaseTrack); |
63 | m_type = type; |
64 | |
65 | #if !RELEASE_LOG_DISABLED |
66 | if (!nullLogger().get()) { |
67 | nullLogger() = Logger::create(this); |
68 | nullLogger()->setEnabled(this, false); |
69 | } |
70 | |
71 | m_logger = nullLogger().get(); |
72 | m_logIdentifier = nextLogIdentifier(); |
73 | #endif |
74 | } |
75 | |
76 | Element* TrackBase::element() |
77 | { |
78 | return m_mediaElement; |
79 | } |
80 | |
81 | void TrackBase::setMediaElement(HTMLMediaElement* element) |
82 | { |
83 | m_mediaElement = element; |
84 | |
85 | #if !RELEASE_LOG_DISABLED |
86 | if (element) { |
87 | m_logger = &element->logger(); |
88 | m_logIdentifier = element->logIdentifier(); |
89 | } |
90 | #endif |
91 | } |
92 | |
93 | // See: https://tools.ietf.org/html/bcp47#section-2.1 |
94 | static bool isValidBCP47LanguageTag(const String& languageTag) |
95 | { |
96 | auto const length = languageTag.length(); |
97 | |
98 | // Max length picked as double the longest example tag in spec which is 49 characters: |
99 | // https://tools.ietf.org/html/bcp47#section-4.4.2 |
100 | if (length < 2 || length > 100) |
101 | return false; |
102 | |
103 | UChar firstChar = languageTag[0]; |
104 | |
105 | if (!isASCIIAlpha(firstChar)) |
106 | return false; |
107 | |
108 | UChar secondChar = languageTag[1]; |
109 | |
110 | if (length == 2) |
111 | return isASCIIAlpha(secondChar); |
112 | |
113 | bool grandFatheredIrregularOrPrivateUse = (firstChar == 'i' || firstChar == 'x') && secondChar == '-'; |
114 | unsigned nextCharIndexToCheck; |
115 | |
116 | if (!grandFatheredIrregularOrPrivateUse) { |
117 | if (!isASCIIAlpha(secondChar)) |
118 | return false; |
119 | |
120 | if (length == 3) |
121 | return isASCIIAlpha(languageTag[2]); |
122 | |
123 | if (isASCIIAlpha(languageTag[2])) { |
124 | if (languageTag[3] == '-') |
125 | nextCharIndexToCheck = 4; |
126 | else |
127 | return false; |
128 | } else if (languageTag[2] == '-') |
129 | nextCharIndexToCheck = 3; |
130 | else |
131 | return false; |
132 | } else |
133 | nextCharIndexToCheck = 2; |
134 | |
135 | for (; nextCharIndexToCheck < length; ++nextCharIndexToCheck) { |
136 | UChar c = languageTag[nextCharIndexToCheck]; |
137 | if (isASCIIAlphanumeric(c) || c == '-') |
138 | continue; |
139 | return false; |
140 | } |
141 | return true; |
142 | } |
143 | |
144 | void TrackBase::setLanguage(const AtomicString& language) |
145 | { |
146 | if (!language.isEmpty() && !isValidBCP47LanguageTag(language)) { |
147 | String message; |
148 | if (language.contains((UChar)'\0')) |
149 | message = "The language contains a null character and is not a valid BCP 47 language tag."_s ; |
150 | else { |
151 | StringBuilder stringBuilder; |
152 | stringBuilder.appendLiteral("The language '" ); |
153 | stringBuilder.append(language); |
154 | stringBuilder.appendLiteral("' is not a valid BCP 47 language tag." ); |
155 | message = stringBuilder.toString(); |
156 | } |
157 | if (auto element = this->element()) |
158 | element->document().addConsoleMessage(MessageSource::Rendering, MessageLevel::Warning, message); |
159 | } else |
160 | m_validBCP47Language = language; |
161 | |
162 | m_language = language; |
163 | } |
164 | |
165 | AtomicString TrackBase::validBCP47Language() const |
166 | { |
167 | return m_validBCP47Language; |
168 | } |
169 | |
170 | #if !RELEASE_LOG_DISABLED |
171 | WTFLogChannel& TrackBase::logChannel() const |
172 | { |
173 | return LogMedia; |
174 | } |
175 | #endif |
176 | |
177 | MediaTrackBase::MediaTrackBase(Type type, const AtomicString& id, const AtomicString& label, const AtomicString& language) |
178 | : TrackBase(type, id, label, language) |
179 | { |
180 | } |
181 | |
182 | void MediaTrackBase::setKind(const AtomicString& kind) |
183 | { |
184 | setKindInternal(kind); |
185 | } |
186 | |
187 | void MediaTrackBase::setKindInternal(const AtomicString& kind) |
188 | { |
189 | if (isValidKind(kind)) |
190 | m_kind = kind; |
191 | else |
192 | m_kind = emptyAtom(); |
193 | } |
194 | |
195 | } // namespace WebCore |
196 | |
197 | #endif |
198 | |