mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
* Use 2024 style edition Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Reformat all code Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> --------- Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
173 lines
5.2 KiB
Rust
173 lines
5.2 KiB
Rust
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
|
|
use std::fmt;
|
|
|
|
use dom_struct::dom_struct;
|
|
|
|
use crate::dom::bindings::codegen::Bindings::TimeRangesBinding::TimeRangesMethods;
|
|
use crate::dom::bindings::error::{Error, Fallible};
|
|
use crate::dom::bindings::num::Finite;
|
|
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
|
|
use crate::dom::bindings::root::DomRoot;
|
|
use crate::dom::window::Window;
|
|
use crate::script_runtime::CanGc;
|
|
|
|
#[derive(Clone, JSTraceable, MallocSizeOf)]
|
|
struct TimeRange {
|
|
start: f64,
|
|
end: f64,
|
|
}
|
|
|
|
impl TimeRange {
|
|
pub(crate) fn union(&mut self, other: &TimeRange) {
|
|
self.start = f64::min(self.start, other.start);
|
|
self.end = f64::max(self.end, other.end);
|
|
}
|
|
|
|
fn contains(&self, time: f64) -> bool {
|
|
self.start <= time && time < self.end
|
|
}
|
|
|
|
fn is_overlapping(&self, other: &TimeRange) -> bool {
|
|
// This also covers the case where `self` is entirely contained within `other`,
|
|
// for example: `self` = [2,3) and `other` = [1,4).
|
|
self.contains(other.start) || self.contains(other.end) || other.contains(self.start)
|
|
}
|
|
|
|
fn is_contiguous(&self, other: &TimeRange) -> bool {
|
|
other.start == self.end || other.end == self.start
|
|
}
|
|
|
|
pub(crate) fn is_before(&self, other: &TimeRange) -> bool {
|
|
other.start >= self.end
|
|
}
|
|
}
|
|
|
|
impl fmt::Debug for TimeRange {
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
|
write!(fmt, "[{},{})", self.start, self.end)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum TimeRangesError {
|
|
EndOlderThanStart,
|
|
OutOfRange,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Default, JSTraceable, MallocSizeOf)]
|
|
pub struct TimeRangesContainer {
|
|
ranges: Vec<TimeRange>,
|
|
}
|
|
|
|
impl TimeRangesContainer {
|
|
#[allow(clippy::len_without_is_empty)]
|
|
pub fn len(&self) -> u32 {
|
|
self.ranges.len() as u32
|
|
}
|
|
|
|
pub(crate) fn is_empty(&self) -> bool {
|
|
self.ranges.is_empty()
|
|
}
|
|
|
|
pub fn start(&self, index: u32) -> Result<f64, TimeRangesError> {
|
|
self.ranges
|
|
.get(index as usize)
|
|
.map(|r| r.start)
|
|
.ok_or(TimeRangesError::OutOfRange)
|
|
}
|
|
|
|
pub fn end(&self, index: u32) -> Result<f64, TimeRangesError> {
|
|
self.ranges
|
|
.get(index as usize)
|
|
.map(|r| r.end)
|
|
.ok_or(TimeRangesError::OutOfRange)
|
|
}
|
|
|
|
pub fn add(&mut self, start: f64, end: f64) -> Result<(), TimeRangesError> {
|
|
if start > end {
|
|
return Err(TimeRangesError::EndOlderThanStart);
|
|
}
|
|
|
|
let mut new_range = TimeRange { start, end };
|
|
|
|
// For each present range check if we need to:
|
|
// - merge with the added range, in case we are overlapping or contiguous,
|
|
// - insert in place, we are completely, not overlapping and not contiguous
|
|
// in between two ranges.
|
|
let mut idx = 0;
|
|
while idx < self.ranges.len() {
|
|
if new_range.is_overlapping(&self.ranges[idx]) ||
|
|
new_range.is_contiguous(&self.ranges[idx])
|
|
{
|
|
// The ranges are either overlapping or contiguous,
|
|
// we need to merge the new range with the existing one.
|
|
new_range.union(&self.ranges[idx]);
|
|
self.ranges.remove(idx);
|
|
} else if new_range.is_before(&self.ranges[idx]) &&
|
|
(idx == 0 || self.ranges[idx - 1].is_before(&new_range))
|
|
{
|
|
// We are exactly after the current previous range and before the current
|
|
// range, while not overlapping with none of them.
|
|
// Or we are simply at the beginning.
|
|
self.ranges.insert(idx, new_range);
|
|
return Ok(());
|
|
} else {
|
|
idx += 1;
|
|
}
|
|
}
|
|
|
|
// Insert at the end.
|
|
self.ranges.insert(idx, new_range);
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[dom_struct]
|
|
pub(crate) struct TimeRanges {
|
|
reflector_: Reflector,
|
|
ranges: TimeRangesContainer,
|
|
}
|
|
|
|
impl TimeRanges {
|
|
fn new_inherited(ranges: TimeRangesContainer) -> TimeRanges {
|
|
Self {
|
|
reflector_: Reflector::new(),
|
|
ranges,
|
|
}
|
|
}
|
|
|
|
pub(crate) fn new(
|
|
window: &Window,
|
|
ranges: TimeRangesContainer,
|
|
can_gc: CanGc,
|
|
) -> DomRoot<TimeRanges> {
|
|
reflect_dom_object(Box::new(TimeRanges::new_inherited(ranges)), window, can_gc)
|
|
}
|
|
}
|
|
|
|
impl TimeRangesMethods<crate::DomTypeHolder> for TimeRanges {
|
|
// https://html.spec.whatwg.org/multipage/#dom-timeranges-length
|
|
fn Length(&self) -> u32 {
|
|
self.ranges.len()
|
|
}
|
|
|
|
// https://html.spec.whatwg.org/multipage/#dom-timeranges-start
|
|
fn Start(&self, index: u32) -> Fallible<Finite<f64>> {
|
|
self.ranges
|
|
.start(index)
|
|
.map(Finite::wrap)
|
|
.map_err(|_| Error::IndexSize)
|
|
}
|
|
|
|
// https://html.spec.whatwg.org/multipage/#dom-timeranges-end
|
|
fn End(&self, index: u32) -> Fallible<Finite<f64>> {
|
|
self.ranges
|
|
.end(index)
|
|
.map(Finite::wrap)
|
|
.map_err(|_| Error::IndexSize)
|
|
}
|
|
}
|