`Gfx::Vector[2,3,4]` are nearly identical implementations. This code
redundancy does not follow the DRY (Don't Repeat Yourself) principle
leading to possible out-of-sync errors between the classes.
Combining these classes into a class template which can be specialized
for each needed size makes the differences obvious through
`constexpr-if` blocks and `requires` clauses.
When calculating the intrinsic width of a block-level box, we were
previously measuring the content boxes of children. This meant that
shrink-to-fit sized blocks didn't gain enough width to contain children
with horizontal padding and/or border.
A button that is "mimic pressed" is drawn like it is being clicked when
it isn't necessarily actually being pressed. This lets programs which
keyboard based input that mirrors a button to show visual feedback when
a key is pressed.
Services expect cookies to be submitted with forms, especially login
screens.
Allows us to sign in to GitHub (including two factor authentication)
and start using it!
Build the final custom property map right away instead of first making
a temporary pointer-only map. We also precompute the final needed
capacity for the map to avoid incremental rehashing.
GL_LINEAR_MIPMAP_NEAREST means choose nearest mipmap level, interpolate
texels linearly.
GL_NEAREST_MIPMAP_LINEAR means choose the two closest mipmap levels,
sample the texels unfiltered and linearly interpolate based on the
fractional value of the mipmap level.
Previously we had this backwards.
Until now, we've been treating the bottom of every line box fragment as
its baseline, and just aligning all the bottoms to the bottom of the
line box. That gave decent results in many cases, but was not correct.
This patch starts moving towards actual baseline calculations as
specified by CSS2.
Note that once layout is finished with a line box, we also store the
baseline of the line box in LineBox::m_baseline. This allows us to align
the real baseline of display:inline-block elements with other inline
content on the same line.
Some services using WebSockets require that the request contains the
Origin header, otherwise these services will return a 403 Forbidden
response. WebSocketServer already supports sending the Origin header,
however LibWeb did not send the origin with the IPC request.
I also added a common interface with StringView compatible parameters:
int serenity_setenv(const char*, ssize_t, const char*, ssize_t, int)
This function is called by both C and C++ API for setenv().
We were mixing up the "name character" and "name start character"
validation checks. Also, we were not checking the first character after
a colon against the "name start character" set.
I was wrong in 56df05ae44, there are
situations where floating children should not affect the auto height of
their parent.
It turns out we were using the "height:auto for BFC roots" algorithm for
all height:auto blocks. This patch fixes that by splitting it into two
separate functions, and implementing most of the two different variants.
Note that we don't support vertical margin collapsing here yet.
Thanks to Tim for noticing the error! :^)
This allows us to submit forms from <button> elements and not just
<input type="submit">
This allows Discord to progress past the username registration :^)
This makes it available for all form associated elements and not just
select and input elements. It also makes it more spec compliant,
especially around the form attribute.
The main thing missing is re-associating form elements with a form
attribute when the form attribute changes or an element with an ID
is inserted/removed or has its ID changed.
A top level browsing context is a browsing context with no parent
browsing context.
However, we considered a top level browsing context to be a browsing
context with no associated browsing context container.
If an element with height:auto has any floating descendants whose bottom
margin edge is below the element's bottom content edge, then the height
is increased to include those edges.
Before this patch, we were stopping at the bottom *content* edge of
floating descendants.
Just like Dr. POSIX ordered. Move the macro where it belongs, but make
sure it's visible to Userland files compiled with -DKERNEL. Parts of
LibEDID that are compiled into the Kernel use offsetof to parse the
EDID information given to us by hardware.
POSIX doesn't tell us to export a macro like this, and it's largely
going to never be defined when compiling a serenity-native C++ file,
since AK defines it already.
This does raise a strange issue where some futex-related helpers in
serenity.h are declared with ALWAYS_INLINE. Whether these helpers belong
in a C-visible header as file-static methods is questionable, but let's
work around the issue but adding some preprocessor magic to make sure
these declarations get the behavior they used to have without leaking
macros.
Before this the event loop was spun until the state of the promise was
not pending, however it is possible that a promise has already been
fulfilled/rejected when awaiting it. This could then lead to a crash
below as it would not pump the event loop in such cases.
Although this change is in LibJS, it really only impacts any usage of
LibJS within a EventLoop environment such as LibWeb.
Instead of checking the state of the promise we know check that success
has a value which can only happen if either the fulfilled or rejected
closure set up by await are called.
This patch begins the support for the 'view-box' attribute that can be
attached to <svg>'s.
The FormattingContext determines the size of the Element according to
the specified 'width' and 'height' or if they are not given by the
'viewbox' or by the bounding box of the path if nothing is specified.
When we try to paint a SVG Path that belongs to a <svg> that has the
'view-box' and a specified 'height'/'width', all the parts of the path
get scaled/moved accordingly.
There probably are many edge cases and bugs still to be found, but this
is a nice start. :^)
Previously we used a native ui button to draw the buttons.
These buttons can however not be styled with css.
To allow these to be styled with css, we create a button with
the UA stylesheet that resembles the system ui button.
Instead of making a full copy of every NodeState when cloning a
FormattingState, we make NodeState ref-counted and implement a basic
copy-on-write mechanism.
FormattingState::get_mutable() now makes a deep copy of the NodeState
when first accessed *if* it is shared with other FormattingStates.
We'll have to do something more proper to support this scenario
eventually, but for now let's at least not crash just because somebody
put an SVG <path> inside an HTML element.
Let's have one function that determines the type of transformation
needed, and another to actually perform the transformation.
This makes it much easier to read, and we don't have to duplicate the
logic for doing the transformation.
We now consider a layout box as having definite size in these cases:
- The size is a <length>.
- The size is a <percentage> and the containing block has definite size.
This is not complete, but a bit more accurate than what we had before.
Previously we were computing the bottom edge of a line box by finding
the bottommost fragment on the line.
That method didn't give correct results for line boxes with no fragments
(which is exactly what you get when inserting a bunch of <br> elements.)
To cover all situations, we now keep track of the bottommost edge in the
LineBox object itself.
Using WeakPtr to remember which LineBoxFragment owns which Box was
imposing some annoying constraints on the layout code. Importantly, it
was forcing us to heap-allocate fragments, which makes it much harder to
clone a FormattingState.
This patch replaces the WeakPtr with a coordinate system instead.
Fragments are referred to by their line box index + fragment index
within the line box.
The last commit fixes a bug, but also exposes the fact that trailing
space highlighting isn't really supported on multiple lines. This patch
correct the wrong behavior by adding an offset to adjust rectangle's
position.
Before this patch the highlighted rectangle wasn't placed on the right
spot. Now the red highlighting is correctly placed at the end of the
line. This was due to a function called with a wrong argument.
This doesn't affect the parameter's own behavior but is part of the
parameter meta-data, just as the name. If a parameter is logarithmic,
UI elements should represent it with an interface that scales
logarithmically.
Previously we didn't set the end position for the return type node of
function FunctionType nodes.
This caused a VERIFY failure crash when dumping an AST that contains
such nodes.
After the kill_line (^U) command was used, searching backwards in the
history would still filter based on the text previous to the deletion.
Update the inline search cursor like already done in other internal
functions, so the text used for search is the current one.
CRC32 table is generated at compile-time and put into a static
variable in the header file. This can be moved to be a function
instead of a class, be moved to the `.cpp` file` and generated as an
array instead of a class which only implements `operator[]`.
Of course, Buffer is going to be removed very soon, but much of the
WavLoader behavior still depends on it. Therefore, this intermediary
API will allow adopting the Loader infrastructure without digging too
deep into the WavLoader legacy code. That's for later :^)
The Buffer files had contained both the ResampleHelper and the
sample format utilities. Because the Buffer class (and its file) is
going to be deleted soon, this commit separates those two things into
their own files.
The data is taken straight from the ISO/IEC 11172-3 standard. For
decoding efficiency the tables are transformed into trees at compile
time using a constexpr approach. That way no runtime initialization is
necessary and decoding can be faster than searching through tables.
The primary benefit of this is that it's unsigned, as you can't have a
negative amount of children. Plus, all the users of child_count expect
it to be size_t.
We now validate that the provided tag names are valid XML tag names,
and otherwise throw an "invalid character" DOM exception.
2% progression on ACID3. :^)
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.
If vertical-align is a length value, we lift each line box fragment that
far from the baseline of the line box.
This is rather messy, and we'll have to improve factoring as we add
support for more alignment types.
The purpose of "entering" a box is to collect box model metrics that
apply to content fragments within the box. However, inline-blocks are
special, in that their inner content does not directly participate in
the inline formatting context outside it.
We were neglecting to pop nodes from the box model stack. The metrics
were already being zeroed out when used, but let's not grow the stack
needlessly.
Instead of just the outline, fill them with some semi-transparent color.
Also add tag name, ID, classes and coordinates to the little tooltip.
Finally, use the border box instead of the context box for metrics,
same as other browsers.
Instead of awkwardly visiting and mutating lengths inside StyleValues,
we now simply create a new StyleValue instead.
This fixes an issue where inherited relative lengths could get
absolutized using a parent as reference, and then not having the correct
values when used in a child context.
Note that we implement .elements as a HTMLCollection for now, instead of
the correct HTMLFormControlsCollection subclass. This covers most
use-cases already.
1% progression on ACID3. :^)
This API now follows the spec a bit more closely, with regards to the
event being dispatched. There are still FIXME's but this is already an
improvement.
2% progression on ACID3. :^)
There were two things preventing this from working right:
- UIEvents::UIEvent::create() was actually just DOM::Event::create()
- We didn't return the right JavaScript wrapper type for UIEvent
Previously we were only matching elements with *no* text children.
With this patch, we now also allow any number of empty text children to
be present as well.
1% progression on ACID3. :^)
Use the new Gfx::Font::AllowInexactSizeMatch parameter when doing CSS
font lookups. This fixes a long-standing issue where text with e.g text
with "font-size:12px" would be larger than "font-size:13px" since there
was an exact match for 12, but none for 13 (so we'd fall back to 10).
This allows bitmap font lookup to return the best matching size instead
of failing completely. The previous behavior (exact matches only)
remains the default.
Instead of re-measuring the distance between the left and right edges of
a line box, we now simply adjust the final width based on how much the
rightmost fragment moved during the alignment process.
This shape is for use by the main widget of a frameless window
that still wishes to have proper borders but no title.
Raised Containers were used previously for this pattern but did not
always represent perspective and shadow correctly depending on thread
highlighting and the immediate background color. Containers are
really meant to be used inside other widgets where the background
color can be controlled.
This works a little differently from the other caches - ALL rules
containing a pseudo-element are in this bucket. This lets us only look
at this bucket when finding styles for a pseudo-element, and ignore it
if we're not.
We were painting this in the Foreground phase by mistake. Also, the
`inspected_node() == dom_node()` check returns true for pseudo-elements
(both values are nullptr) so I've added an extra check there. As noted,
once pseudo-elements are inspectable we will need to revisit this.
Since each selector can only have zero or one pseudo-element, we match
against it as a separate step, before matching the rest of the
selector. This should be faster, but mostly I did this because I could
not figure out how else to stop selectors without a pseudo-element from
matching the pseudo-element, eg so `.foo` styles don't affect
`.foo::before`.
This means we can instantiate them for pseudo-elements, which don't have
an associated Element. They all pass it to their parent as a
`Layout::Node*` and handle a lack of `layout_node()` already so this
won't affect any functionality.
For now, we only understand `none`, `normal`, `<image>` and `<string>`.
The various other functions and identifiers can be added later.
We can *almost* use a StyleValueList for this, except it's divided into
two parts - the content, and the optional "alt text". So, I've added a
new StyleValue for it.
This adds a keyboard event for Super+0 to Super+9. Later to be consumed
in the taskbar.
Currently only this keyboard sequence is supported:
- Super key down
- Digit key down
But not this:
- Super key down
- Digit key down
- Digit key up
- Digit key down
Segments inherit from Button and let us add clickable widgets
to status bars. This patch also adds proportional, fixed and
autosized modes for segments and lets the status bar consume
all non-clickable segments for override text.
There were a couple issues here:
1. The line feed should only be appended once, rather than one per
string.
2. The new_strings list of strings was unused (we were creating the new
list, then passing the old list to Document.write).
Fonts now provide their preferred line height based on maximum
height and requested line gap. TTFs provide a preferred line gap
from table metrics while BitmapFonts are hardcoded at the previous
default for now.
Ruler needs to take into account spacing between glyphs for
proportional fonts as line count increases. This also replaces
the less accurate 'x' width estimate for widest character with
a '4'
This is the only dimension type besides `<length>` that is used in any
media queries in levels 4 or 5 right now. Others can be included
if/when they're needed.
This means the units are defined in a single place instead of two.
Also removed the verify that we didn't produce a bogus % dimension token
in the Tokenizer, since this has never happened and the parser is not a
tokenizer test suite. :^)
These will require some tweaking here and elsewhere in LibGUI, to handle
both rendering of the emojis as single glyphs consistently, and faking
key events with multiple code points after selecting one.
This necessitates switching from passing a single code point to the
callback to passing a non-const Utf8CodePointIterator instead.
Note that the text selection mechanisms in LibGUI and LibWeb don't
handle this properly yet; they still assume that each code point
renders as one glyph. Similarly, width calculations for text widths
don't either, so a single such an emoji will require space for more
than one glyph.
It also doesn't work in LibVT's TerminalWidget, where each code point
is handled and rendered separately, so LibGfx never gets a chance to
check if subsequent code points could result in a combined emoji.
In the common case of text rendering rather than getting the emoji
bitmap for a fixed number of code points, we don't know how many code
points make one emoji. As far as I can tell, the longest ones are up to
ten code points, so we try to consume all of them and do a lookup during
each iteration, and return the emoji for the longest chain of code
points. Quite basic and definitely room for improvement, but it works!
Not all emojis are just one code point, so the existing API is not
sufficient: Emoji::emoji_for_code_point(u32).
The file name for such emojis is simply each U+XXXX separated by an
underscore.
Different thread highlights between widgets lead to different
visual weights between splitters, even when they have the same
width or height. This means some splitters look best at odd
sizes while others even. This sets the default spacing to the
most commonly used, depending on orientation, and adjusts
spacing for a few apps based on the new paint rect.
The most consistent look across apps requires some manual
tweaking occassionally. Knurlheads, use your discretion!
Splitters could be resized in such an order that all their remaining
children were fixed size, leading to unfillable gaps on resize events.
HackStudio and TextEditor already had logic to handle this edge case,
so this patch factors it into a general solution for all Splitters.
At least one widget is now guaranteed to be resizeable after a child
is removed.
This will verify that the signature of the ephemeral key used in the
DHE and ECDHE key exchanges is actually generated by the server.
This verification is done using the first certificate provided by the
server, however the validity of this certificate is not checked here.
Instead this code expects the validity to be checked earlier by
`TLSv12::handle_certificate`.
This add an implementation for the EMSA-PKCS1-V1_5-ENCODE function from
RFC8017 section 9.2. The verification of this encoding is implemented by
simply encoding the message to be verified, and then comparing the two
encoded string.
The digest info for the different hash function is from RFC8017 section
9.2 notes 1. These byte sequences are actually ASN.1 encoded data,
however these are always constant for a specific hash function and can
be treated as opaque byte sequences.
Previously, the names of declarations where stored as a simple
StringView.
Because of that, we couldn't parse out-of-line function definitions,
which have qualified names.
For example, we couldn't parse the following snippet:
```
void MyClass::foo(){}
```
To fix this, we now store the name of a declaration with a
ASTNode::Name node, which represents a qualified named.
Our API still specifies it as a double, but internally we communicate a
float to the rasterizer. Additionally, clamp the value to 0..1 as
described in the spec.
Our implementation keeps the top-most item on the matrix stacks in a
member variable, so we can always use that instead of considering the
actual stack.
Additionally, the current matrix mode should not influence retrieving
the projection or model view matrix.
This fixes the issue where e.g. `299.97` would be cast to an integer
value of `299`, whereas the pixel's center would lie at `299.5` and
would then erroneously be excluded.
Currently, LibSoftGPU is still OpenGL-minded in that it uses a
coordinate system with the origin of `(0, 0)` at the lower-left of
textures, buffers and window coordinates. Because we are blitting to a
`Gfx::Bitmap` that has the origin at the top-left, we need to flip the
Y-coordinates somewhere in the rasterization logic.
We used to do this during conversion of NDC-coordinates to window
coordinates. This resulted in some incorrect behavior when
rasterization did not pass through the vertex transformation logic,
e.g. when calling `glDrawPixels`.
This changes the coordinate system to OpenGL's throughout, only to blit
the final color buffer upside down to the target bitmap. This fixes
drawing to the depth buffer directly resulting in upside down images.
Between the OpenGL client and server, a lot of data type and color
conversion needs to happen. We are performing these conversions both in
`LibSoftGPU` and `LibGL`, which is not ideal. Additionally, some
concepts like the color, depth and stencil buffers should share their
logic but have separate implementations.
This is the first step towards generalizing our `LibSoftGPU` frame
buffer: a generalized `Typed3DBuffer` is introduced for arbitrary 3D
value storage and retrieval, and `Typed2DBuffer` wraps around it to
provide in an easy-to-use 2D pixel buffer. The color, depth and stencil
buffers are replaced by `Typed2DBuffer` and are now managed by the new
`FrameBuffer` class.
The `Image` class now uses multiple `Typed3DBuffer`s for layers and
mipmap levels. Additionally, the textures are now always stored as
BGRA8888, only converting between formats when reading or writing
pixels.
Ideally this refactor should have no functional changes, but some
graphical glitches in Grim Fandango seem to be fixed and most OpenGL
ports get an FPS boost on my machine. :^)
This function was added as a FIXME but was then arbitrarily invoked in
the rest of `Device`. We are better off removing this FIXME for now and
reevaluate introducing multithreading later on, so the code is not
littered with useless empty function calls.
We check for primitive support in `glEnd()`, so we do not need to
preemptively reject the mode in `glBegin()`. This allows `glBegin()` to
be invoked with `GL_POINTS`, for example.
Unlike all the other CSS properties, 'float' is special, and can only be
accessed via 'cssFloat' on CSSStyleDeclaration. So this patch adds
support for that. 1 point on ACID3! :^)
This necessitated making HTMLParser ref-counted, and having it register
itself with Document when created. That makes it possible for scripts to
add new input at the current parser insertion point.
There is now a reference cycle between Document and HTMLParser. This
cycle is explicitly broken by calling Document::detach_parser() at the
end of HTMLParser::run().
This is a huge progression on ACID3, from 31% to 49%! :^)
When calculating how much space is available for inline content between
left and right floated elements, we have to use coordinates in the
containing block's coordinate space, since that's what floats use.
This fixes an issue where text would sometimes overlap floats.
We were subtracting the content width of right-floated boxes from their
X position for no reason. Removing this makes floats snuggle up to each
other on the right side. :^)
When encountering a box that claims to have block-level children, but
its CSS display type isn't actually "flow" inside, we would previously
crash due to a VERIFY() failure.
However, many sites choke on this due to freestanding table-related
boxes like those created by "table-row" and "table-row-group".
We're supposed to fix those up by wrapping them in a full set of table
boxes during layout tree construction, but that algorithm obviously
isn't working correctly in all cases. So let's work around the crashes
for now, allowing many more sites to load (even if visually incorrect.)
This is a rather monstrous hack, and we should get rid of it as soon as
it's not needed anymore.
"5em" means 5*font-size, but by forcing "em" to mean the presentation
size of the bitmap font actually used, we broke a bunch of layouts that
depended on a correct interpretation of "em".
This means that "em" units will no longer be relative to the exact
size of the bitmap font in use, but I think that's a compromise we'll
have to make, since accurate layouts are more important.
This yields a visual progression on both ACID2 and ACID3. :^)
Previously, these were added during layout. This didn't fit into the new
world where layout doesn't mutate the tree incrementally, so this patch
adds logic to Layout::TreeBuilder for adding a marker to each list-item
box after its children have been constructed.
This patch adds a map of Layout::Node to FormattingState::NodeState.
Instead of updating layout nodes incrementally as layout progresses
through the formatting contexts, all updates are now written to the
corresponding NodeState instead.
At the end of layout, FormattingState::commit() is called, which
transfers all the values from the NodeState objects to the Node.
This will soon allow us to perform completely non-destructive layouts
which don't affect the tree.
Note that there are many imperfections here, and still many places
where we assign to the NodeState, but later read directly from the Node
instead. I'm just committing at this stage to make subsequent diffs
easier to understand.
The purpose of this new object will be to keep track of various states
during an ongoing layout.
Until now, we've been updating layout tree nodes as we go during layout,
which adds an invisible layer of implicit serialization to the whole
layout system.
My idea with FormattingState is that running layout will produce a
result entirely contained within the FormattingState object. At the end
of layout, it can then be applied to the layout tree, or simply queried
for some metrics we were trying to determine.
When doing subtree layouts to determine intrinsic sizes, we will
eventually be able to clone the current FormattingState, and run the
subtree layout in isolation, opening up opportunities for parallelism.
This first patch doesn't go very far though, it merely adds the object
as a skeleton class, and makes sure the root BFC has one. :^)
The ICB (initial containing block) gets its style from StyleComputer's
create_document_style(). It's basically a generic style for the root of
the layout tree.
With this patch, we now assign the width and height of the viewport rect
as two CSS "px" lengths to the "width" and "height" properties of the
ICB style. (Previously they were just defaulting to "auto" and we
assigned override dimensions during layout.)
This fixes an issue where position:absolute elements with relative width
and/or height were not dimensioned correctly, since the values were
relative to the width and/or height of the ICB style.
This implements basic support for dynamic markup insertion, adding
* Document::open()
* Document::write(Vector<String> const&)
* Document::writeln(Vector<String> const&)
* Document::close()
The HTMLParser is modified to make it possible to create a
script-created parser which initially only contains a HTMLTokenizer
without any data. Aditionally the HTMLParser::run method gains an
overload which does not modify the Document and does not run
HTMLParser::the_end() so that we can reenter the parser at a later time.
Furthermore all FIXMEs that consern the insertion point are implemented
wich is defined in the HTMLTokenizer. Additionally the following
member-variables of the HTMLParser are now exposed by getter funcions:
* m_tokenizer
* m_aborted
* m_script_nesting_level
The HTMLTokenizer is modified so that it contains an insertion
point which keeps track of where the next input from the Document::write
functions will be inserted. The insertion point is implemented as the
charakter offset into m_decoded_input and a boolean describing if the
insertion point is defined. Functions to update, check and {re}store the
insertion point are also added.
The function HTMLTokenizer::insert_eof is added to tell a script-created
parser that document::close was called and HTMLParser::the_end() should
be called.
Lastly an explicit default constructor is added to HTMLTokenizer to
create a empty HTMLTokenizer into which data can be inserted.
Also, update the expected hash in the LibWeb TestHTMLTokenizer
regression test.
This is due to the "This comment has a few too many dashes." comment
token being updated.
Newline normalization will replace \r and \r\n with \n.
The spec specifically states
> Before the tokenization stage, the input stream must be preprocessed
> by normalizing newlines.
wheras this is implemented the processing during the tokenization
itself.
This should still exhibit the same behaviour, while keeping the
tokenization logic in the same place.
In 'NamedCharacterReference' we attempt to lookup the code point by a
identifier, eg apos; becomes '
This is done by passing the entire rest of the document to the
`HTML::code_points_from_entity` function.
However, before this change we didn't sent the final character which
meant if the document ended in a named character reference the lookup
would fail.
This follows the ECMA402 spec and means String.prototype.localeCompare
will automatically become actually locale aware once StringCompare is
actually implemented based on UTS #10.