Skip to content

Commit

Permalink
vaev-layout: Initial implementation of specified sizing.
Browse files Browse the repository at this point in the history
  • Loading branch information
sleepy-monax committed Jul 29, 2024
1 parent 84d53ab commit a213053
Show file tree
Hide file tree
Showing 23 changed files with 873 additions and 363 deletions.
17 changes: 0 additions & 17 deletions src/web/vaev-base/base.h

This file was deleted.

221 changes: 3 additions & 218 deletions src/web/vaev-base/length.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@
#include <karm-base/distinct.h>
#include <karm-io/emit.h>
#include <karm-math/fixed.h>
#include <karm-math/radius.h>
#include <karm-math/rect.h>
#include <karm-math/spacing.h>

#include "base.h"
#include "writing.h"

namespace Vaev {

/// Represents a physical pixel on the actual device screen.
Expand All @@ -23,6 +21,8 @@ using Vec2Px = Math::Vec2<Px>;

using SpacingPx = Math::Spacing<Px>;

using RadiusPx = Math::Radius<Px>;

// 6. MARK: Distance Units: the <length> type
// https://drafts.csswg.org/css-values/#lengths

Expand Down Expand Up @@ -143,219 +143,4 @@ struct Length {
}
};

struct FontMetrics {
Px fontSize;
Px xHeight; //< height of the lowercase 'x'.
Px capHeight;
Px zeroAdvance; //< width of the '0' character.
Px lineHeight;
};

template <>
struct ValueContext<Length> {
using Resolved = Px;

Px dpi = Px{96};

// https://drafts.csswg.org/css-values/#small-viewport-size
Math::Rect<Px> smallViewport;

// https://drafts.csswg.org/css-values/#large-viewport-size
Math::Rect<Px> largeViewport;

// https://drafts.csswg.org/css-values/#dynamic-viewport-size
Math::Rect<Px> dynamicViewport;

InlineAxis inlineAxis;
BlockAxis blockAxis;

FontMetrics fontMetrics;
FontMetrics rootFontMetrics;

constexpr Px resolve(Length const &l) const {
switch (l.unit()) {
// Font-relative

case Length::Unit::EM:
return Px::fromFloatNearest(l.val() * fontMetrics.fontSize.toFloat<f64>());

case Length::Unit::REM:
return Px::fromFloatNearest(l.val() * rootFontMetrics.fontSize.toFloat<f64>());

case Length::Unit::EX:
return Px::fromFloatNearest(l.val() * fontMetrics.xHeight.toFloat<f64>());

case Length::Unit::REX:
return Px::fromFloatNearest(l.val() * rootFontMetrics.xHeight.toFloat<f64>());

case Length::Unit::CAP:
return Px::fromFloatNearest(l.val() * fontMetrics.capHeight.toFloat<f64>());

case Length::Unit::RCAP:
return Px::fromFloatNearest(l.val() * rootFontMetrics.capHeight.toFloat<f64>());

case Length::Unit::CH:
return Px::fromFloatNearest(l.val() * fontMetrics.zeroAdvance.toFloat<f64>());

case Length::Unit::RCH:
return Px::fromFloatNearest(l.val() * rootFontMetrics.zeroAdvance.toFloat<f64>());

case Length::Unit::IC:
return Px::fromFloatNearest(l.val() * fontMetrics.zeroAdvance.toFloat<f64>());

case Length::Unit::RIC:
return Px::fromFloatNearest(l.val() * rootFontMetrics.zeroAdvance.toFloat<f64>());

case Length::Unit::LH:
return Px::fromFloatNearest(l.val() * fontMetrics.lineHeight.toFloat<f64>());

case Length::Unit::RLH:
return Px::fromFloatNearest(l.val() * rootFontMetrics.lineHeight.toFloat<f64>());

// Viewport-relative

// https://drafts.csswg.org/css-values/#vw

// Equal to 1% of the width of current viewport.
case Length::Unit::VW:
case Length::Unit::LVW:
return Px::fromFloatNearest(l.val() * largeViewport.width.toFloat<f64>() / 100);

case Length::Unit::SVW:
return Px::fromFloatNearest(l.val() * smallViewport.width.toFloat<f64>() / 100);

case Length::Unit::DVW:
return Px::fromFloatNearest(l.val() * dynamicViewport.width.toFloat<f64>() / 100);

// https://drafts.csswg.org/css-values/#vh
// Equal to 1% of the height of current viewport.
case Length::Unit::VH:
case Length::Unit::LVH:
return Px::fromFloatNearest(l.val() * largeViewport.height.toFloat<f64>() / 100);

case Length::Unit::SVH:
return Px::fromFloatNearest(l.val() * smallViewport.height.toFloat<f64>() / 100);

case Length::Unit::DVH:
return Px::fromFloatNearest(l.val() * dynamicViewport.height.toFloat<f64>() / 100);

// https://drafts.csswg.org/css-values/#vi
// Equal to 1% of the size of the viewport in the box’s inline axis.
case Length::Unit::VI:
case Length::Unit::LVI:
if (inlineAxis == InlineAxis::HORIZONTAL) {
return Px::fromFloatNearest(l.val() * largeViewport.width.toFloat<f64>() / 100);
} else {
return Px::fromFloatNearest(l.val() * largeViewport.height.toFloat<f64>() / 100);
}

case Length::Unit::SVI:
if (inlineAxis == InlineAxis::HORIZONTAL) {
return Px::fromFloatNearest(l.val() * smallViewport.width.toFloat<f64>() / 100);
} else {
return Px::fromFloatNearest(l.val() * smallViewport.height.toFloat<f64>() / 100);
}

case Length::Unit::DVI:
if (inlineAxis == InlineAxis::HORIZONTAL) {
return Px::fromFloatNearest(l.val() * dynamicViewport.width.toFloat<f64>() / 100);
} else {
return Px::fromFloatNearest(l.val() * dynamicViewport.height.toFloat<f64>() / 100);
}

// https://drafts.csswg.org/css-values/#vb
// Equal to 1% of the size of the viewport in the box’s block axis.
case Length::Unit::VB:
case Length::Unit::LVB:
if (blockAxis == BlockAxis::HORIZONTAL) {
return Px::fromFloatNearest(l.val() * largeViewport.width.toFloat<f64>() / 100);
} else {
return Px::fromFloatNearest(l.val() * largeViewport.height.toFloat<f64>() / 100);
}

case Length::Unit::SVB:
if (blockAxis == BlockAxis::HORIZONTAL) {
return Px::fromFloatNearest(l.val() * smallViewport.width.toFloat<f64>() / 100);
} else {
return Px::fromFloatNearest(l.val() * smallViewport.height.toFloat<f64>() / 100);
}

case Length::Unit::DVB:
if (blockAxis == BlockAxis::HORIZONTAL) {
return Px::fromFloatNearest(l.val() * dynamicViewport.width.toFloat<f64>() / 100);
} else {
return Px::fromFloatNearest(l.val() * dynamicViewport.height.toFloat<f64>() / 100);
}

// https://drafts.csswg.org/css-values/#vmin
// Equal to the smaller of vw and vh.
case Length::Unit::VMIN:
case Length::Unit::LVMIN:
return min(
resolve(Length(l.val(), Length::Unit::VW)),
resolve(Length(l.val(), Length::Unit::VH))
);

case Length::Unit::SVMIN:
return min(
resolve(Length(l.val(), Length::Unit::SVW)),
resolve(Length(l.val(), Length::Unit::SVH))
);

case Length::Unit::DVMIN:
return min(
resolve(Length(l.val(), Length::Unit::DVW)),
resolve(Length(l.val(), Length::Unit::DVH))
);

// https://drafts.csswg.org/css-values/#vmax
// Equal to the larger of vw and vh.
case Length::Unit::VMAX:
case Length::Unit::LVMAX:
return max(
resolve(Length(l.val(), Length::Unit::VW)),
resolve(Length(l.val(), Length::Unit::VH))
);

case Length::Unit::DVMAX:
return max(
resolve(Length(l.val(), Length::Unit::DVW)),
resolve(Length(l.val(), Length::Unit::DVH))
);

case Length::Unit::SVMAX:
return max(
resolve(Length(l.val(), Length::Unit::SVW)),
resolve(Length(l.val(), Length::Unit::SVH))
);

// Absolute
// https://drafts.csswg.org/css-values/#absolute-lengths
case Length::Unit::CM:
return Px::fromFloatNearest(l.val() * dpi.toFloat<f64>() / 2.54);

case Length::Unit::MM:
return Px::fromFloatNearest(l.val() * dpi.toFloat<f64>() / 25.4);

case Length::Unit::Q:
return Px::fromFloatNearest(l.val() * dpi.toFloat<f64>() / 101.6);

case Length::Unit::IN:
return Px::fromFloatNearest(l.val() * dpi.toFloat<f64>());

case Length::Unit::PT:
return Px::fromFloatNearest(l.val() * dpi.toFloat<f64>() / 72.0);

case Length::Unit::PC:
return Px::fromFloatNearest(l.val() * dpi.toFloat<f64>() / 6.0);

case Length::Unit::PX:
return Px::fromFloatNearest(l.val());

default:
panic("invalid length unit");
}
}
};

} // namespace Vaev
18 changes: 1 addition & 17 deletions src/web/vaev-base/percent.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
#include <karm-base/distinct.h>
#include <karm-io/emit.h>

#include "base.h"

namespace Vaev {

using Percent = Distinct<f64, struct _PercentTag>;
Expand Down Expand Up @@ -58,7 +56,7 @@ struct PercentOr {
}

constexpr bool resolved() const {
return _type == Type::VALUE and _value.resolved();
return _type == Type::VALUE;
}

T value() const {
Expand All @@ -74,20 +72,6 @@ struct PercentOr {
}
};

template <typename T>
struct ValueContext<PercentOr<T>> : public ValueContext<T> {
using Resolved = ValueContext<T>::Resolved;

T percentRelative;

Resolved resolve(PercentOr<T> value) {
if (value == PercentOr<T>::Type::PERCENT) {
return {percentRelative * (value.percent().value() / 100.)};
}
return ValueContext<T>::resolve(value.value());
}
};

} // namespace Vaev

template <>
Expand Down
30 changes: 27 additions & 3 deletions src/web/vaev-base/sizing.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,20 @@

#include "length.h"
#include "percent.h"
#include "writing.h"

namespace Vaev {

// https://www.w3.org/TR/css-sizing-3/#box-sizing
enum struct BoxSizing {
enum struct BoxSizing : u8 {
CONTENT_BOX,
BORDER_BOX,
};

// https://www.w3.org/TR/css-sizing-3/#propdef-width
// https://www.w3.org/TR/css-sizing-3/#propdef-height
struct Size {
enum struct Type {
enum struct Type : u8 {
NONE,
AUTO,
LENGTH,
Expand Down Expand Up @@ -82,11 +83,34 @@ struct Size {
}
};


struct Sizing {
Size width, height;
Size minWidth, minHeight;
Size maxWidth, maxHeight;

Size &size(Axis axis) {
return axis == Axis::HORIZONTAL ? width : height;
}

Size const size(Axis axis) const {
return axis == Axis::HORIZONTAL ? width : height;
}

Size &minSize(Axis axis) {
return axis == Axis::HORIZONTAL ? minWidth : minHeight;
}

Size const minSize(Axis axis) const {
return axis == Axis::HORIZONTAL ? minWidth : minHeight;
}

Size &maxSize(Axis axis) {
return axis == Axis::HORIZONTAL ? maxWidth : maxHeight;
}

Size const maxSize(Axis axis) const {
return axis == Axis::HORIZONTAL ? maxWidth : maxHeight;
}
};

} // namespace Vaev
8 changes: 2 additions & 6 deletions src/web/vaev-base/width.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,14 @@ struct Width {

using enum Type;

Type type = Type::VALUE;
Type type;
PercentOr<Length> value;

constexpr Width()
: Width(Percent{}) {
}

constexpr Width(Type type)
: type(type) {
}

constexpr Width(PercentOr<Length> percent)
constexpr Width(PercentOr<Length> percent = {})
: type(Type::VALUE), value(percent) {
}

Expand Down
Loading

0 comments on commit a213053

Please sign in to comment.