bc95111e1ef6c7dfd0ff2335c13eadbd2a234eb1
[WebKit-https.git] / Source / WebCore / html / track / TrackBase.cpp
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 "Language.h"
30 #include <wtf/text/StringBuilder.h>
31
32 #if ENABLE(VIDEO_TRACK)
33
34 #include "HTMLMediaElement.h"
35
36 namespace WebCore {
37
38 static int s_uniqueId = 0;
39
40 TrackBase::TrackBase(Type type, const AtomicString& id, const AtomicString& label, const AtomicString& language)
41     : m_uniqueId(++s_uniqueId)
42     , m_id(id)
43     , m_label(label)
44     , m_language(language)
45     , m_validBCP47Language(language)
46 {
47     ASSERT(type != BaseTrack);
48     m_type = type;
49 }
50
51 TrackBase::~TrackBase()
52 {
53 }
54
55 Element* TrackBase::element()
56 {
57     return m_mediaElement;
58 }
59
60 // See: https://tools.ietf.org/html/bcp47#section-2.1
61 static bool isValidBCP47LanguageTag(const String& languageTag)
62 {
63     auto const length = languageTag.length();
64
65     // Max length picked as double the longest example tag in spec which is 49 characters:
66     // https://tools.ietf.org/html/bcp47#section-4.4.2
67     if (length < 2 || length > 100)
68         return false;
69
70     UChar firstChar = languageTag[0];
71
72     if (!isASCIIAlpha(firstChar))
73         return false;
74
75     UChar secondChar = languageTag[1];
76
77     if (length == 2)
78         return isASCIIAlpha(secondChar);
79
80     bool grandFatheredIrregularOrPrivateUse = (firstChar == 'i' || firstChar == 'x') && secondChar == '-';
81     unsigned nextCharIndexToCheck;
82
83     if (!grandFatheredIrregularOrPrivateUse) {
84         if (!isASCIIAlpha(secondChar))
85             return false;
86
87         if (length == 3)
88             return isASCIIAlpha(languageTag[2]);
89
90         if (isASCIIAlpha(languageTag[2])) {
91             if (languageTag[3] == '-')
92                 nextCharIndexToCheck = 4;
93             else
94                 return false;
95         } else if (languageTag[2] == '-')
96             nextCharIndexToCheck = 3;
97         else
98             return false;
99     } else
100         nextCharIndexToCheck = 2;
101
102     for (; nextCharIndexToCheck < length; ++nextCharIndexToCheck) {
103         UChar c = languageTag[nextCharIndexToCheck];
104         if (isASCIIAlphanumeric(c) || c == '-')
105             continue;
106         return false;
107     }
108     return true;
109 }
110     
111 void TrackBase::setLanguage(const AtomicString& language)
112 {
113     if (!language.isEmpty() && !isValidBCP47LanguageTag(language)) {
114         String message;
115         if (language.contains((UChar)'\0'))
116             message = WTF::ASCIILiteral("The language contains a null character and is not a valid BCP 47 language tag.");
117         else {
118             StringBuilder stringBuilder;
119             stringBuilder.appendLiteral("The language '");
120             stringBuilder.append(language);
121             stringBuilder.appendLiteral("' is not a valid BCP 47 language tag.");
122             message = stringBuilder.toString();
123         }
124         if (auto element = this->element())
125             element->document().addConsoleMessage(MessageSource::Rendering, MessageLevel::Warning, message);
126     } else
127         m_validBCP47Language = language;
128     
129     m_language = language;
130 }
131
132 AtomicString TrackBase::validBCP47Language() const
133 {
134     return m_validBCP47Language;
135 }
136
137 MediaTrackBase::MediaTrackBase(Type type, const AtomicString& id, const AtomicString& label, const AtomicString& language)
138     : TrackBase(type, id, label, language)
139 {
140 }
141
142 void MediaTrackBase::setKind(const AtomicString& kind)
143 {
144     setKindInternal(kind);
145 }
146
147 void MediaTrackBase::setKindInternal(const AtomicString& kind)
148 {
149     if (isValidKind(kind))
150         m_kind = kind;
151     else
152         m_kind = emptyAtom;
153 }
154
155 } // namespace WebCore
156
157 #endif