145f4a96d31804ce6f45ba53253e35ae26c2eda8
[WebKit-https.git] / Source / WebCore / html / track / TextTrackCueGeneric.cpp
1 /*
2  * Copyright (C) 2013, 2014 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
28 #if ENABLE(VIDEO_TRACK)
29
30 #include "TextTrackCueGeneric.h"
31
32 #include "CSSPropertyNames.h"
33 #include "CSSStyleDeclaration.h"
34 #include "CSSValueKeywords.h"
35 #include "HTMLNames.h"
36 #include "HTMLSpanElement.h"
37 #include "InbandTextTrackPrivateClient.h"
38 #include "Logging.h"
39 #include "RenderObject.h"
40 #include "ScriptExecutionContext.h"
41 #include "StyleProperties.h"
42 #include "TextTrackCue.h"
43 #include <wtf/MathExtras.h>
44
45 namespace WebCore {
46
47 // This default value must be the same as the one specified in mediaControlsApple.css for -webkit-media-controls-closed-captions-container
48 const static int DEFAULTCAPTIONFONTSIZE = 10;
49
50 class TextTrackCueGenericBoxElement final : public VTTCueBox {
51 public:
52     static Ref<TextTrackCueGenericBoxElement> create(Document& document, TextTrackCueGeneric& cue)
53     {
54         return adoptRef(*new TextTrackCueGenericBoxElement(document, cue));
55     }
56     
57     void applyCSSProperties(const IntSize&) override;
58     
59 private:
60     TextTrackCueGenericBoxElement(Document&, VTTCue&);
61 };
62
63 TextTrackCueGenericBoxElement::TextTrackCueGenericBoxElement(Document& document, VTTCue& cue)
64     : VTTCueBox(document, cue)
65 {
66 }
67
68 void TextTrackCueGenericBoxElement::applyCSSProperties(const IntSize& videoSize)
69 {
70     setInlineStyleProperty(CSSPropertyPosition, CSSValueAbsolute);
71     setInlineStyleProperty(CSSPropertyUnicodeBidi, CSSValueWebkitPlaintext);
72     
73     TextTrackCueGeneric* cue = static_cast<TextTrackCueGeneric*>(getCue());
74     Ref<HTMLSpanElement> cueElement = cue->element();
75
76     CSSValueID alignment = cue->getCSSAlignment();
77     float size = static_cast<float>(cue->getCSSSize());
78     if (cue->useDefaultPosition()) {
79         setInlineStyleProperty(CSSPropertyBottom, 0, CSSPrimitiveValue::CSS_PX);
80         setInlineStyleProperty(CSSPropertyMarginBottom, 1.0, CSSPrimitiveValue::CSS_PERCENTAGE);
81     } else {
82         setInlineStyleProperty(CSSPropertyLeft, static_cast<float>(cue->position()), CSSPrimitiveValue::CSS_PERCENTAGE);
83         setInlineStyleProperty(CSSPropertyTop, static_cast<float>(cue->line()), CSSPrimitiveValue::CSS_PERCENTAGE);
84
85         double authorFontSize = videoSize.height() * cue->baseFontSizeRelativeToVideoHeight() / 100.0;
86         if (!authorFontSize)
87             authorFontSize = DEFAULTCAPTIONFONTSIZE;
88
89         if (cue->fontSizeMultiplier())
90             authorFontSize *= cue->fontSizeMultiplier() / 100;
91
92         double multiplier = m_fontSizeFromCaptionUserPrefs / authorFontSize;
93         double newCueSize = std::min(size * multiplier, 100.0);
94         if (cue->getWritingDirection() == VTTCue::Horizontal) {
95             setInlineStyleProperty(CSSPropertyWidth, newCueSize, CSSPrimitiveValue::CSS_PERCENTAGE);
96             if ((alignment == CSSValueMiddle || alignment == CSSValueCenter) && multiplier != 1.0)
97                 setInlineStyleProperty(CSSPropertyLeft, static_cast<double>(cue->position() - (newCueSize - m_cue.getCSSSize()) / 2), CSSPrimitiveValue::CSS_PERCENTAGE);
98         } else {
99             setInlineStyleProperty(CSSPropertyHeight, newCueSize,  CSSPrimitiveValue::CSS_PERCENTAGE);
100             if ((alignment == CSSValueMiddle || alignment == CSSValueCenter) && multiplier != 1.0)
101                 setInlineStyleProperty(CSSPropertyTop, static_cast<double>(cue->line() - (newCueSize - m_cue.getCSSSize()) / 2), CSSPrimitiveValue::CSS_PERCENTAGE);
102         }
103     }
104
105     double textPosition = m_cue.position();
106     double maxSize = 100.0;
107     
108     if (alignment == CSSValueEnd || alignment == CSSValueRight)
109         maxSize = textPosition;
110     else if (alignment == CSSValueStart || alignment == CSSValueLeft)
111         maxSize = 100.0 - textPosition;
112
113     if (cue->getWritingDirection() == VTTCue::Horizontal) {
114         setInlineStyleProperty(CSSPropertyMinWidth, "-webkit-min-content");
115         setInlineStyleProperty(CSSPropertyMaxWidth, maxSize, CSSPrimitiveValue::CSS_PERCENTAGE);
116     } else {
117         setInlineStyleProperty(CSSPropertyMinHeight, "-webkit-min-content");
118         setInlineStyleProperty(CSSPropertyMaxHeight, maxSize, CSSPrimitiveValue::CSS_PERCENTAGE);
119     }
120
121     if (cue->foregroundColor().isValid())
122         cueElement->setInlineStyleProperty(CSSPropertyColor, cue->foregroundColor().serialized());
123     if (cue->highlightColor().isValid())
124         cueElement->setInlineStyleProperty(CSSPropertyBackgroundColor, cue->highlightColor().serialized());
125
126     if (cue->getWritingDirection() == VTTCue::Horizontal)
127         setInlineStyleProperty(CSSPropertyHeight, CSSValueAuto);
128     else
129         setInlineStyleProperty(CSSPropertyWidth, CSSValueAuto);
130
131     if (cue->baseFontSizeRelativeToVideoHeight())
132         cue->setFontSize(cue->baseFontSizeRelativeToVideoHeight(), videoSize, false);
133
134     if (cue->getAlignment() == VTTCue::Middle)
135         setInlineStyleProperty(CSSPropertyTextAlign, CSSValueCenter);
136     else if (cue->getAlignment() == VTTCue::End)
137         setInlineStyleProperty(CSSPropertyTextAlign, CSSValueEnd);
138     else
139         setInlineStyleProperty(CSSPropertyTextAlign, CSSValueStart);
140
141     if (cue->backgroundColor().isValid())
142         setInlineStyleProperty(CSSPropertyBackgroundColor, cue->backgroundColor().serialized());
143     setInlineStyleProperty(CSSPropertyWebkitWritingMode, cue->getCSSWritingMode(), false);
144     setInlineStyleProperty(CSSPropertyWhiteSpace, CSSValuePreWrap);
145 }
146
147 TextTrackCueGeneric::TextTrackCueGeneric(ScriptExecutionContext& context, const MediaTime& start, const MediaTime& end, const String& content)
148     : VTTCue(context, start, end, content)
149     , m_baseFontSizeRelativeToVideoHeight(0)
150     , m_fontSizeMultiplier(0)
151 {
152 }
153
154 Ref<VTTCueBox> TextTrackCueGeneric::createDisplayTree()
155 {
156     return TextTrackCueGenericBoxElement::create(ownerDocument(), *this);
157 }
158
159 ExceptionOr<void> TextTrackCueGeneric::setLine(double line)
160 {
161     auto result = VTTCue::setLine(line);
162     if (!result.hasException())
163         m_useDefaultPosition = false;
164     return result;
165 }
166
167 ExceptionOr<void> TextTrackCueGeneric::setPosition(double position)
168 {
169     auto result = VTTCue::setPosition(position);
170     if (!result.hasException())
171         m_useDefaultPosition = false;
172     return result;
173 }
174
175 void TextTrackCueGeneric::setFontSize(int fontSize, const IntSize& videoSize, bool important)
176 {
177     if (!hasDisplayTree() || !fontSize)
178         return;
179     
180     if (important || !baseFontSizeRelativeToVideoHeight()) {
181         VTTCue::setFontSize(fontSize, videoSize, important);
182         return;
183     }
184
185     double size = videoSize.height() * baseFontSizeRelativeToVideoHeight() / 100;
186     if (fontSizeMultiplier())
187         size *= fontSizeMultiplier() / 100;
188     displayTreeInternal().setInlineStyleProperty(CSSPropertyFontSize, lround(size), CSSPrimitiveValue::CSS_PX);
189
190     LOG(Media, "TextTrackCueGeneric::setFontSize - setting cue font size to %li", lround(size));
191 }
192
193 bool TextTrackCueGeneric::cueContentsMatch(const TextTrackCue& cue) const
194 {
195     // Do call the parent class cueContentsMatch here, because we want to confirm
196     // the content of the two cues are identical (even though the types are not the same).
197     if (!VTTCue::cueContentsMatch(cue))
198         return false;
199     
200     const TextTrackCueGeneric* other = static_cast<const TextTrackCueGeneric*>(&cue);
201
202     if (m_baseFontSizeRelativeToVideoHeight != other->baseFontSizeRelativeToVideoHeight())
203         return false;
204     if (m_fontSizeMultiplier != other->fontSizeMultiplier())
205         return false;
206     if (m_fontName != other->fontName())
207         return false;
208     if (m_foregroundColor != other->foregroundColor())
209         return false;
210     if (m_backgroundColor != other->backgroundColor())
211         return false;
212
213     return true;
214 }
215
216 bool TextTrackCueGeneric::isEqual(const TextTrackCue& cue, TextTrackCue::CueMatchRules match) const
217 {
218     // Do not call the parent class isEqual here, because we are not cueType() == VTTCue,
219     // and will fail that equality test.
220     if (!TextTrackCue::isEqual(cue, match))
221         return false;
222
223     if (cue.cueType() != TextTrackCue::Generic)
224         return false;
225
226     return cueContentsMatch(cue);
227 }
228
229     
230 bool TextTrackCueGeneric::doesExtendCue(const TextTrackCue& cue) const
231 {
232     if (!cueContentsMatch(cue))
233         return false;
234     
235     return VTTCue::doesExtendCue(cue);
236 }
237
238 bool TextTrackCueGeneric::isOrderedBefore(const TextTrackCue* that) const
239 {
240     if (VTTCue::isOrderedBefore(that))
241         return true;
242
243     if (that->cueType() == Generic && startTime() == that->startTime() && endTime() == that->endTime()) {
244         // Further order generic cues by their calculated line value.
245         std::pair<double, double> thisPosition = getPositionCoordinates();
246         std::pair<double, double> thatPosition = toVTTCue(that)->getPositionCoordinates();
247         return thisPosition.second > thatPosition.second || (thisPosition.second == thatPosition.second && thisPosition.first < thatPosition.first);
248     }
249
250     return false;
251 }
252
253 bool TextTrackCueGeneric::isPositionedAbove(const TextTrackCue* that) const
254 {
255     if (that->cueType() == Generic && startTime() == that->startTime() && endTime() == that->endTime()) {
256         // Further order generic cues by their calculated line value.
257         std::pair<double, double> thisPosition = getPositionCoordinates();
258         std::pair<double, double> thatPosition = toVTTCue(that)->getPositionCoordinates();
259         return thisPosition.second > thatPosition.second || (thisPosition.second == thatPosition.second && thisPosition.first < thatPosition.first);
260     }
261     
262     if (that->cueType() == Generic)
263         return startTime() > that->startTime();
264     
265     return VTTCue::isOrderedBefore(that);
266 }
267     
268 } // namespace WebCore
269
270 #endif