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 45namespace WebCore { 46 47// This default value must be the same as the one specified in mediaControlsApple.css for -webkit-media-controls-closed-captions-container 48const static int DEFAULTCAPTIONFONTSIZE = 10; 49 50class TextTrackCueGenericBoxElement final : public VTTCueBox { 51public: 52 static PassRefPtr<TextTrackCueGenericBoxElement> create(Document& document, TextTrackCueGeneric& cue) 53 { 54 return adoptRef(new TextTrackCueGenericBoxElement(document, cue)); 55 } 56 57 virtual void applyCSSProperties(const IntSize&) override; 58 59private: 60 TextTrackCueGenericBoxElement(Document&, VTTCue&); 61}; 62 63TextTrackCueGenericBoxElement::TextTrackCueGenericBoxElement(Document& document, VTTCue& cue) 64 : VTTCueBox(document, cue) 65{ 66} 67 68void TextTrackCueGenericBoxElement::applyCSSProperties(const IntSize& videoSize) 69{ 70 setInlineStyleProperty(CSSPropertyPosition, CSSValueAbsolute); 71 setInlineStyleProperty(CSSPropertyUnicodeBidi, CSSValueWebkitPlaintext); 72 73 TextTrackCueGeneric* cue = static_cast<TextTrackCueGeneric*>(getCue()); 74 RefPtr<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 147TextTrackCueGeneric::TextTrackCueGeneric(ScriptExecutionContext& context, double start, double end, const String& content) 148 : VTTCue(context, start, end, content) 149 , m_baseFontSizeRelativeToVideoHeight(0) 150 , m_fontSizeMultiplier(0) 151 , m_defaultPosition(true) 152{ 153} 154 155PassRefPtr<VTTCueBox> TextTrackCueGeneric::createDisplayTree() 156{ 157 return TextTrackCueGenericBoxElement::create(ownerDocument(), *this); 158} 159 160void TextTrackCueGeneric::setLine(double line, ExceptionCode& ec) 161{ 162 m_defaultPosition = false; 163 VTTCue::setLine(line, ec); 164} 165 166void TextTrackCueGeneric::setPosition(double position, ExceptionCode& ec) 167{ 168 m_defaultPosition = false; 169 VTTCue::setPosition(position, ec); 170} 171 172void TextTrackCueGeneric::setFontSize(int fontSize, const IntSize& videoSize, bool important) 173{ 174 if (!hasDisplayTree() || !fontSize) 175 return; 176 177 if (important || !baseFontSizeRelativeToVideoHeight()) { 178 VTTCue::setFontSize(fontSize, videoSize, important); 179 return; 180 } 181 182 double size = videoSize.height() * baseFontSizeRelativeToVideoHeight() / 100; 183 if (fontSizeMultiplier()) 184 size *= fontSizeMultiplier() / 100; 185 displayTreeInternal()->setInlineStyleProperty(CSSPropertyFontSize, lround(size), CSSPrimitiveValue::CSS_PX); 186 187 LOG(Media, "TextTrackCueGeneric::setFontSize - setting cue font size to %li", lround(size)); 188} 189 190bool TextTrackCueGeneric::cueContentsMatch(const TextTrackCue& cue) const 191{ 192 // Do call the parent class cueContentsMatch here, because we want to confirm 193 // the content of the two cues are identical (even though the types are not the same). 194 if (!VTTCue::cueContentsMatch(cue)) 195 return false; 196 197 const TextTrackCueGeneric* other = static_cast<const TextTrackCueGeneric*>(&cue); 198 199 if (m_baseFontSizeRelativeToVideoHeight != other->baseFontSizeRelativeToVideoHeight()) 200 return false; 201 if (m_fontSizeMultiplier != other->fontSizeMultiplier()) 202 return false; 203 if (m_fontName != other->fontName()) 204 return false; 205 if (m_foregroundColor != other->foregroundColor()) 206 return false; 207 if (m_backgroundColor != other->backgroundColor()) 208 return false; 209 210 return true; 211} 212 213bool TextTrackCueGeneric::isEqual(const TextTrackCue& cue, TextTrackCue::CueMatchRules match) const 214{ 215 // Do not call the parent class isEqual here, because we are not cueType() == VTTCue, 216 // and will fail that equality test. 217 if (!TextTrackCue::isEqual(cue, match)) 218 return false; 219 220 if (cue.cueType() != TextTrackCue::Generic) 221 return false; 222 223 return cueContentsMatch(cue); 224} 225 226 227bool TextTrackCueGeneric::doesExtendCue(const TextTrackCue& cue) const 228{ 229 if (!cueContentsMatch(cue)) 230 return false; 231 232 return VTTCue::doesExtendCue(cue); 233} 234 235bool TextTrackCueGeneric::isOrderedBefore(const TextTrackCue* that) const 236{ 237 if (VTTCue::isOrderedBefore(that)) 238 return true; 239 240 if (that->cueType() == Generic && startTime() == that->startTime() && endTime() == that->endTime()) { 241 // Further order generic cues by their calculated line value. 242 std::pair<double, double> thisPosition = getPositionCoordinates(); 243 std::pair<double, double> thatPosition = toVTTCue(that)->getPositionCoordinates(); 244 return thisPosition.second > thatPosition.second || (thisPosition.second == thatPosition.second && thisPosition.first < thatPosition.first); 245 } 246 247 return false; 248} 249 250bool TextTrackCueGeneric::isPositionedAbove(const TextTrackCue* that) const 251{ 252 if (that->cueType() == Generic && startTime() == that->startTime() && endTime() == that->endTime()) { 253 // Further order generic cues by their calculated line value. 254 std::pair<double, double> thisPosition = getPositionCoordinates(); 255 std::pair<double, double> thatPosition = toVTTCue(that)->getPositionCoordinates(); 256 return thisPosition.second > thatPosition.second || (thisPosition.second == thatPosition.second && thisPosition.first < thatPosition.first); 257 } 258 259 if (that->cueType() == Generic) 260 return startTime() > that->startTime(); 261 262 return VTTCue::isOrderedBefore(that); 263} 264 265} // namespace WebCore 266 267#endif 268