1/* 2 * Copyright (C) 2013 Google 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 are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include "config.h" 32 33#if ENABLE(VIDEO_TRACK) && ENABLE(WEBVTT_REGIONS) 34 35#include "TextTrackRegion.h" 36 37#include "ExceptionCodePlaceholder.h" 38#include "Logging.h" 39#include "WebVTTParser.h" 40#include <wtf/MathExtras.h> 41#include <wtf/text/StringBuilder.h> 42 43namespace WebCore { 44 45// The region occupies by default 100% of the width of the video viewport. 46static const float defaultWidth = 100; 47 48// The region has, by default, 3 lines of text. 49static const long defaultHeightInLines = 3; 50 51// The region and viewport are anchored in the bottom left corner. 52static const float defaultAnchorPointX = 0; 53static const float defaultAnchorPointY = 100; 54 55// The region doesn't have scrolling text, by default. 56static const bool defaultScroll = false; 57 58TextTrackRegion::TextTrackRegion() 59 : m_id(emptyString()) 60 , m_width(defaultWidth) 61 , m_heightInLines(defaultHeightInLines) 62 , m_regionAnchor(FloatPoint(defaultAnchorPointX, defaultAnchorPointY)) 63 , m_viewportAnchor(FloatPoint(defaultAnchorPointX, defaultAnchorPointY)) 64 , m_scroll(defaultScroll) 65 , m_track(0) 66{ 67} 68 69TextTrackRegion::~TextTrackRegion() 70{ 71} 72 73void TextTrackRegion::setTrack(TextTrack* track) 74{ 75 m_track = track; 76} 77 78void TextTrackRegion::setId(const String& id) 79{ 80 m_id = id; 81} 82 83void TextTrackRegion::setWidth(double value, ExceptionCode& ec) 84{ 85 if (std::isinf(value) || std::isnan(value)) { 86 ec = TypeError; 87 return; 88 } 89 90 if (value < 0 || value > 100) { 91 ec = INDEX_SIZE_ERR; 92 return; 93 } 94 95 m_width = value; 96} 97 98void TextTrackRegion::setHeight(long value, ExceptionCode& ec) 99{ 100 if (value < 0) { 101 ec = INDEX_SIZE_ERR; 102 return; 103 } 104 105 m_heightInLines = value; 106} 107 108void TextTrackRegion::setRegionAnchorX(double value, ExceptionCode& ec) 109{ 110 if (std::isinf(value) || std::isnan(value)) { 111 ec = TypeError; 112 return; 113 } 114 115 if (value < 0 || value > 100) { 116 ec = INDEX_SIZE_ERR; 117 return; 118 } 119 120 m_regionAnchor.setX(value); 121} 122 123void TextTrackRegion::setRegionAnchorY(double value, ExceptionCode& ec) 124{ 125 if (std::isinf(value) || std::isnan(value)) { 126 ec = TypeError; 127 return; 128 } 129 130 if (value < 0 || value > 100) { 131 ec = INDEX_SIZE_ERR; 132 return; 133 } 134 135 m_regionAnchor.setY(value); 136} 137 138void TextTrackRegion::setViewportAnchorX(double value, ExceptionCode& ec) 139{ 140 if (std::isinf(value) || std::isnan(value)) { 141 ec = TypeError; 142 return; 143 } 144 145 if (value < 0 || value > 100) { 146 ec = INDEX_SIZE_ERR; 147 return; 148 } 149 150 m_viewportAnchor.setX(value); 151} 152 153void TextTrackRegion::setViewportAnchorY(double value, ExceptionCode& ec) 154{ 155 if (std::isinf(value) || std::isnan(value)) { 156 ec = TypeError; 157 return; 158 } 159 160 if (value < 0 || value > 100) { 161 ec = INDEX_SIZE_ERR; 162 return; 163 } 164 165 m_viewportAnchor.setY(value); 166} 167 168const AtomicString TextTrackRegion::scroll() const 169{ 170 DEFINE_STATIC_LOCAL(const AtomicString, upScrollValueKeyword, ("up", AtomicString::ConstructFromLiteral)); 171 172 if (m_scroll) 173 return upScrollValueKeyword; 174 175 return ""; 176} 177 178void TextTrackRegion::setScroll(const AtomicString& value, ExceptionCode& ec) 179{ 180 DEFINE_STATIC_LOCAL(const AtomicString, upScrollValueKeyword, ("up", AtomicString::ConstructFromLiteral)); 181 182 if (value != emptyString() && value != upScrollValueKeyword) { 183 ec = SYNTAX_ERR; 184 return; 185 } 186 187 m_scroll = value == upScrollValueKeyword; 188} 189 190void TextTrackRegion::updateParametersFromRegion(TextTrackRegion* region) 191{ 192 m_heightInLines = region->height(); 193 m_width = region->width(); 194 195 m_regionAnchor = FloatPoint(region->regionAnchorX(), region->regionAnchorY()); 196 m_viewportAnchor = FloatPoint(region->viewportAnchorX(), region->viewportAnchorY()); 197 198 setScroll(region->scroll(), ASSERT_NO_EXCEPTION); 199} 200 201void TextTrackRegion::setRegionSettings(const String& input) 202{ 203 m_settings = input; 204 unsigned position = 0; 205 206 while (position < input.length()) { 207 while (position < input.length() && WebVTTParser::isValidSettingDelimiter(input[position])) 208 position++; 209 210 if (position >= input.length()) 211 break; 212 213 parseSetting(input, &position); 214 } 215} 216 217TextTrackRegion::RegionSetting TextTrackRegion::getSettingFromString(const String& setting) 218{ 219 DEFINE_STATIC_LOCAL(const AtomicString, idKeyword, ("id", AtomicString::ConstructFromLiteral)); 220 DEFINE_STATIC_LOCAL(const AtomicString, heightKeyword, ("height", AtomicString::ConstructFromLiteral)); 221 DEFINE_STATIC_LOCAL(const AtomicString, widthKeyword, ("width", AtomicString::ConstructFromLiteral)); 222 DEFINE_STATIC_LOCAL(const AtomicString, regionAnchorKeyword, ("regionanchor", AtomicString::ConstructFromLiteral)); 223 DEFINE_STATIC_LOCAL(const AtomicString, viewportAnchorKeyword, ("viewportanchor", AtomicString::ConstructFromLiteral)); 224 DEFINE_STATIC_LOCAL(const AtomicString, scrollKeyword, ("scroll", AtomicString::ConstructFromLiteral)); 225 226 if (setting == idKeyword) 227 return Id; 228 if (setting == heightKeyword) 229 return Height; 230 if (setting == widthKeyword) 231 return Width; 232 if (setting == viewportAnchorKeyword) 233 return ViewportAnchor; 234 if (setting == regionAnchorKeyword) 235 return RegionAnchor; 236 if (setting == scrollKeyword) 237 return Scroll; 238 239 return None; 240} 241 242void TextTrackRegion::parseSettingValue(RegionSetting setting, const String& value) 243{ 244 DEFINE_STATIC_LOCAL(const AtomicString, scrollUpValueKeyword, ("up", AtomicString::ConstructFromLiteral)); 245 246 bool isValidSetting; 247 String numberAsString; 248 int number; 249 unsigned position; 250 FloatPoint anchorPosition; 251 252 switch (setting) { 253 case Id: 254 if (value.find("-->") == notFound) 255 m_id = value; 256 break; 257 case Width: 258 number = WebVTTParser::parseFloatPercentageValue(value, isValidSetting); 259 if (isValidSetting) 260 m_width = number; 261 else 262 LOG(Media, "TextTrackRegion::parseSettingValue, invalid Width"); 263 break; 264 case Height: 265 position = 0; 266 267 numberAsString = WebVTTParser::collectDigits(value, &position); 268 number = value.toInt(&isValidSetting); 269 270 if (isValidSetting && number >= 0) 271 m_heightInLines = number; 272 else 273 LOG(Media, "TextTrackRegion::parseSettingValue, invalid Height"); 274 break; 275 case RegionAnchor: 276 anchorPosition = WebVTTParser::parseFloatPercentageValuePair(value, ',', isValidSetting); 277 if (isValidSetting) 278 m_regionAnchor = anchorPosition; 279 else 280 LOG(Media, "TextTrackRegion::parseSettingValue, invalid RegionAnchor"); 281 break; 282 case ViewportAnchor: 283 anchorPosition = WebVTTParser::parseFloatPercentageValuePair(value, ',', isValidSetting); 284 if (isValidSetting) 285 m_viewportAnchor = anchorPosition; 286 else 287 LOG(Media, "TextTrackRegion::parseSettingValue, invalid ViewportAnchor"); 288 break; 289 case Scroll: 290 if (value == scrollUpValueKeyword) 291 m_scroll = true; 292 else 293 LOG(Media, "TextTrackRegion::parseSettingValue, invalid Scroll"); 294 break; 295 case None: 296 break; 297 } 298} 299 300void TextTrackRegion::parseSetting(const String& input, unsigned* position) 301{ 302 String setting = WebVTTParser::collectWord(input, position); 303 304 size_t equalOffset = setting.find('=', 1); 305 if (equalOffset == notFound || !equalOffset || equalOffset == setting.length() - 1) 306 return; 307 308 RegionSetting name = getSettingFromString(setting.substring(0, equalOffset)); 309 String value = setting.substring(equalOffset + 1, setting.length() - 1); 310 311 parseSettingValue(name, value); 312} 313 314} // namespace WebCore 315 316#endif 317