Skip to content

Commit

Permalink
web-media: Implemented media query level 4.
Browse files Browse the repository at this point in the history
  • Loading branch information
sleepy-monax committed Apr 22, 2024
1 parent f545a88 commit ee802a4
Show file tree
Hide file tree
Showing 10 changed files with 870 additions and 10 deletions.
20 changes: 10 additions & 10 deletions src/libs/karm-base/box.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,27 @@ struct Box {
constexpr Box(T *ptr)
: _ptr(ptr) {}

constexpr Box(Box const &) = delete;
constexpr Box(Box const &other)
: _ptr(new T(*other._ptr)) {}

template <Meta::Derive<T> U>
constexpr Box(Box<U> &&other) {
delete _ptr;
_ptr = other._ptr;
other._ptr = nullptr;
}
constexpr Box(Box<U> &&other)
: _ptr(std::exchange(other._ptr, nullptr)) {}

constexpr ~Box() {
if (_ptr)
delete _ptr;
_ptr = nullptr;
}

constexpr Box &operator=(Box const &) = delete;
constexpr Box &operator=(Box const &other) {
*this = Box(other);
return *this;
}

template <Meta::Derive<T> U>
constexpr Box &operator=(Box<U> &&other) {
delete _ptr;
_ptr = other._ptr;
other._ptr = nullptr;
std::swap(_ptr, other._ptr);
return *this;
}

Expand Down
96 changes: 96 additions & 0 deletions src/web/web-css/units.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,16 @@ struct Length {
bool isRelative() const {
return not isAbsolute();
}

bool operator==(Length const &other) const {
return _val == other._val and _unit == other._unit;
}

std::partial_ordering operator<=>(Length const &other) const {
if (_unit != other._unit)
return std::partial_ordering::unordered;
return _val <=> other._val;
}
};

struct FontMetrics {
Expand Down Expand Up @@ -472,4 +482,90 @@ struct Angle {
}
};

// 7.4. MARK: Resolution Units: the <resolution> type and dpi, dpcm, dppx units
// https://drafts.csswg.org/css-values/#resolution

struct Resolution {
enum struct Unit {
DPI,
DPCM,
DPPX,
INFINITE,
};

double _val;
Unit _unit;

static Resolution fromDpi(double val) {
return {val, Unit::DPI};
}

static Resolution fromDpcm(double val) {
return {val, Unit::DPCM};
}

static Resolution fromDppx(double val) {
return {val, Unit::DPPX};
}

static Resolution infinite() {
return {0.0, Unit::INFINITE};
}

double val() const {
return _val;
}

Unit unit() const {
return _unit;
}

double toDpi() const {
switch (_unit) {
case Unit::DPI:
return _val;
case Unit::DPCM:
return _val * 2.54;
case Unit::DPPX:
return _val * 96.0;
case Unit::INFINITE:
return INFINITY;
}
}

double toDpcm() const {
switch (_unit) {
case Unit::DPI:
return _val / 2.54;
case Unit::DPCM:
return _val;
case Unit::DPPX:
return _val * 96.0 / 2.54;
case Unit::INFINITE:
return INFINITY;
}
}

double toDppx() const {
switch (_unit) {
case Unit::DPI:
return _val / 96.0;
case Unit::DPCM:
return _val * 2.54 / 96.0;
case Unit::DPPX:
return _val;
case Unit::INFINITE:
return INFINITY;
}
}

bool operator==(Resolution const &other) const {
return _val == other._val and _unit == other._unit;
}

std::partial_ordering operator<=>(Resolution const &other) const {
return toDpi() <=> other.toDpi();
}
};

} // namespace Web::Css
205 changes: 205 additions & 0 deletions src/web/web-media/features.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
#pragma once

#include "media.h"
#include "types.h"

namespace Web::Media {

template <typename T>
struct RangeBound {
enum Type : u8 {
NONE,
INCLUSIVE,
EXCLUSIVE,
};

T value = {};
Type type = NONE;
};

template <typename T, auto Media::*F>
struct RangeFeature {
using Bound = RangeBound<T>;

Bound lower{};
Bound upper{};

bool match(T actual) const {
bool result = true;

if (lower.type == Bound::INCLUSIVE) {
result &= actual >= lower.value;
} else if (lower.type == Bound::EXCLUSIVE) {
result &= actual > lower.value;
}

if (upper.type == Bound::INCLUSIVE) {
result &= actual <= upper.value;
} else if (upper.type == Bound::EXCLUSIVE) {
result &= actual < upper.value;
}

return result;
}

bool match(Media const &media) const {
return match(media.*F);
}

static RangeFeature min(T value) {
return {
.lower = {value, Bound::INCLUSIVE},
};
}

static RangeFeature max(T value) {
return {
.upper = {value, Bound::INCLUSIVE},
};
}

static RangeFeature exact(T value) {
return {
.lower = {value, Bound::INCLUSIVE},
.upper = {value, Bound::INCLUSIVE},
};
}
};

template <typename T, auto Media::*F>
struct DiscreteFeature {
T value;

bool match(T actual) const {
return actual == value;
}

bool match(Media const &media) const {
return match(media.*F);
}
};

/// 2.3. Media Types
/// https://drafts.csswg.org/mediaqueries/#media-types
using TypeFeature = DiscreteFeature<Type, &Media::type>;

// 4. MARK: Viewport/Page Dimensions Media Features

/// 4.1. Width: the width feature
/// https://drafts.csswg.org/mediaqueries/#width
using WidthFeature = RangeFeature<Css::Length, &Media::width>;

/// 4.2. Height: the height feature
/// https://drafts.csswg.org/mediaqueries/#height
using HeightFeature = RangeFeature<Css::Length, &Media::height>;

/// 4.3. Device Width: the device-width feature
/// https://drafts.csswg.org/mediaqueries/#aspect-ratio
using AspectRatioFeature = RangeFeature<double, &Media::aspectRatio>;

/// 4.4. Device Height: the device-height feature
/// https://drafts.csswg.org/mediaqueries/#orientation
using OrientationFeature = DiscreteFeature<Orientation, &Media::orientation>;

// 5. MARK: Display Quality Media Features

/// 5.1. Resolution: the resolution feature
/// https://drafts.csswg.org/mediaqueries/#resolution
using ResolutionFeature = RangeFeature<Css::Resolution, &Media::resolution>;

/// 5.2. Scan: the scan feature
/// https://drafts.csswg.org/mediaqueries/#scan
using ScanFeature = DiscreteFeature<Scan, &Media::scan>;

/// 5.3. Grid: the grid feature
/// https://drafts.csswg.org/mediaqueries/#grid
using GridFeature = DiscreteFeature<bool, &Media::grid>;

/// 5.4. Update: the update feature
/// https://drafts.csswg.org/mediaqueries/#update
using UpdateFeature = DiscreteFeature<Update, &Media::update>;

/// 5.5. Overflow Block: the overflow-block feature
/// https://drafts.csswg.org/mediaqueries/#overflow-block
using OverflowBlockFeature = DiscreteFeature<OverflowBlock, &Media::overflowBlock>;

/// 5.6. Overflow Inline: the overflow-inline feature
/// https://drafts.csswg.org/mediaqueries/#overflow-inline
using OverflowInlineFeature = DiscreteFeature<OverflowInline, &Media::overflowInline>;

// 6. MARK: Color Media Features

// 6.1. Color: the color feature
/// https://drafts.csswg.org/mediaqueries/#color
using ColorFeature = RangeFeature<int, &Media::color>;

/// 6.2. Color Index: the color-index feature
/// https://drafts.csswg.org/mediaqueries/#color-index
using ColorIndexFeature = RangeFeature<int, &Media::colorIndex>;

/// 6.3. Monochrome: the monochrome feature
/// https://drafts.csswg.org/mediaqueries/#monochrome
using MonochromeFeature = RangeFeature<int, &Media::monochrome>;

/// 6.4. Color Gamut: the color-gamut feature
/// https://drafts.csswg.org/mediaqueries/#color-gamut
using ColorGamutFeature = DiscreteFeature<ColorGamut, &Media::colorGamut>;

// 7. MARK: Interaction Media Features

/// 7.1. Pointer: the pointer feature
/// https://drafts.csswg.org/mediaqueries/#pointer
using PointerFeature = DiscreteFeature<Pointer, &Media::pointer>;

/// 7.2. Hover: the hover feature
/// https://drafts.csswg.org/mediaqueries/#hover
using HoverFeature = DiscreteFeature<Hover, &Media::hover>;

/// 7.3. Any Pointer: the any-pointer feature
/// https://drafts.csswg.org/mediaqueries/#any-pointer
using AnyPointerFeature = DiscreteFeature<Pointer, &Media::anyPointer>;

/// 7.4. Any Hover: the any-hover feature
/// https://drafts.csswg.org/mediaqueries/#any-hover
using AnyHoverFeature = DiscreteFeature<Hover, &Media::anyHover>;

using _Feature = Union<
TypeFeature,
WidthFeature,
HeightFeature,
AspectRatioFeature,
OrientationFeature,
ResolutionFeature,
ScanFeature,
GridFeature,
UpdateFeature,
OverflowBlockFeature,
OverflowInlineFeature,
ColorFeature,
ColorIndexFeature,
MonochromeFeature,
ColorGamutFeature,
PointerFeature,
HoverFeature,
AnyPointerFeature,
AnyHoverFeature>;

struct Feature : public _Feature {
using _Feature::_Feature;

bool match(Media const &media) const {
return visit([&](auto const &feature) {
return feature.match(media);
});
}

static Feature type(Type value) {
return TypeFeature{value};
}

static Feature width(RangeFeature<Css::Length, &Media::width> value) {
return value;
}
};

} // namespace Web::Media
10 changes: 10 additions & 0 deletions src/web/web-media/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1",
"id": "web-media",
"type": "lib",
"description": "Implementation of CSS Media Queries Level 4 (https://drafts.csswg.org/mediaqueries)",
"requires": [
"karm-logger",
"web-css"
]
}
Loading

0 comments on commit ee802a4

Please sign in to comment.