1 /* 2 * Copyright (C) 2007, 2009, 2010 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 COMPUTER, 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 COMPUTER, 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 #include "TimeRanges.h" 29 30 #include <math.h> 31 32 using namespace WebCore; 33 34 TimeRanges::TimeRanges(float start, float end) 35 { 36 add(start, end); 37 } 38 39 PassRefPtr<TimeRanges> TimeRanges::copy() 40 { 41 RefPtr<TimeRanges> newSession = TimeRanges::create(); 42 43 unsigned size = m_ranges.size(); 44 for (unsigned i = 0; i < size; i++) 45 newSession->add(m_ranges[i].m_start, m_ranges[i].m_end); 46 47 return newSession.release(); 48 } 49 50 float TimeRanges::start(unsigned index, ExceptionCode& ec) const 51 { 52 if (index >= length()) { 53 ec = INDEX_SIZE_ERR; 54 return 0; 55 } 56 return m_ranges[index].m_start; 57 } 58 59 float TimeRanges::end(unsigned index, ExceptionCode& ec) const 60 { 61 if (index >= length()) { 62 ec = INDEX_SIZE_ERR; 63 return 0; 64 } 65 return m_ranges[index].m_end; 66 } 67 68 void TimeRanges::add(float start, float end) 69 { 70 ASSERT(start <= end); 71 unsigned int overlappingArcIndex; 72 Range addedRange(start, end); 73 74 // For each present range check if we need to: 75 // - merge with the added range, in case we are overlapping or contiguous 76 // - Need to insert in place, we we are completely, not overlapping and not contiguous 77 // in between two ranges. 78 // 79 // TODO: Given that we assume that ranges are correctly ordered, this could be optimized. 80 81 for (overlappingArcIndex = 0; overlappingArcIndex < m_ranges.size(); overlappingArcIndex++) { 82 if (addedRange.isOverlappingRange(m_ranges[overlappingArcIndex]) 83 || addedRange.isContiguousWithRange(m_ranges[overlappingArcIndex])) { 84 // We need to merge the addedRange and that range. 85 addedRange = addedRange.unionWithOverlappingOrContiguousRange(m_ranges[overlappingArcIndex]); 86 m_ranges.remove(overlappingArcIndex); 87 overlappingArcIndex--; 88 } else { 89 // Check the case for which there is no more to do 90 if (!overlappingArcIndex) { 91 if (addedRange.isBeforeRange(m_ranges[0])) { 92 // First index, and we are completely before that range (and not contiguous, nor overlapping). 93 // We just need to be inserted here. 94 break; 95 } 96 } else { 97 if (m_ranges[overlappingArcIndex - 1].isBeforeRange(addedRange) 98 && addedRange.isBeforeRange(m_ranges[overlappingArcIndex])) { 99 // We are exactly after the current previous range, and before the current range, while 100 // not overlapping with none of them. Insert here. 101 break; 102 } 103 } 104 } 105 } 106 107 // Now that we are sure we don't overlap with any range, just add it. 108 m_ranges.insert(overlappingArcIndex, addedRange); 109 } 110 111 bool TimeRanges::contain(float time) const 112 { 113 ExceptionCode unused; 114 for (unsigned n = 0; n < length(); n++) { 115 if (time >= start(n, unused) && time <= end(n, unused)) 116 return true; 117 } 118 return false; 119 } 120 121 float TimeRanges::nearest(float time) const 122 { 123 ExceptionCode unused; 124 float closest = 0; 125 unsigned count = length(); 126 for (unsigned ndx = 0; ndx < count; ndx++) { 127 float startTime = start(ndx, unused); 128 float endTime = end(ndx, unused); 129 if (time >= startTime && time <= endTime) 130 return time; 131 if (fabs(startTime - time) < closest) 132 closest = fabsf(startTime - time); 133 else if (fabs(endTime - time) < closest) 134 closest = fabsf(endTime - time); 135 } 136 return closest; 137 } 138