Commit graph

147 commits

Author SHA1 Message Date
Simon Wülker
3d320fa96a
Update rustfmt to the 2024 style edition (#35764)
* Use 2024 style edition

Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>

* Reformat all code

Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>

---------

Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
2025-03-03 11:26:53 +00:00
Euclid Ye
28cea920ec
layout: Merge BoxFragment::used_overflow into ComputedValuesExt::effective_overflow (#35670) (#35670)
* Update wpt-test



* Merge used_overflow to effective_overflow; remove duplicate call



* Remove more duplicate calls; update effective_overflow logic



* Update reference link&style



* Apply final review suggestions

Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com>
2025-03-02 21:44:59 +00:00
Oriol Brufau
1966ab182f
layout: Use definite cross size to compute flex base size (#35688)
An intrinsic flex base size depends on the contents, which may depend on
the cross size through an aspect ratio. We were only taking this into
account if the preferred cross size was numeric, but `auto` or `stretch`
can also be definite.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2025-02-27 13:54:44 +00:00
Oriol Brufau
03e953e22c
layout: Support stretch cross size for flex base size (#35663)
The computation of the flex base size may involve transferring a
definite cross size into the main axis through the aspect ratio.
We were only considering numeric sizes as definite, but `stretch` can
also be definite.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2025-02-26 18:03:38 +00:00
Oriol Brufau
6aae4df909
layout: Support stretch cross size for automatic min size in flexbox (#35652)
The computation of the automatic minimum size may involve transferring
a definite cross size into the main axis through the aspect ratio.
We were only considering numeric sizes as definite, but `stretch` can
also be definite.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2025-02-26 16:30:36 +00:00
Oriol Brufau
ebb19bcd60
layout: Change the IndefiniteContainingBlock sizes to Option<Au> (#35653)
Thus avoiding the need to convert to/from `AuOrAuto`.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2025-02-25 14:24:29 +00:00
Oriol Brufau
864a5edb0b
layout: Let automatic_min_size() take a flex-relative cb size (#35642)
This method was taking an `IndefiniteContainingBlock` parameter, and
then it would first take the size corresponding to the main axis, and
then the one for the cross axis.

But it's simpler to just let it take a `FlexRelativeVec2<AuOrAuto>`
parameter.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2025-02-25 08:37:42 +00:00
Simon Wülker
be6765447d
Update to rust 1.85 (#35628)
* Update to rust 1.85

This is needed for cargo-deny

Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>

* Upgrade crown

Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>

* Clippy fixes

Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>

* Re-upgrade cargo-deny to 0.18

Keeping it locked to 0.18 just in case they
update their required rustc version again

Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>

---------

Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
2025-02-24 17:44:35 +00:00
Oriol Brufau
41c2422a66
layout: Ignore indefinite stretch on min and max sizing properties (#35630)
We were always treating an indefinite `stretch` as the automatic size.
This instead treats it as `0px` on min sizing properties, and as `none`
on max sizing properties, aligning with Blink and this recent CSSWG
resolution: https://github.com/w3c/csswg-drafts/issues/11006

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2025-02-24 13:51:08 +00:00
Oriol Brufau
f01d525852
layout: Fully support sizing keywords on main size property of flex item (#35471)
Still lacking support on min and max main size properties, and on the
various cross size properties.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2025-02-17 21:19:50 +00:00
Oriol Brufau
c2224d5afc
layout: Partial support for sizing keywords on flex items (#35469)
* Add tests for sizing keywords on flex items

Signed-off-by: Oriol Brufau <obrufau@igalia.com>

* layout: Partial support for sizing keywords on flex items

When a flex item has `flex-basis: auto`, the used `flex-basis` is the
value of the main size property. In that case, if the main size property
was set to keyword, we were always assuming it was `auto`. Now we handle
non-`auto` keywords correctly.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>

---------

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2025-02-17 17:51:10 +00:00
Oriol Brufau
2b930814d7
layout: Basic implementation of size keywords on flex-basis (#35413)
layout: Basic implementation of size keywords on `flex-basis`

This splits the logic to resolve the used value of `flex-basis` into its
own method, which preserves size keywords.

And then it changes `flex_base_size()` to resolve the provided keywords
properly. However, it doesn't handle size keywords in the cross axis.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2025-02-13 15:24:06 +00:00
TIN TUN AUNG
2030b7affd
layout: align-content with default value normal should behave as strech in flex container (#35178)
Signed-off-by: rayguo17 <rayguo17@gmail.com>
2025-02-03 08:27:55 +00:00
Oriol Brufau
fea8b68860
layout: Remove min and max container sizes from FlexContext (#35144)
Thanks to #34946 we don't have to recompute the min and max sizes, we
can get them from the `ContainingBlock`.

And then in `FlexContext` there is no need to store both the definite
and the min & max sizes of the container`, we can instead make do with
a single `FlexRelativeVec2<SizeConstraint>`.

This removes 1 of the 3 usages of `ContentBoxSizesAndPBMDeprecated`,
which is also good.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2025-01-24 16:11:23 +00:00
Martin Robinson
102b77aef8
Make naming of variables consistent with SpecificLayoutInfo (#35104)
This is a followup to #34926.

Fixes #35078.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
2025-01-21 17:28:14 +00:00
Oriol Brufau
f6c166533e
layout: Respect alignment when sizing replaced abspos (#35085)
If an absolutely position element which is replaced has `justify-self`
or `align-self` set to `stretch`, and no inset is `auto` on that axis,
then an automatic size should behave as `stretch`, not as `fit-content`.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2025-01-20 13:25:00 +00:00
Oriol Brufau
60dc3b26fb
layout: Allow layouts to customize their used style (#35012)
Some layouts like table need some style overrides. We were handling this
in `ComputedValuesExt`, but it was messy, unreliable and too limited.

For example, we were assuming that a style with `display: table` would
belong to a table wrapper box or table grid box. However, certain HTML
elements can ignore their `display` value and generate a different kind
of box. I think we aren't doing that yet, but we will need this.

Also, resolving the used border of a table needs layout information,
which we don't have in `ComputedValuesExt`. This patch will allow to
improve border collapsing in a follow-up.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2025-01-16 16:54:47 +00:00
Oriol Brufau
f66cd172d6
layout: Generalize ContainingBlock's block size to a SizeConstraint (#34946)
It used to be an `AuOrAuto`, turning it into a `SizeConstraint` allows
passing the information about the min and max constraints when the
containing block doesn't have a definite block size.

This will be useful for table layout.

Note that in most cases we were already constructing the containing
block from a `SizeConstraint`, but we were calling `to_auto_or()` to
turn it into an `AuOrAuto`.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2025-01-13 10:25:33 +00:00
Martin Robinson
de780dcde4
layout: Make Fragment hold ArcRefCell inside (#34923)
Push the interior mutability into enum variants of `Fragment`, so that
they can be cloned. This saves memory in the `Fragment` tree as the
`Fragment` enum is now a relatively wee 16 bytes and the interior parts
can be a variety of sizes. Before, every `Fragment` was the size of the
biggest kind (`BoxFragment` - 248 bytes).

This a step on the way toward incremental layout.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
2025-01-13 09:59:59 +00:00
Steven Novaryo
76fa456a9a
layout: grid template getComputedStyle resolved value (#34885)
* Store taffy detailed info into fragment

Signed-off-by: stevennovaryo <steven.novaryo@gmail.com>

* Fix info propagation and resolved grid track query

Signed-off-by: stevennovaryo <steven.novaryo@gmail.com>

* Fix import

Signed-off-by: stevennovaryo <steven.novaryo@gmail.com>

* Fix tracklist matching logic and type optimization

Signed-off-by: stevennovaryo <steven.novaryo@gmail.com>

* Run fmt

Signed-off-by: stevennovaryo <steven.novaryo@gmail.com>

* Update wpt expectations

Signed-off-by: stevennovaryo <steven.novaryo@gmail.com>

* Optimizing info propagation and minor qol

Signed-off-by: stevennovaryo <steven.novaryo@gmail.com>

* Run fmt

Signed-off-by: stevennovaryo <steven.novaryo@gmail.com>

---------

Signed-off-by: stevennovaryo <steven.novaryo@gmail.com>
2025-01-09 10:49:27 +00:00
Martin Robinson
621ddd749c
Elide lifetimes where possible after rustup (#34824)
The new version of rust allows us to elide some lifetimes and clippy is
now complaining about this. This change elides them where possible and
removes the clippy exceptions.

Fixes #34804.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
2025-01-03 18:54:44 +00:00
Oriol Brufau
e2a0ac07ff
Refactor box size computation (#34671)
in each layout logic, in order to correctly resolve sizing keywords.

This patch adds a new `Sizes` struct which holds the preferred, min and
max sizing values for one axis, and unifies the logic to resolve the
final size into there.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2024-12-19 00:52:18 +00:00
Martin Robinson
3e052676ef
script: Manage <iframe> sizes in Window (#34643)
Manage `<iframe>` size updates in `Window`. In addition to removing
duplicated code, this will allow setting `<iframe>` sizes synchronously
on child `Pipeline`s of the same origin in the script process in a
followup change. The goal is remove flakiness from `<iframe>` sizing.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
2024-12-16 15:05:33 +00:00
Oriol Brufau
f7e2ec3a0f
Distinguish cached inline_content_sizes() from uncached ones (#34595)
Several structs and enums had a `inline_content_sizes()` method, but it
wasn't clear which ones would try to cache the result, and which ones
would always compute it.

Therefore, this performs some clarifying renaming:
 - Cached ones stay as `inline_content_sizes()`
 - Uncached ones become `compute_inline_content_sizes()`

Also, to simplify calls to `LayoutBoxBase::inline_content_sizes()`,
`compute_inline_content_sizes()` is moved into a new trait.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2024-12-12 15:39:51 +00:00
Oriol Brufau
41e3c321e5
Make sure to cache inline_content_sizes() (#34586)
The refactoring in 264c0f972f stopped
caching the `inline_content_sizes()` calls from:
- `FlexItemBox::layout_for_block_content_size()`
- `IndependentFormattingContext::layout_float_or_atomic_inline()`
- `TaffyContainerContext::compute_child_layout()`

Also, the call from `OutsideMarker::layout()` was never cached.

This patch caches all of them.

It's not clear at all which `inline_content_sizes()` are cached and
which aren't, so I plan to improve the situation in a follow-up.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2024-12-12 01:37:05 +00:00
Martin Robinson
f1b8d49e77
layout: Make a new ContainingBlockSize type (#34565)
This might make caching these values a bit easier in the future.
Correcting the visibility of `ContainingBlock` also exposed some new
rustc and clippy warnings that are fixed here.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
2024-12-11 14:40:04 +00:00
Martin Robinson
264c0f972f
layout: Add LayoutBoxBase and use it for IndependentFormattingContext (#34507)
Add a new struct `LayoutBoxBase`, that will be used throughout the box
tree. The idea of this struct is that we have a place to consistently
store common layout information (style and node information) and also to
cache layout results such as content sizes (inline and maybe later box
sizes) and eventually layout results.

In addition to the addition of this struct,
`IndependentFormattingContext` is flattened slightly so that it directly
holds the contents of both replaced and non-replaced elements.

This is only added to independent formatting contexts, but will later be
added to all block containers as well.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
2024-12-07 19:12:25 +00:00
Oriol Brufau
0be5209003
Improve performance of flex column layouts by caching (#34461)
* Obey min and max properties when computing main size of column flex

When laying out a column flex container with an auto preferred main size,
we were resolving the used main size to the intrinsic max-content size.
However, we weren't clamping this amount between the min and max sizes.

Co-authored-by: Martin Robinson <mrobinson@igalia.com>
Signed-off-by: Oriol Brufau <obrufau@igalia.com>

* Improve performance of flex column layouts by caching

We were already using a cache for layout_for_block_content_size(), but
we were only storing the intrinsic block size. Thus when laying out the
flex items for real, we would perform new layouts, triggering an
exponential complexity in case of nested flexboxes.

Now we cache the entire layout result so that we can avoid doing the
work again.

This improves the results of flexbox-deeply-nested-column-flow.html
(a Blink perf test) from ~40 runs/second to ~500 runs/second on my PC.

Co-authored-by: Martin Robinson <mrobinson@igalia.com>
Signed-off-by: Oriol Brufau <obrufau@igalia.com>

---------

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
2024-12-03 12:35:24 +00:00
Oriol Brufau
ad448da7de
Obey min and max properties when computing main size of column flex (#34450)
When laying out a column flex container with an auto preferred main size,
we were resolving the used main size to the intrinsic max-content size.
However, we weren't clamping this amount between the min and max sizes.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
2024-12-02 22:14:54 +00:00
Oriol Brufau
19a7e95a6a
Refactor computation of preferred aspect ratios (#34416)
* Refactor computation of preferred aspect ratios

Computing min/max-content sizes required a ContainingBlock in order to
resolve the padding and border when determining the preferred aspect
ratio. However, all callers already knew the padding and border, so they
can compute the ratio themselves, and pass it directly instead of
the ContainingBlock.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>

* Put preferred aspect ratio into ConstraintSpace

Signed-off-by: Oriol Brufau <obrufau@igalia.com>

---------

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2024-11-29 11:40:52 +00:00
Oriol Brufau
a37ccc3e64
Use natural ratio for object-fit (#34413)
We were using the preferred aspect ratio provided by the `aspect-ratio`
property instead of the natural aspect ratio. However, the preferred
aspect ratio should only be used to size the replaced element. To paint
the replaced contents into that element we need the natural ratio.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2024-11-28 12:57:38 +00:00
Delan Azabani
d65a2e9797
Additional tracing for flex layout, inline layout, and fonts (#34392)
Signed-off-by: Delan Azabani <dazabani@igalia.com>
2024-11-27 02:44:06 +00:00
Oriol Brufau
ba061ec2b0
Refine logic for laying out flex item in column layout after #34346 (#34372)
- Clamp the stretch size to not be negative when the sum of padding,
  borders and margins exceed the available space. This avoids a 2nd
  layout.
- Avoid computing the inline content sizes if the result isn't needed.
- Instead of clamping both the min-content and max-content sizes to be
  between the min and max constraints, just compute the fit-content size
  first, and then clamp. Then `ContentSizes::map()` can be removed.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2024-11-25 16:17:54 +00:00
Oriol Brufau
f943ba023a
Improve performance of column flexboxes (#34346)
If a flex item in a single-line column flex container stretches, then
we can know its final size. So instead of first laying it out using its
intrinsic inline size, and then stretching it later, we can use the
correct size from the very beginning.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
2024-11-22 22:52:47 +00:00
Delan Azabani
caf2467649
Set all tracing spans to trace level for now (#34256)
* Clean up tracing instrumentation

Signed-off-by: Delan Azabani <dazabani@igalia.com>

* Set all tracing spans to trace level for now

Signed-off-by: Delan Azabani <dazabani@igalia.com>

---------

Signed-off-by: Delan Azabani <dazabani@igalia.com>
2024-11-19 02:53:43 +00:00
Oriol Brufau
9102644470
Use a RwLock to cache inline_content_sizes() (#34232)
In order to support size keywords in block layout, we may need to call
`inline_content_sizes()` in order to compute the min/max-content sizes.
But this required a mutable reference in order the update the cache,
and in various places we already had mutable references.

So this switches the cache into a RwLock to avoid needing mutable refs.
Note OnceCell wouldn't work because it's not thread-safe.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2024-11-13 09:56:02 +00:00
Oriol Brufau
b28260aa13
Fix inline content sizes of intrinsic element with indefinite block size (#34152)
To compute the min-content and max-content inline sizes of a replaced
element, we were only using the aspect ratio to transfer definite block
sizes resulting from clamping the preferred block size between the min
and max block sizes.

However, if the preferred block size is indefinite, then we weren't
transfering the min and max through the aspect ratio.

This patch adds a `SizeConstraint` enum that can represent these cases,
and a `ConstraintSpace` struct analogous to `IndefiniteContainingBlock`
but with no inline size, and a `SizeConstraint` block size.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2024-11-11 11:38:19 +00:00
Martin Robinson
f4cc20f7ef
layout: Fix caching of streching flex items in row flex (#34162)
When a flex item stretches in the cross axis in a row flex, the flex
container layout should depend on block constraints. In this case the
cross axis is the block axis (assuming horizontal writing modes --
vertical are not yet supported). This changes fixes an issue where the
cached layout was used in this case when stretching should trigger a new
layout.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
2024-11-08 16:59:23 +00:00
Martin Robinson
a61522a1e8
layout: Clean up the flexible length resolution algorithm (#34153)
Instead of doing so much zipping, which is confusing, create a temporary
data structure for each item that holds all relevant information. In
addition, add detailed specification text so it is easier to understand
what is going on.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
2024-11-06 09:54:20 +00:00
Oriol Brufau
ee7b207f96
Implement keyword sizes for replaced elements (#34091)
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2024-11-05 13:46:58 +00:00
Martin Robinson
3289e7d84d
layout: Properly calculate free space in flexbox flexible length resolution (#34150)
Previously, when there were no more violations, the returned value for
line free space was incorrect for flexible length resolution. It was
returning the container main space minus the inner length of each item.
Free space is determined by the outer length though. Fix this by reusing
the `free_space()` function, but with an argument indicating that all
items are now frozen.

Fixes #34079.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
2024-11-05 13:32:34 +00:00
Martin Robinson
fe0701e226
layout: Add parallel layout to flexbox (#34132)
This adds parallelism using rayon to the initial layout of flex lines
and line item. There is still no support for parallelism when laying out
line items again to account for stretch. This can be done in a followup
change.

In addition, the array of data for each line item is collected into a
new structure, `FlexLineItem`. This prevents a lot of needless zipping
of iterators at the expense of some new vector allocations. A folluwup
change can likely unify this structure and `FlexItemLayoutResult` though
that will require a larger refactor.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
2024-11-05 11:48:27 +00:00
Martin Robinson
f151cdf6ee
layout: Remove an obselete comment from flexbox (#34148)
This behavior is handled properly in `style_ext.rs`.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
2024-11-05 09:50:22 +00:00
Oriol Brufau
072ff302d2
Replace ComputedValues with WritingMode on IndefiniteContainingBlock (#34090)
We only need the writing mode, not the entire computed style.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
2024-11-04 18:00:58 +00:00
Martin Robinson
52db185568
layout: Avoid layout sometimes when stretching (#33967)
This is the second flexbox caching change. It seeks to detect when a
relayout can be avoided in the case of a stretching flex item. This
heuristic can be combined, because currently we still do relayout
sometimes when we do not need to.

For instance currently we always relayout when a flex child is itself a
column flex. This only needs to happen when the grandchildren themselves
grow or shrink. That optimization is perhaps a lower priority as
`flex-grow: 0 / flex-shrink: 1` is the default behavior for flex.

Since this change means we more consistenly zero out the percentage part
of `calc` expressions when they have circular dependencies, this causes one
test to start failing (`/css/css-values/calc-min-height-block-1.html`).
This is related to w3c/csswg-drafts#10969, which is pending on further
discussion in the working group.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
2024-10-24 17:44:30 +00:00
Martin Robinson
01c9ecfe01
layout: Cache content block size contributions (#33964)
This is the first part of caching intermediary layout during flexbox
layout. A later change will try to reuse these layouts, when possible,
for actual item layout and re-layout due to stretching.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
2024-10-22 14:43:53 +00:00
Delan Azabani
fa1f7e5839
Gate all use of tracing behind Cargo feature (#33845)
Signed-off-by: Delan Azabani <dazabani@igalia.com>
2024-10-16 10:24:24 +00:00
Oriol Brufau
b9ed45942d
Avoid recomputing inline_content_sizes() when not needed (#33806)
The result of `inline_content_sizes()` may depend on the block size of
the containing block, so we were always recomputing in case we got
a different block size.

However, if no content has a vertical percentage or stretches vertically,
then we don't need to recompute: the result will be the same anyways.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
2024-10-14 16:06:27 +00:00
tanishka
091b8ecda0
layout: Handle inline margins in layout_for_block_content_size() (#33780)
* fix: Handle inline margins in layout_for_block_content_size()

Signed-off-by: taniishkaaa <tanishkasingh2004@gmail.com>

* Update test expectations

Signed-off-by: taniishkaaa <tanishkasingh2004@gmail.com>

---------

Signed-off-by: taniishkaaa <tanishkasingh2004@gmail.com>
2024-10-10 20:45:18 +00:00
Adavize Promise
52cddb45bd
Use content_box_sizes_and_padding_border_margin_deprecated() in FlexItem::new() (#33754)
* Use content_box_sizes_and_padding_border_margin_deprecated() in FlexItem::new()

Signed-off-by: PS Adavize <siyakapromise@gmail.com>

* remove unnecessary variable declaration declaration

Signed-off-by: PS Adavize <siyakapromise@gmail.com>

* Remove redundant variable pbm

Signed-off-by: PS Adavize <siyakapromise@gmail.com>

---------

Signed-off-by: PS Adavize <siyakapromise@gmail.com>
2024-10-10 11:13:48 +00:00