Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Libraries/LibGfx/Font/Font.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ float ladybird_gfx_font_glyph_width(void const*, u32);
u32 ladybird_gfx_font_glyph_id(void const*, u32);
bool ladybird_gfx_font_contains_glyph(void const*, u32);
bool ladybird_gfx_font_is_emoji_font(void const*);
void ladybird_gfx_font_ref(void const*);
void ladybird_gfx_font_unref(void const*);
}

namespace Gfx {
Expand Down Expand Up @@ -274,3 +276,15 @@ extern "C" bool ladybird_gfx_font_is_emoji_font(void const* font)
VERIFY(font);
return static_cast<Gfx::Font const*>(font)->is_emoji_font();
}

extern "C" void ladybird_gfx_font_ref(void const* font)
{
VERIFY(font);
static_cast<Gfx::Font const*>(font)->ref();
}

extern "C" void ladybird_gfx_font_unref(void const* font)
{
VERIFY(font);
static_cast<Gfx::Font const*>(font)->unref();
}
9 changes: 9 additions & 0 deletions Libraries/LibGfx/Path.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
#include <LibGfx/PathSkia.h>
#include <LibIPC/Decoder.h>
#include <LibIPC/Encoder.h>
#include <core/SkPath.h>

extern "C" {
void ladybird_gfx_path_destroy(void*);
bool ladybird_gfx_path_equals(void const*, void const*);
}

namespace Gfx {
Expand Down Expand Up @@ -52,3 +54,10 @@ extern "C" void ladybird_gfx_path_destroy(void* path)
{
delete static_cast<Gfx::Path*>(path);
}

extern "C" bool ladybird_gfx_path_equals(void const* a, void const* b)
{
auto const& path_a = *static_cast<Gfx::Path const*>(a);
auto const& path_b = *static_cast<Gfx::Path const*>(b);
return static_cast<Gfx::PathImplSkia const&>(path_a.impl()).sk_path() == static_cast<Gfx::PathImplSkia const&>(path_b.impl()).sk_path();
}
75 changes: 49 additions & 26 deletions Libraries/LibGfx/Rust/src/font.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ unsafe extern "C" {
forced_presentation: bool,
) -> *const c_void;
fn ladybird_gfx_font_cascade_list_first(list: *const c_void) -> *const c_void;
fn ladybird_gfx_font_ref(font: *const c_void);
fn ladybird_gfx_font_unref(font: *const c_void);
fn ladybird_gfx_font_cascade_list_ref(list: *const c_void);
fn ladybird_gfx_font_cascade_list_unref(list: *const c_void);
fn ladybird_gfx_emoji_presentation_for_code_point(
Expand Down Expand Up @@ -163,33 +165,54 @@ impl<'a> FontCascadeListRef<'a> {
}
}

/// A strong reference to a `Gfx::FontCascadeList`, keeping the list and every
/// font it can resolve alive until dropped.
pub struct RetainedFontCascadeList {
raw: NonNull<c_void>,
}
/// Generates a strong-reference handle over a C++ ref/unref FFI pair:
/// retain-on-construct, release-on-drop.
macro_rules! retained_ffi_handle {
($(#[$documentation:meta])* $name:ident, $ref_function:ident, $unref_function:ident, $type_name:literal) => {
$(#[$documentation])*
pub struct $name {
raw: NonNull<c_void>,
}

impl RetainedFontCascadeList {
/// # Safety
///
/// `raw` must point to a live `Gfx::FontCascadeList` at the time of the
/// call.
pub unsafe fn retain(raw: *const c_void) -> Self {
let raw = NonNull::new(raw.cast_mut()).expect("Gfx::FontCascadeList pointer must not be null");
// SAFETY: The caller guarantees the list is live, and ref() keeps it
// that way until this reference drops.
unsafe { ladybird_gfx_font_cascade_list_ref(raw.as_ptr()) };
Self { raw }
}
impl $name {
/// # Safety
///
/// `raw` must point to a live object at the time of the call.
pub unsafe fn retain(raw: *const c_void) -> Self {
let raw = NonNull::new(raw.cast_mut()).expect(concat!($type_name, " pointer must not be null"));
// SAFETY: The caller guarantees the object is live, and the
// reference taken here keeps it that way until drop.
unsafe { $ref_function(raw.as_ptr()) };
Self { raw }
}

pub fn as_raw(&self) -> *const c_void {
self.raw.as_ptr()
}
}

pub fn as_raw(&self) -> *const c_void {
self.raw.as_ptr()
}
impl Drop for $name {
fn drop(&mut self) {
// SAFETY: retain() took a strong reference on construction.
unsafe { $unref_function(self.raw.as_ptr()) };
}
}
};
}

impl Drop for RetainedFontCascadeList {
fn drop(&mut self) {
// SAFETY: retain() took a strong reference on construction.
unsafe { ladybird_gfx_font_cascade_list_unref(self.raw.as_ptr()) };
}
}
retained_ffi_handle!(
/// A strong reference to a single `Gfx::Font`, keeping it alive until dropped.
RetainedFont,
ladybird_gfx_font_ref,
ladybird_gfx_font_unref,
"Gfx::Font"
);

retained_ffi_handle!(
/// A strong reference to a `Gfx::FontCascadeList`, keeping the list and every
/// font it can resolve alive until dropped.
RetainedFontCascadeList,
ladybird_gfx_font_cascade_list_ref,
ladybird_gfx_font_cascade_list_unref,
"Gfx::FontCascadeList"
);
20 changes: 20 additions & 0 deletions Libraries/LibGfx/Rust/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ use std::ptr::NonNull;

unsafe extern "C" {
fn ladybird_gfx_path_destroy(path: *mut c_void);
fn ladybird_gfx_path_equals(a: *const c_void, b: *const c_void) -> bool;
}

/// The sole owner of a heap-allocated `Gfx::Path`, destroying it on drop.
pub struct OwnedPath {
raw: NonNull<c_void>,
identity: u64,
}

impl OwnedPath {
Expand All @@ -25,8 +27,10 @@ impl OwnedPath {
/// `Gfx::Path` is owned or destroyed.
#[inline]
pub unsafe fn adopt(raw: *mut c_void) -> Self {
static NEXT_IDENTITY: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(1);
Self {
raw: NonNull::new(raw).expect("Gfx::Path pointer must not be null"),
identity: NEXT_IDENTITY.fetch_add(1, std::sync::atomic::Ordering::Relaxed),
}
}

Expand All @@ -35,6 +39,22 @@ impl OwnedPath {
pub fn as_raw(&self) -> *mut c_void {
self.raw.as_ptr()
}

/// A process-unique, never-reused identity for this path allocation, so
/// consumers holding a copied snapshot can recognize an unchanged path
/// without comparing contents.
#[inline]
pub fn identity(&self) -> u64 {
self.identity
}
}

impl PartialEq for OwnedPath {
fn eq(&self, other: &Self) -> bool {
self.identity == other.identity
// SAFETY: Both sides own live heap-allocated paths for the duration of the call.
|| unsafe { ladybird_gfx_path_equals(self.raw.as_ptr(), other.raw.as_ptr()) }
}
}

impl Drop for OwnedPath {
Expand Down
32 changes: 32 additions & 0 deletions Libraries/LibWeb/CSS/ComputedProperties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,38 @@ RefPtr<StyleValue const> ComputedValues::background_color_style_value() const

static_assert(to_underlying(PseudoElement::KnownPseudoElementCount) <= sizeof(u64) * 8);

static bool style_value_contains_anchor_function(StyleValue const& value)
{
if (value.is_anchor())
return true;
if (value.is_calculated())
return value.as_calculated().contains_anchor_function();
return false;
}

bool ComputedValues::inset_properties_contain_anchor_functions() const
{
// A bare anchor function is not stored in the inset length box at all: it lives in the
// per-side anchor inset handles kept next to it.
if (has_anchor_inset(PropertyID::Top) || has_anchor_inset(PropertyID::Right)
|| has_anchor_inset(PropertyID::Bottom) || has_anchor_inset(PropertyID::Left))
return true;
// Anchor functions inside expressions survive to used-value time as calculated values, so
// when no inset is calculated (the common case), skip reconstructing the style values.
auto const& inset_box = inset();
if (!inset_box.top().is_calculated() && !inset_box.right().is_calculated() && !inset_box.bottom().is_calculated() && !inset_box.left().is_calculated())
return false;
auto top = computed_style_value(PropertyID::Top);
auto right = computed_style_value(PropertyID::Right);
auto bottom = computed_style_value(PropertyID::Bottom);
auto left = computed_style_value(PropertyID::Left);
VERIFY(top && right && bottom && left);
return style_value_contains_anchor_function(*top)
|| style_value_contains_anchor_function(*right)
|| style_value_contains_anchor_function(*bottom)
|| style_value_contains_anchor_function(*left);
}

RefPtr<StyleValue const> ComputedValues::computed_style_value(PropertyID property_id, WithAnimationsApplied with_animations_applied) const
{
if (with_animations_applied == WithAnimationsApplied::No && m_base_values)
Expand Down
95 changes: 24 additions & 71 deletions Libraries/LibWeb/CSS/ComputedValues.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -751,7 +751,8 @@ void const* style_group_default_payload(size_t group_index)
static auto const default_payloads = [] {
constexpr auto group_count = to_underlying(StyleGroupIndex::Count);
Array<ComputedValuesFFI::StyleGroupVTable, group_count> vtables;
#define LIBWEB_STYLE_GROUP_VTABLE(name) vtables[to_underlying(StyleGroupIndex::name)] = make_style_group_vtable<ComputedValues::name>();
#define LIBWEB_STYLE_GROUP_VTABLE(name, path, sharing_name, affects_layout) \
vtables[to_underlying(StyleGroupIndex::name)] = make_style_group_vtable<ComputedValues::name>();
LIBWEB_ENUMERATE_COMPUTED_VALUE_STYLE_GROUPS(LIBWEB_STYLE_GROUP_VTABLE)
#undef LIBWEB_STYLE_GROUP_VTABLE
Array<void const*, group_count> payloads {};
Expand Down Expand Up @@ -853,34 +854,27 @@ bool ComputedValues::adopt_identical_group_payloads(ComputedValues const& previo
}
all_shared = false;
};
#define LIBWEB_ADOPT_STYLE_GROUP(path) adopt(path, previous.path);
LIBWEB_ADOPT_STYLE_GROUP(m_inherited.table)
LIBWEB_ADOPT_STYLE_GROUP(m_inherited.list)
LIBWEB_ADOPT_STYLE_GROUP(m_inherited.ui)
LIBWEB_ADOPT_STYLE_GROUP(m_inherited.svg)
LIBWEB_ADOPT_STYLE_GROUP(m_inherited.text)
LIBWEB_ADOPT_STYLE_GROUP(m_inherited.box)
LIBWEB_ADOPT_STYLE_GROUP(m_inherited.font)
LIBWEB_ADOPT_STYLE_GROUP(m_noninherited.animation)
LIBWEB_ADOPT_STYLE_GROUP(m_noninherited.box)
LIBWEB_ADOPT_STYLE_GROUP(m_noninherited.surround)
LIBWEB_ADOPT_STYLE_GROUP(m_noninherited.sizing)
LIBWEB_ADOPT_STYLE_GROUP(m_noninherited.misc)
LIBWEB_ADOPT_STYLE_GROUP(m_noninherited.alignment)
LIBWEB_ADOPT_STYLE_GROUP(m_noninherited.border)
LIBWEB_ADOPT_STYLE_GROUP(m_noninherited.background)
LIBWEB_ADOPT_STYLE_GROUP(m_noninherited.transform)
LIBWEB_ADOPT_STYLE_GROUP(m_noninherited.effects)
LIBWEB_ADOPT_STYLE_GROUP(m_noninherited.mask_data)
LIBWEB_ADOPT_STYLE_GROUP(m_noninherited.text_reset)
LIBWEB_ADOPT_STYLE_GROUP(m_noninherited.content_data)
LIBWEB_ADOPT_STYLE_GROUP(m_noninherited.anchor)
LIBWEB_ADOPT_STYLE_GROUP(m_noninherited.grid)
LIBWEB_ADOPT_STYLE_GROUP(m_noninherited.svg_reset)
#define LIBWEB_ADOPT_STYLE_GROUP(name, path, sharing_name, affects_layout) adopt(path, previous.path);
LIBWEB_ENUMERATE_COMPUTED_VALUE_STYLE_GROUPS(LIBWEB_ADOPT_STYLE_GROUP)
#undef LIBWEB_ADOPT_STYLE_GROUP
return all_shared;
}

bool ComputedValues::differs_in_any_layout_affecting_group_payload_from(ComputedValues const& other) const
{
auto differs = []<typename T>(StyleStructRef<T> const& mine, StyleStructRef<T> const& theirs) {
return !mine.ptr_equals(theirs) && !(mine == theirs);
};
#define LIBWEB_COMPARE_STYLE_GROUP(name, path, sharing_name, affects_layout) \
if constexpr (affects_layout) { \
if (differs(path, other.path)) \
return true; \
}
LIBWEB_ENUMERATE_COMPUTED_VALUE_STYLE_GROUPS(LIBWEB_COMPARE_STYLE_GROUP)
#undef LIBWEB_COMPARE_STYLE_GROUP
return false;
}

// https://drafts.csswg.org/css-transforms-2/#grouping-property-values
bool ComputedValues::has_transform_style_grouping_property() const
{
Expand Down Expand Up @@ -935,52 +929,11 @@ bool ComputedValues::has_transform_style_grouping_property() const
void const* ComputedValues::style_group_payload(StyleGroupIndex group) const
{
switch (group) {
case StyleGroupIndex::InheritedTableValues:
return &*m_inherited.table;
case StyleGroupIndex::InheritedListValues:
return &*m_inherited.list;
case StyleGroupIndex::InheritedUIValues:
return &*m_inherited.ui;
case StyleGroupIndex::InheritedSVGValues:
return &*m_inherited.svg;
case StyleGroupIndex::InheritedTextValues:
return &*m_inherited.text;
case StyleGroupIndex::InheritedBoxValues:
return &*m_inherited.box;
case StyleGroupIndex::FontValues:
return &*m_inherited.font;
case StyleGroupIndex::AnimationValues:
return &*m_noninherited.animation;
case StyleGroupIndex::SVGResetValues:
return &*m_noninherited.svg_reset;
case StyleGroupIndex::GridValues:
return &*m_noninherited.grid;
case StyleGroupIndex::AnchorValues:
return &*m_noninherited.anchor;
case StyleGroupIndex::EffectsValues:
return &*m_noninherited.effects;
case StyleGroupIndex::MaskValues:
return &*m_noninherited.mask_data;
case StyleGroupIndex::TextResetValues:
return &*m_noninherited.text_reset;
case StyleGroupIndex::ContentValues:
return &*m_noninherited.content_data;
case StyleGroupIndex::TransformValues:
return &*m_noninherited.transform;
case StyleGroupIndex::BackgroundValues:
return &*m_noninherited.background;
case StyleGroupIndex::BorderValues:
return &*m_noninherited.border;
case StyleGroupIndex::AlignmentValues:
return &*m_noninherited.alignment;
case StyleGroupIndex::MiscResetValues:
return &*m_noninherited.misc;
case StyleGroupIndex::SizingValues:
return &*m_noninherited.sizing;
case StyleGroupIndex::SurroundValues:
return &*m_noninherited.surround;
case StyleGroupIndex::BoxValues:
return &*m_noninherited.box;
#define LIBWEB_STYLE_GROUP_PAYLOAD_CASE(name, path, sharing_name, affects_layout) \
case StyleGroupIndex::name: \
return &*path;
LIBWEB_ENUMERATE_COMPUTED_VALUE_STYLE_GROUPS(LIBWEB_STYLE_GROUP_PAYLOAD_CASE)
#undef LIBWEB_STYLE_GROUP_PAYLOAD_CASE
case StyleGroupIndex::Count:
break;
}
Expand Down
Loading
Loading