diff options
author | Sam Atkins <atkinssj@serenityos.org> | 2022-11-08 17:37:49 +0000 |
---|---|---|
committer | Sam Atkins <atkinssj@gmail.com> | 2022-12-08 12:46:03 +0000 |
commit | bd272e638cc33e3282ffde1052eafd15cd00eac5 (patch) | |
tree | 443cf21c5f6338e6798edf07cffe17a3494fdda1 /Userland | |
parent | 83f31cb4a7d5724e59a4baf05bd46d092dc15be9 (diff) | |
download | serenity-bd272e638cc33e3282ffde1052eafd15cd00eac5.zip |
LibWeb: Introduce CSSPixels and DevicePixels classes
These are an attempt to separate the internal "pixel" used by CSS from
the actual "pixel" that exists on the display. Because of things like
2x display scaling, the ratio between these can vary, so having
distinct types will help prevent errors when converting from one unit
to the other.
`CSSPixels` refers to the `px` unit used on the web, which depending on
the device may or may not map to 1 pixel on the physical display. It's
a wrapper around `float`, and will be used by LibWeb for size and
position values up until we go to paint them to the screen.
`DevicePixels` on the other hand is a 1-to-1 pixel on the physical
display. It's a wrapper around `int`.
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/Libraries/LibWeb/PixelUnits.h | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/Userland/Libraries/LibWeb/PixelUnits.h b/Userland/Libraries/LibWeb/PixelUnits.h new file mode 100644 index 0000000000..702107e81b --- /dev/null +++ b/Userland/Libraries/LibWeb/PixelUnits.h @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/Concepts.h> +#include <AK/DistinctNumeric.h> +#include <AK/Traits.h> +#include <LibGfx/Forward.h> +#include <math.h> + +namespace Web { + +/// DevicePixels: A position or length on the physical display. +AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(int, DevicePixels, Arithmetic, CastToUnderlying, Comparison, Increment); + +template<Arithmetic T> +constexpr bool operator==(DevicePixels left, T right) { return left.value() == right; } + +template<Arithmetic T> +constexpr bool operator!=(DevicePixels left, T right) { return left.value() != right; } + +template<Arithmetic T> +constexpr bool operator>(DevicePixels left, T right) { return left.value() > right; } + +template<Arithmetic T> +constexpr bool operator<(DevicePixels left, T right) { return left.value() < right; } + +template<Arithmetic T> +constexpr bool operator>=(DevicePixels left, T right) { return left.value() >= right; } + +template<Arithmetic T> +constexpr bool operator<=(DevicePixels left, T right) { return left.value() <= right; } + +template<Arithmetic T> +constexpr DevicePixels operator*(DevicePixels left, T right) { return left.value() * right; } +template<Arithmetic T> +constexpr DevicePixels operator*(T left, DevicePixels right) { return right * left; } + +template<Arithmetic T> +constexpr DevicePixels operator/(DevicePixels left, T right) { return left.value() / right; } + +template<Arithmetic T> +constexpr DevicePixels operator%(DevicePixels left, T right) { return left.value() % right; } + +/// CSSPixels: A position or length in CSS "reference pixels", independent of zoom or screen DPI. +/// See https://www.w3.org/TR/css-values-3/#reference-pixel +AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(float, CSSPixels, Arithmetic, CastToUnderlying, Comparison, Increment); + +template<Arithmetic T> +constexpr bool operator==(CSSPixels left, T right) { return left.value() == right; } + +template<Arithmetic T> +constexpr bool operator!=(CSSPixels left, T right) { return left.value() != right; } + +template<Arithmetic T> +constexpr bool operator>(CSSPixels left, T right) { return left.value() > right; } + +template<Arithmetic T> +constexpr bool operator<(CSSPixels left, T right) { return left.value() < right; } + +template<Arithmetic T> +constexpr bool operator>=(CSSPixels left, T right) { return left.value() >= right; } + +template<Arithmetic T> +constexpr bool operator<=(CSSPixels left, T right) { return left.value() <= right; } + +template<Arithmetic T> +constexpr CSSPixels operator*(CSSPixels left, T right) { return left.value() * right; } +template<Arithmetic T> +constexpr CSSPixels operator*(T left, CSSPixels right) { return right * left; } + +template<Arithmetic T> +constexpr CSSPixels operator/(CSSPixels left, T right) { return left.value() / right; } + +template<Arithmetic T> +constexpr CSSPixels operator%(CSSPixels left, T right) { return left.value() % right; } + +using CSSPixelLine = Gfx::Line<CSSPixels>; +using CSSPixelPoint = Gfx::Point<CSSPixels>; +using CSSPixelRect = Gfx::Rect<CSSPixels>; +using CSSPixelSize = Gfx::Size<CSSPixels>; + +using DevicePixelLine = Gfx::Line<DevicePixels>; +using DevicePixelPoint = Gfx::Point<DevicePixels>; +using DevicePixelRect = Gfx::Rect<DevicePixels>; +using DevicePixelSize = Gfx::Size<DevicePixels>; + +} + +constexpr Web::CSSPixels floor(Web::CSSPixels const& value) +{ + return ::floorf(value.value()); +} + +constexpr Web::CSSPixels ceil(Web::CSSPixels const& value) +{ + return ::ceilf(value.value()); +} + +constexpr Web::CSSPixels round(Web::CSSPixels const& value) +{ + return ::roundf(value.value()); +} + +constexpr Web::CSSPixels fmod(Web::CSSPixels const& x, Web::CSSPixels const& y) +{ + return ::fmodf(x.value(), y.value()); +} + +constexpr Web::CSSPixels abs(Web::CSSPixels const& value) +{ + return AK::abs(value.value()); +} + +constexpr Web::DevicePixels abs(Web::DevicePixels const& value) +{ + return AK::abs(value.value()); +} + +namespace AK { + +template<> +struct Traits<Web::CSSPixels> : public GenericTraits<Web::CSSPixels> { + static unsigned hash(Web::CSSPixels const& key) + { + return double_hash(key.value()); + } + + static bool equals(Web::CSSPixels const& a, Web::CSSPixels const& b) + { + return a == b; + } +}; + +template<> +struct Traits<Web::DevicePixels> : public GenericTraits<Web::DevicePixels> { + static unsigned hash(Web::DevicePixels const& key) + { + return double_hash(key.value()); + } + + static bool equals(Web::DevicePixels const& a, Web::DevicePixels const& b) + { + return a == b; + } +}; + +template<> +struct Formatter<Web::CSSPixels> : Formatter<float> { + ErrorOr<void> format(FormatBuilder& builder, Web::CSSPixels const& value) + { + return Formatter<float>::format(builder, value.value()); + } +}; + +template<> +struct Formatter<Web::DevicePixels> : Formatter<float> { + ErrorOr<void> format(FormatBuilder& builder, Web::DevicePixels const& value) + { + return Formatter<float>::format(builder, value.value()); + } +}; + +} |