summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorSam Atkins <atkinssj@serenityos.org>2022-11-08 17:37:49 +0000
committerSam Atkins <atkinssj@gmail.com>2022-12-08 12:46:03 +0000
commitbd272e638cc33e3282ffde1052eafd15cd00eac5 (patch)
tree443cf21c5f6338e6798edf07cffe17a3494fdda1 /Userland
parent83f31cb4a7d5724e59a4baf05bd46d092dc15be9 (diff)
downloadserenity-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.h168
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());
+ }
+};
+
+}