Commit graph

74 commits

Author SHA1 Message Date
BenJilks
11e7d72686 LibWeb: Layout text chunks based on their Unicode direction
Some checks are pending
CI / Lagom (false, FUZZ, ubuntu-22.04, Linux, Clang) (push) Waiting to run
CI / Lagom (false, NO_FUZZ, macos-14, macOS, Clang) (push) Waiting to run
CI / Lagom (false, NO_FUZZ, ubuntu-22.04, Linux, GNU) (push) Waiting to run
CI / Lagom (true, NO_FUZZ, ubuntu-22.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (macos-14, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (ubuntu-22.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Push notes / build (push) Waiting to run
Append text chunks to either the start or end of the text fragment,
depending on the text direction. The direction is determined by what
script its code points are from.
2024-08-31 11:49:47 +02:00
Aliaksandr Kalenik
7181c3f2ea Everywhere: Limit layout text fragments to use one font for all glyphs
The ChunkIterator now limits a chunk to using only one font (before, it
was possible to have a chunk with >1 font, when `unicode-range` CSS
property is used).

This change allows us to reduce some complexity in the text shaping and
painting code and makes us compatible with the APIs in Skia and
HarfBuzz.
2024-06-30 19:23:24 +02:00
Matthew Olsson
31341b280a LibWeb: Add calls to JS_{DECLARE,DEFINE}_ALLOCATOR() 2024-04-09 09:13:06 +02:00
Andreas Kling
dd8504c68d LibWeb: Store "text for rendering" in TextPaintable
Instead of TextPaintable fragments being an offset+length view into the
layout node, they are now a view into the paintable instead.

This removes an awkward time window where we'd have bogus state in text
fragments after layout invalidation but before relayout. It also makes
the code slightly nicer in general, since there's less mixing of layout
and painting concepts.
2024-03-18 13:42:16 +01:00
Shannon Booth
56d10bf198 LibWeb: Port Layout::TextNode from DeprecatedString 2023-11-28 17:15:27 -05:00
Ali Mohammad Pur
aeee98b3a1 AK+Everywhere: Remove the null state of DeprecatedString
This commit removes DeprecatedString's "null" state, and replaces all
its users with one of the following:
- A normal, empty DeprecatedString
- Optional<DeprecatedString>

Note that null states of DeprecatedFlyString/StringView/etc are *not*
affected by this commit. However, DeprecatedString::empty() is now
considered equal to a null StringView.
2023-10-13 18:33:21 +03:30
Cr4xy
bbfe0d3a82 LibWeb: Implement text-transform: capitalize 2023-10-03 09:47:17 -04:00
Shannon Booth
b603e860af LibWeb: Port CharacterData from DeprecatedString to String
The existing implementation has some pre-existing issues where it is
incorrectly assumes that byte offsets are given through the IDL instead
of UTF-16 code units. While making these changes, leave some FIXMEs for
that.
2023-09-19 10:54:07 +02:00
Sam Atkins
489f9c3151 LibWeb: Implement text-transform: math-auto
This is a simple mapping of some code-points to others.

I was going to use a ref test for this, but without knowing that the
font contains the code-points (which SerenitySans does not) we'd be
comparing a series of replacement characters to a series of replacement
characters, which doesn't tell you if they're the right code-points
underneath.
2023-09-11 17:03:22 +01:00
Sam Atkins
ce775ea701 LibWeb: Use a switch to handle TextTransform values
This makes it more obvious that we're missing some of these. (And makes
it easier to find this code when searching for a specific value.)
2023-09-11 17:03:22 +01:00
Andreas Kling
1c47695bae LibWeb: Invalidate layout-transformed text on DOM text node change
This fixes an issue where programmatically changing the value of an
input element wasn't reflected visually.
2023-08-16 12:16:05 +02:00
Karol Kosek
d4b5205482 Revert "LibWeb: Make TextNode::ChunkIterator emit an empty chunk for content:"""
This reverts commit b062a0fb7c.

This made a calculation of pseudo-elements' height incorrect when they
had `height` set to `auto` and used other techniques (like setting
`padding-top`) to set height, as it was now also adding an empty line.

Additionally, the case didn't work for content containing whitespace
characters, so a pseudo-element with `content: " "` didn't have *this*
particular problem.
2023-08-02 17:35:54 +02:00
Andreas Kling
b918ce4022 LibWeb: Make Layout::TextNode::text_for_rendering() lazily computed
As it turns out, Layout::TreeBuilder never managed to wrap text within
table boxes in anonymous wrapper boxes, since it relied on checking
text_for_rendering(), and that was never initialized during that early
stage of tree building.

This patch fixes the issue by making text_for_rendering() compute the
(potentially collapsed) text lazily when called.

Note that the test included with this patch is still totally wrong,
but that is now a TFC problem rather than a TreeBuilder problem. :^)
2023-07-03 11:50:58 +02:00
Andreas Kling
4d401bf796 LibWeb: Make the paint tree GC-allocated
This simplifies the ownership model between DOM/layout/paint nodes
immensely by deferring to the garbage collector for figuring out what's
live and what's not.
2023-01-11 12:55:00 +01:00
Timothy Flynn
1ff29afc45 LibUnicode+LibJS+LibWeb: Propagate OOM from Unicode case transformations 2023-01-09 22:48:15 +00:00
Andreas Kling
32e35a02f9 LibWeb: Apply CSS text-transform during layout
Previously we were doing this at the painting stage, which meant that
layout potentially used the wrong glyphs when measuring text.

This would lead to incorrect layout metrics and was visible on the
HTML5Test score display, for example. :^)
2022-12-24 12:27:46 +01:00
Linus Groh
57dc179b1f Everywhere: Rename to_{string => deprecated_string}() where applicable
This will make it easier to support both string types at the same time
while we convert code, and tracking down remaining uses.

One big exception is Value::to_string() in LibJS, where the name is
dictated by the ToString AO.
2022-12-06 08:54:33 +01:00
Linus Groh
6e19ab2bbc AK+Everywhere: Rename String to DeprecatedString
We have a new, improved string type coming up in AK (OOM aware, no null
state), and while it's going to use UTF-8, the name UTF8String is a
mouthful - so let's free up the String name by renaming the existing
class.
Making the old one have an annoying name will hopefully also help with
quick adoption :^)
2022-12-06 08:54:33 +01:00
Andreas Kling
5839ef2ed8 LibWeb: Render text inside <input type=password> as asterisks (*)
This makes it possible to enter passwords while recording YouTube
videos. :^)
2022-11-05 18:54:39 +01:00
Andreas Kling
b062a0fb7c LibWeb: Make TextNode::ChunkIterator emit an empty chunk for content:""
This ensures that we create a line box for content:"", which would
otherwise get pruned by the empty line cleanup in IFC.

The empty line box is important in this case, since it gives us a
reference point for measuring the automatic height of the IFC's
containing block. By having an empty line, we can now correctly measure
the impact of vertical margins on a generated box with content:""
and allow them to contribute to the block height.
2022-10-14 19:50:15 +02:00
Andreas Kling
063d6cab8b LibWeb: Remove unused Layout::TextNode::ChunkIterator::m_layout_mode 2022-10-14 19:50:15 +02:00
Andreas Kling
a0e6882d99 LibWeb: Remove Layout::Node::set_inline()
Now that this flag is no longer used, we can stop setting it.
2022-10-06 15:29:38 +02:00
Andreas Kling
64959a8504 LibWeb: Express intrinsic size layout via size constraints
Previously, we had three layout modes:

- Normal:
    - Everything uses the computed values from CSS.

- MinContent:
    - Containing blocks act as if they have 0 width.
    - All line breaking opportunities are taken.

- MaxContent:
    - Containing blocks act as if they have infinite width.
    - Only forced line breaks are accepted.

The above was based on a set of misunderstandings of CSS sizing.
A major problem with the above was that *all* containing blocks
behaved differently during intrinsic size layout, not just the
relevant one.

With this patch there are only two layout modes:

- Normal:
    - Everything uses the computed values from CSS.

- IntrinsicSizeDetermination:
    - One or more boxes have size constraints applied.

There are two size constraints per layout box, set here:

- FormattingState::NodeState::width_constraint
- FormattingState::NodeState::height_constraint

They are of type SizeConstraint and can be one of None, MinContent,
or MaxContent. The default is None.

When performing an IntrinsicSizeDetermination layout, we now assign
a size constraint to the box we're trying to determine the intrinsic
size of, which is then honored by using two new helpers to query
the dimensions of containing blocks:

- FormattingContext::containing_block_width_for(Box)
- FormattingContext::containing_block_height_for(Box)

If there's a relevant constraint in effect on the Box, the size of
its containing block is adjusted accordingly.

This is essentially an implementation of the "available space"
constraints from CSS-SIZING-3. I'm sure some things will break from
this, and we'll have to deal with that separately.

Spec: https://drafts.csswg.org/css-sizing-3/#available
2022-07-11 18:57:45 +02:00
Andreas Kling
03008d9c9c LibWeb: Ensure that TextNode::ChunkIterator emits preserved newlines
When doing max-content layout, we were not committing newlines even
though we were supposed to due to white-space:pre*.

This broke the WPT harness due to a VERIFY() in ChunkIterator where we
were assuming the commit would always succeed.

Thanks to Orphis for reporting this! :^)
2022-03-29 03:05:11 +02:00
Andreas Kling
4575ab558b LibWeb: Make whitespace collapsing stateless
Previously, the whitespace collapsing code had a parameter telling it
whether the previous text node ended in whitespace. This was not
actually necessary, so let's get rid of it.
2022-03-27 21:56:21 +02:00
Andreas Kling
fa99259412 LibWeb: Simplify text chunk iteration a little bit
Instead of TextNode::ChunkIterator having two bool members to remember
things across calls to next(), this patch reorganizes the loop in next()
so that preserved newline/whitespace chunks are emitted right away
instead of in an awkward deferred way.
2022-03-26 20:04:56 +01:00
Andreas Kling
c1f0d21bbe LibWeb: Rename the LayoutMode enum values and explain them
The old mode names, while mechanically accurate, didn't really reflect
their relationship to the CSS specifications.

This patch renames them as follows:

    Default => Normal
    AllPossibleLineBreaks => MinContent
    OnlyRequiredLineBreaks => MaxContent

There's also now an explainer comment with the LayoutMode enum about the
specific implications of layout in each mode.
2022-03-19 15:46:15 +01:00
Lenny Maiorani
c37820b898 Libraries: Use default constructors/destructors in LibWeb
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#cother-other-default-operation-rules

"The compiler is more likely to get the default semantics right and
you cannot implement these functions better than the compiler."
2022-03-17 17:23:49 +00:00
Andreas Kling
be5f0b5ac4 LibWeb: Move text fragment painting to PaintableWithLines
All the other painting code has moved to paintables already.
2022-03-16 23:13:05 +01:00
Andreas Kling
e099960e4d LibWeb: Remove a bunch of no-longer needed #includes 2022-03-11 00:21:49 +01:00
Andreas Kling
cb0c5390ff LibWeb: Move mouse event and label logic from layout to painting tree
Input events have nothing to do with layout, so let's not send them to
layout nodes.

The job of Paintable starts to become clear. It represents a paintable
item that can be rendered into the viewport, which means it can also
be targeted by the mouse cursor.
2022-03-11 00:21:49 +01:00
Andreas Kling
ed84fbce47 LibWeb: Make Paintable ref-counted
This will allow us to use a protective NonnullRefPtr to keep paintables
alive while running arbitrary JavaScript in response to events.
2022-03-11 00:21:49 +01:00
Andreas Kling
4d98851aea LibWeb: Generate a TextPaintable for every Layout::TextNode
This is prep work for moving event handling over to the painting tree.
2022-03-11 00:21:49 +01:00
Andreas Kling
02b316fd5c LibWeb: Let Paintable perform the painting
This patch adds a bunch of Paintable subclasses, each corresponding to
the Layout::Node subclasses that had a paint() override. All painting
logic is moved from layout nodes into their corresponding paintables.

Paintables are now created by asking a Layout::Box to produce one:

    static NonnullOwnPtr<Paintable> Layout::Box::create_paintable()

Note that inline nodes still have their painting logic. Since they
are not boxes, and all paintables have a corresponding box, we'll need
to come up with some other solution for them.
2022-03-11 00:21:49 +01:00
Andreas Kling
f0d833a3d7 LibWeb: Move StackingContext and PaintPhase into the Painting namespace 2022-03-11 00:21:49 +01:00
Maciej
86c0961240 LibWeb: Make TextNode::ChunkIterator::try_commit_chunk() const 2022-03-07 21:49:36 +01:00
Karol Kosek
7e599aa1e5 LibWeb: Implement missing text-decoration styles
This commit will draw appropriate line styles for the Double, Dashed
and Dotted values.
2022-03-06 22:04:41 +01:00
Karol Kosek
b6b116d5f2 LibWeb: Compute text-decoration-thickness values 2022-03-06 22:04:41 +01:00
Karol Kosek
727e69fe11 LibWeb: Paint text decoration in front of the text
Previously, the decoration was painted behind the text. This probably
wasn't noticed before, as we didn't compute `text-decoration-color`
values yet and the decoration had the same color anyway.
2022-03-06 22:04:41 +01:00
Karol Kosek
f9d66bef5d LibWeb: Compute text-decoration-color values
Previosly, we used only the text color as a line decoration color.

The FIXME comment has been directly copy-pasted from the border color
note a few lines below.
2022-03-06 22:04:41 +01:00
Andreas Kling
e61bf997db LibWeb: Don't break on *every character* in AllPossibleLineBreaks mode
This mode is used to find the min-content inline size, so we should
break between words, not characters.
2022-03-05 21:26:19 +01:00
Andreas Kling
8daf603f46 LibWeb: Paint full bitmap font glyphs, even if there's overlap
Since we now honor the CSS font-size values when deciding line box
metrics, we sometimes find ourselves needing to paint text with a bitmap
font into a box that isn't large enough for the glyphs.

As it turns out, it looks a bit better if we just grow the paint rect to
fit the glyphs (instead of painting chopped-off glyphs.) So let's just
do that for now.
2022-02-26 09:32:52 +01:00
Andreas Kling
e91b2c57c1 LibWeb: Allow label activation via any descendant of the label node
Previously we were only forwarding the activation to the labelled
control if the user clicked on an immediate child of <label>.
2022-02-15 23:24:41 +01:00
Tobias Christiansen
3b877c889b LibWeb: Consider TextDecorationStyle when rendering text
For now only Wavy is additionally supported, but the infrastructure is
there.
2022-01-23 15:48:27 +03:30
Andreas Kling
766d816db3 LibWeb: Remove old Layout::Node::split_into_lines() API
Now that we build lines incrementally, we no longer need the atomic line
splitting API.

The new InlineLevelIterator and LineBuilder setup does have some
regressions from the old behavior, but we can deal with them as we go.
2022-01-23 01:22:41 +01:00
Andreas Kling
7c57961c61 LibWeb: Move BrowsingContext into HTML/
Browsing contexts are defined by the HTML specification, so let's move
them into the HTML directory. :^)
2021-11-18 21:11:30 +01:00
Andreas Kling
8b1108e485 Everywhere: Pass AK::StringView by value 2021-11-11 01:27:46 +01:00
Felix Rauch
30c39e0e41 LibWeb: Fix inline blocks swallowing trailing whitespace
In #10434 an issue with leading whitespace in new lines after
a <br> element was fixed by checking whether the last fragment
of LineBox is empty.

However, this introduced a regression by which whitespace following
inline elements was swallowed, so `<b>Test</b> 123` would appear
like `Test123`.

By asking specifically if we are handling a forced linebreak
instead of implicity asking for a property that may be shared by
other Node types, we can maintain the correct behavior in regards
to leading whitespace on new lines, as well as trailing whitespace
of inline elements.
2021-10-26 17:27:04 +02:00
Nico Weber
b8dc3661ac Libraries: Fix -Wunreachable-code warnings from clang 2021-10-08 23:33:46 +02:00
Andreas Kling
c4826eae4f LibWeb: Rename Layout::BlockBox => BlockContainer
There's a subtle difference here. A "block box" in the spec is a
block-level box, while a "block container" is a box whose children are
either all inline-level boxes in an IFC, or all block-level boxes
participating in a BFC.

Notably, an "inline-block" box is a "block container" but not a "block
box" since it is itself inline-level.
2021-10-06 20:10:36 +02:00