Compare commits

...

29 commits

Author SHA1 Message Date
Johan Dahlin
fb8479b513
Merge 4c1d4aa678 into 001df24935 2024-11-21 15:15:52 +02:00
Pavel Shliak
001df24935 LibWebSocket: Clean up #include directives
Some checks are pending
CI / Lagom (false, NO_FUZZ, macos-15, macOS, Clang) (push) Waiting to run
CI / Lagom (false, FUZZ, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (false, NO_FUZZ, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (true, NO_FUZZ, ubuntu-24.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-24.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
This change aims to improve the speed of incremental builds.
2024-11-21 14:08:33 +01:00
Pavel Shliak
b60cb699a9 LibMedia: Clean up #include directives
This change aims to improve the speed of incremental builds.
2024-11-21 14:08:33 +01:00
Pavel Shliak
8d13115d9a LibCrypto: Clean up #include directives
This change aims to improve the speed of incremental builds.
2024-11-21 14:08:33 +01:00
Pavel Shliak
cd14b215d1 LibDNS: Clean up #include directives
This change aims to improve the speed of incremental builds.
2024-11-21 14:08:33 +01:00
Pavel Shliak
35764db0b7 LibWasm: Clean up #include directives
This change aims to improve the speed of incremental builds.
2024-11-21 14:08:33 +01:00
Pavel Shliak
caf7983039 LibHTTP: Clean up #include directives
This change aims to improve the speed of incremental builds.
2024-11-21 14:08:33 +01:00
Pavel Shliak
cdb54fe504 LibRegex: Clean up #include directives
This change aims to improve the speed of incremental builds.
2024-11-21 14:08:33 +01:00
Psychpsyo
7f989765f5 LibWeb: Fix MouseEvent position values
The clientX and clientY values are, as per the spec, the offset from
the viewport.
This makes them actually be that and also fixes up the calculations
for offsetX, offsetY, pageX and pageY.
I assume all of these got messed up in some sort of refactor in the
past.

The spec comment from the now-removed
compute_mouse_event_client_offset() function sadly has no convenient
place to be anymore so, for now, it is just gone as well.
Personally, I think it'd make sense to refactor a lot of this file so
that not every mouse event repeats a large chunk of (almost) identical
code. That way there'd be a nice place to put the comment without
repeating it all over the file.
But that is out of the scope of this PR.

Also: I know, offsetX and Y are not fully fixed yet, they still
don't ignore the element's CSS transforms but I am working on that
in a new PR.
2024-11-21 13:22:22 +01:00
Aliaksandr Kalenik
41c172c663 LibWeb: Allow custom properties in getPropertyPriority() 2024-11-21 13:16:08 +01:00
Aliaksandr Kalenik
ac5699c8fc LibWeb: Allow custom properties in CSSStyleDeclaration.removeProperty() 2024-11-21 13:16:08 +01:00
Aliaksandr Kalenik
ce26e5d757 LibWeb: Allow custom properties in CSSStyleDeclaration.getPropertyValue 2024-11-21 13:16:08 +01:00
Aliaksandr Kalenik
3a2cc1aa20 LibWeb: Allow custom properties in CSSStyleDeclaration.setProperty()
This change fixes unhoverable toolbar on https://excalidraw.com/
The problem was that React.js uses setProperty() to add style properties
specified in the "style" attribute in the virtual DOM, and we were
failing to add the CSS variable used to set the "pointer-events" value
to "all".
2024-11-21 13:16:08 +01:00
Aliaksandr Kalenik
0448d4d609 LibWeb: Update property_id_from_string() generator to handle ::Custom 2024-11-21 13:16:08 +01:00
Lucas CHOLLET
a1687854ab LibWeb/CSS: Use double in CSSHWB::to_color()
See previous the commit description for more details about the floating
points operations.

The hwb test cases in `css-color-functions` are now rendered identically
to what firefox does (I haven't checked the others tests, but they
aren't affected by this commit).
2024-11-21 11:59:44 +00:00
Lucas CHOLLET
d1120e1809 LibWeb: Make CSSColorValue resolvers return a double
Without this change the math in `CSSHWB::to_color()` is lacking some
precision to generate the correct value to hand to `Color::from_hsv()`.

More precisely, when converting `hwb(120 20 30)`, the HSV's value would
be calculated as `1 - .3`. However, it turns out that `1 - .3f != .7f`
and `1 - .3f` gives bad results down the road in `Color::from_hsv()`.

This example actually only requires `resolve_with_reference_value()` to
return a double. I changed the two others for symmetry.
2024-11-21 11:59:44 +00:00
Lucas CHOLLET
248e4bb517 LibGfx: Round values in Color::with_opacity()
`svg-gradient-userSpaceOnUse` is now rendered to something closer to
what firefox does, so it is at least some progress.
2024-11-21 11:59:44 +00:00
Lucas CHOLLET
b4ba65c6e5 LibGfx: Round values in Color::from_hsv() 2024-11-21 11:59:44 +00:00
devgianlu
009f328308 LibWeb: Implement ECDH.generateKey 2024-11-21 11:45:22 +01:00
Pavel Shliak
d55caff227 LibFileSystem: Fix Windows build
This reverts part of  b3c253e50f
2024-11-21 11:15:49 +01:00
Feng Yu
570c5f8df2 Documentation: Fix broken link in README 2024-11-21 10:42:45 +01:00
Johan Dahlin
4c1d4aa678 Tests: Wait for fonts before completing tests (WIP) 2024-11-20 20:57:00 +01:00
Johan Dahlin
5f42f1318a LibWeb: Layout/Shape font-variant properties 2024-11-20 19:56:04 +01:00
Johan Dahlin
98183c7164 LibWeb/LibGfx: Add ShapeFeatures argument to shape_text() 2024-11-20 19:56:04 +01:00
Johan Dahlin
0a3193f0b6 LibWeb: Style font-variant properties 2024-11-20 19:56:03 +01:00
Johan Dahlin
164dd05467 LibWeb: Parse font-variant properties 2024-11-20 19:54:37 +01:00
Johan Dahlin
0269bdbe60 LibWeb: Add font-variant-* css properties 2024-11-20 19:54:36 +01:00
Johan Dahlin
2b316d16ce WPT: Import /css/css-fonts/font-variant-*.html tests 2024-11-20 19:54:36 +01:00
Johan Dahlin
ce3ce607ae LibWeb: Load otf fonts, used by wpt tests 2024-11-20 19:54:36 +01:00
143 changed files with 4104 additions and 410 deletions

View file

@ -8,5 +8,6 @@ Libraries/LibJS/Tests/modules/top-level-dispose.mjs
Libraries/LibJS/Tests/using-declaration.js
Libraries/LibJS/Tests/using-for-loops.js
Tests/LibWeb/Ref/data
Tests/LibWeb/Ref/input/wpt-import
Tests/LibWeb/Text/input/wpt-import

View file

@ -35,5 +35,5 @@ you are welcome to ask on [Discord](../README.md#get-in-touch-and-participate).
* [LibWeb: From Loading to Painting](LibWebFromLoadingToPainting.md)
* [LibWeb: Browsing Contexts and Navigables](BrowsingContextsAndNavigables.md)
* [How to Add an IDL File](AddNewIDLFile.md)
* [LibWeb Code Style & Patterns](Browser/Patterns.md)
* [LibWeb Code Style & Patterns](LibWebPatterns.md)
* [CSS Generated Files](CSSGeneratedFiles.md)

View file

@ -8,7 +8,6 @@
#include <AK/Time.h>
#include <AK/Types.h>
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
namespace Crypto::ASN1 {

View file

@ -7,7 +7,6 @@
#pragma once
#include <AK/BitmapView.h>
#include <AK/Result.h>
#include <AK/Types.h>
#include <LibCrypto/ASN1/ASN1.h>
#include <LibCrypto/BigInt/UnsignedBigInteger.h>

View file

@ -6,9 +6,8 @@
#pragma once
#include <AK/ByteBuffer.h>
#include <AK/Span.h>
#include <LibCrypto/ASN1/ASN1.h>
#include <LibCrypto/ASN1/DER.h>
namespace Crypto {

View file

@ -10,7 +10,6 @@
#include <AK/ByteString.h>
#include <AK/Endian.h>
#include <AK/Types.h>
#include <LibCrypto/Hash/HashFunction.h>
namespace Crypto::Authentication {

View file

@ -6,9 +6,8 @@
*/
#include "UnsignedBigIntegerAlgorithms.h"
#include <AK/BigIntBase.h>
#include <AK/BuiltinWrappers.h>
#include <AK/NumericLimits.h>
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
namespace Crypto {

View file

@ -7,7 +7,6 @@
#include "UnsignedBigIntegerAlgorithms.h"
#include <AK/BigIntBase.h>
#include <AK/BuiltinWrappers.h>
namespace Crypto {

View file

@ -9,7 +9,6 @@
#include <AK/Concepts.h>
#include <AK/Span.h>
#include <AK/String.h>
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
namespace Crypto {

View file

@ -9,7 +9,6 @@
#pragma once
#include <AK/BigIntBase.h>
#include <AK/ByteBuffer.h>
#include <AK/ByteString.h>
#include <AK/Concepts.h>
#include <AK/Span.h>

View file

@ -5,7 +5,6 @@
*/
#include <AK/Array.h>
#include <AK/NumericLimits.h>
#include <AK/Span.h>
#include <AK/Types.h>
#include <LibCrypto/Checksum/CRC32.h>

View file

@ -8,7 +8,6 @@
#pragma once
#include <AK/ByteString.h>
#include <AK/Vector.h>
#include <LibCrypto/Cipher/Cipher.h>
#include <LibCrypto/Cipher/Mode/CBC.h>
#include <LibCrypto/Cipher/Mode/CTR.h>

View file

@ -6,7 +6,7 @@
#pragma once
#include <AK/ByteBuffer.h>
#include <AK/Span.h>
namespace Crypto::Cipher {

View file

@ -7,7 +7,6 @@
#pragma once
#include <AK/Optional.h>
#include <AK/Span.h>
#include <AK/Types.h>

View file

@ -6,8 +6,6 @@
#pragma once
#include <AK/Random.h>
namespace Crypto::Curves {
class Curve25519 {

View file

@ -7,7 +7,6 @@
#pragma once
#include <AK/ByteBuffer.h>
#include <LibCrypto/Curves/EllipticCurve.h>
namespace Crypto::Curves {

View file

@ -5,7 +5,6 @@
*/
#include <AK/ByteReader.h>
#include <AK/Endian.h>
#include <AK/Random.h>
#include <LibCrypto/Curves/Curve25519.h>
#include <LibCrypto/Curves/X25519.h>

View file

@ -5,6 +5,7 @@
*/
#include <AK/Debug.h>
#include <AK/Random.h>
#include <LibCrypto/BigInt/Algorithms/UnsignedBigIntegerAlgorithms.h>
#include <LibCrypto/NumberTheory/ModularFunctions.h>

View file

@ -6,7 +6,6 @@
#pragma once
#include <AK/Random.h>
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
namespace Crypto::NumberTheory {

View file

@ -7,12 +7,10 @@
#pragma once
#include <AK/Base64.h>
#include <AK/MaybeOwned.h>
#include <AK/IPv4Address.h>
#include <AK/IPv6Address.h>
#include <AK/RedBlackTree.h>
#include <AK/Time.h>
#include <LibCore/Promise.h>
#include <LibCore/SocketAddress.h>
#include <LibURL/URL.h>
namespace DNS {
namespace Messages {

View file

@ -8,6 +8,7 @@
#include <AK/AtomicRefCounted.h>
#include <AK/HashTable.h>
#include <AK/MaybeOwned.h>
#include <AK/MemoryStream.h>
#include <AK/Random.h>
#include <AK/StringView.h>

View file

@ -15,6 +15,8 @@
# include <sys/disk.h>
#elif defined(AK_OS_LINUX)
# include <linux/fs.h>
#elif defined(AK_OS_WINDOWS)
# include <dirent.h>
#endif
// On Linux distros that use glibc `basename` is defined as a macro that expands to `__xpg_basename`, so we undefine it

View file

@ -16,6 +16,7 @@ set(SOURCES
Font/Font.cpp
Font/FontData.cpp
Font/FontDatabase.cpp
Font/FontVariant.cpp
Font/PathFontProvider.cpp
Font/ScaledFont.cpp
Font/ScaledFontSkia.cpp

View file

@ -400,7 +400,8 @@ public:
constexpr Color with_opacity(float opacity) const
{
return with_alpha(alpha() * opacity);
VERIFY(opacity >= 0 && opacity <= 1);
return with_alpha(static_cast<u8>(round(alpha() * opacity)));
}
constexpr Color darkened(float amount = 0.5f) const
@ -549,9 +550,9 @@ public:
break;
}
u8 out_r = (u8)(r * 255);
u8 out_g = (u8)(g * 255);
u8 out_b = (u8)(b * 255);
auto out_r = static_cast<u8>(round(r * 255));
auto out_g = static_cast<u8>(round(g * 255));
auto out_b = static_cast<u8>(round(b * 255));
return Color(out_r, out_g, out_b);
}

View file

@ -0,0 +1,176 @@
/*
* Copyright (c) 2024, Johan Dahlin <jdahlin@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/String.h>
#include <AK/StringBuilder.h>
#include <LibGfx/Font/FontVariant.h>
namespace Gfx {
StringView font_variant_alternates_to_string(FontVariantAlternates value)
{
if (value.normal && value.historical_forms)
return "normal historical-forms"sv;
if (value.normal)
return "normal"sv;
if (value.historical_forms)
return "historical-forms"sv;
return {};
}
StringView font_variant_ligatures_to_string(FontVariantLigatures ligatures)
{
if (ligatures.normal)
return "normal"sv;
if (ligatures.none)
return "none"sv;
Vector<StringView> values;
switch (ligatures.common) {
case FontVariantLigatures::Common::Common:
values.append("common-ligatures"sv);
break;
case FontVariantLigatures::Common::NoCommon:
values.append("no-common-ligatures"sv);
break;
case FontVariantLigatures::Common::Unset:
break;
}
switch (ligatures.discretionary) {
case FontVariantLigatures::Discretionary::Discretionary:
values.append("discretionary-ligatures"sv);
break;
case FontVariantLigatures::Discretionary::NoDiscretionary:
values.append("no-discretionary-ligatures"sv);
break;
case FontVariantLigatures::Discretionary::Unset:
break;
}
switch (ligatures.historical) {
case FontVariantLigatures::Historical::Historical:
values.append("historical-ligatures"sv);
break;
case FontVariantLigatures::Historical::NoHistorical:
values.append("no-historical-ligatures"sv);
break;
case FontVariantLigatures::Historical::Unset:
break;
}
switch (ligatures.contextual) {
case FontVariantLigatures::Contextual::Contextual:
values.append("contextual"sv);
break;
case FontVariantLigatures::Contextual::NoContextual:
values.append("no-contextual"sv);
break;
case FontVariantLigatures::Contextual::Unset:
break;
}
StringBuilder builder;
builder.join(' ', values);
return MUST(builder.to_string());
}
StringView font_variant_east_asian_to_string(FontVariantEastAsian value)
{
Vector<StringView> values;
switch (value.variant) {
case FontVariantEastAsian::Variant::Unset:
break;
case FontVariantEastAsian::Variant::Jis78:
values.append("jis78"sv);
break;
case FontVariantEastAsian::Variant::Jis83:
values.append("jis83"sv);
break;
case FontVariantEastAsian::Variant::Jis90:
values.append("jis90"sv);
break;
case FontVariantEastAsian::Variant::Jis04:
values.append("jis04"sv);
break;
case FontVariantEastAsian::Variant::Simplified:
values.append("simplified"sv);
break;
case FontVariantEastAsian::Variant::Traditional:
values.append("traditional"sv);
break;
}
switch (value.width) {
case FontVariantEastAsian::Width::Unset:
break;
case FontVariantEastAsian::Width::FullWidth:
values.append("full-width"sv);
break;
case FontVariantEastAsian::Width::Proportional:
values.append("proportional-width"sv);
break;
}
if (value.ruby)
values.append("ruby"sv);
StringBuilder builder;
builder.join(' ', values);
return MUST(builder.to_string());
}
StringView font_variant_numeric_to_string(FontVariantNumeric value)
{
Vector<StringView> values;
if (value.normal)
values.append("normal"sv);
if (value.ordinal)
values.append("ordinal"sv);
if (value.slashed_zero)
values.append("slashed-zero"sv);
switch (value.figure) {
case FontVariantNumeric::Figure::Unset:
break;
case FontVariantNumeric::Figure::Lining:
values.append("lining-nums"sv);
break;
case FontVariantNumeric::Figure::Oldstyle:
values.append("oldstyle-nums"sv);
break;
}
switch (value.spacing) {
case FontVariantNumeric::Spacing::Unset:
break;
case FontVariantNumeric::Spacing::Proportional:
values.append("proportional-nums"sv);
break;
case FontVariantNumeric::Spacing::Tabular:
values.append("tabular-nums"sv);
break;
}
switch (value.fraction) {
case FontVariantNumeric::Fraction::Unset:
break;
case FontVariantNumeric::Fraction::Diagonal:
values.append("diagonal-fractions"sv);
break;
case FontVariantNumeric::Fraction::Stacked:
values.append("stacked-fractions"sv);
break;
}
StringBuilder builder;
builder.join(' ', values);
return MUST(builder.to_string());
}
}

View file

@ -0,0 +1,90 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <andreas@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Optional.h>
#include <AK/StringView.h>
#include <AK/Vector.h>
#pragma once
namespace Gfx {
using FontFeatureName = StringView;
class FontVariantAlternates {
public:
bool normal { false };
bool historical_forms { false };
};
class FontVariantEastAsian {
public:
enum class Variant { Unset,
Jis78,
Jis83,
Jis90,
Jis04,
Simplified,
Traditional };
enum class Width { Unset,
Proportional,
FullWidth };
bool normal = false;
bool ruby = false;
Variant variant { Variant::Unset };
Width width { Width::Unset };
};
class FontVariantLigatures {
public:
enum class Common { Unset,
Common,
NoCommon };
enum class Discretionary { Unset,
Discretionary,
NoDiscretionary };
enum class Historical { Unset,
Historical,
NoHistorical };
enum class Contextual { Unset,
Contextual,
NoContextual };
bool normal = false;
bool none = false;
Common common { Common::Unset };
Discretionary discretionary { Discretionary::Unset };
Historical historical { Historical::Unset };
Contextual contextual { Contextual::Unset };
};
class FontVariantNumeric {
public:
enum class Figure { Unset,
Lining,
Oldstyle };
enum class Spacing { Unset,
Proportional,
Tabular };
enum class Fraction { Unset,
Diagonal,
Stacked };
bool normal = false;
bool ordinal = false;
bool slashed_zero = false;
Figure figure { Figure::Unset };
Spacing spacing { Spacing::Unset };
Fraction fraction { Fraction::Unset };
};
extern StringView font_variant_alternates_to_string(FontVariantAlternates);
extern StringView font_variant_east_asian_to_string(FontVariantEastAsian);
extern StringView font_variant_ligatures_to_string(FontVariantLigatures);
extern StringView font_variant_numeric_to_string(FontVariantNumeric);
}

View file

@ -58,13 +58,13 @@ ScaledFontMetrics ScaledFont::metrics() const
return metrics;
}
float ScaledFont::width(StringView view) const { return measure_text_width(Utf8View(view), *this); }
float ScaledFont::width(Utf8View const& view) const { return measure_text_width(view, *this); }
float ScaledFont::width(StringView view) const { return measure_text_width(Utf8View(view), *this, {}); }
float ScaledFont::width(Utf8View const& view) const { return measure_text_width(view, *this, {}); }
float ScaledFont::glyph_width(u32 code_point) const
{
auto string = String::from_code_point(code_point);
return measure_text_width(Utf8View(string), *this);
return measure_text_width(Utf8View(string), *this, {});
}
NonnullRefPtr<ScaledFont> ScaledFont::scaled_with_size(float point_size) const

View file

@ -6,6 +6,8 @@
#pragma once
#include <AK/Assertions.h>
#include <AK/StdLibExtras.h>
#include <AK/Types.h>
#include <initializer_list>

View file

@ -12,7 +12,7 @@
namespace Gfx {
RefPtr<GlyphRun> shape_text(FloatPoint baseline_start, float letter_spacing, Utf8View string, Gfx::Font const& font, GlyphRun::TextType text_type)
RefPtr<GlyphRun> shape_text(FloatPoint baseline_start, float letter_spacing, Utf8View string, Gfx::Font const& font, GlyphRun::TextType text_type, ShapeFeatures const& features)
{
hb_buffer_t* buffer = hb_buffer_create();
ScopeGuard destroy_buffer = [&]() { hb_buffer_destroy(buffer); };
@ -24,7 +24,22 @@ RefPtr<GlyphRun> shape_text(FloatPoint baseline_start, float letter_spacing, Utf
Vector<hb_glyph_info_t> const input_glyph_info({ glyph_info, glyph_count });
auto* hb_font = font.harfbuzz_font();
hb_shape(hb_font, buffer, nullptr, 0);
const hb_feature_t* hb_features_data = nullptr;
Vector<hb_feature_t> hb_features;
if (!features.is_empty()) {
hb_features.ensure_capacity(features.size());
for (auto const& feature : features) {
hb_features.append({
.tag = HB_TAG(feature.tag[0], feature.tag[1], feature.tag[2], feature.tag[3]),
.value = feature.value,
.start = 0,
.end = static_cast<unsigned int>(-1),
});
}
hb_features_data = hb_features.data();
}
hb_shape(hb_font, buffer, hb_features_data, features.size());
glyph_info = hb_buffer_get_glyph_infos(buffer, &glyph_count);
auto* positions = hb_buffer_get_glyph_positions(buffer, &glyph_count);
@ -45,12 +60,14 @@ RefPtr<GlyphRun> shape_text(FloatPoint baseline_start, float letter_spacing, Utf
point.translate_by(letter_spacing, 0);
}
hb_buffer_reset(buffer);
return adopt_ref(*new Gfx::GlyphRun(move(glyph_run), font, text_type, point.x()));
}
float measure_text_width(Utf8View const& string, Gfx::Font const& font)
float measure_text_width(Utf8View const& string, Gfx::Font const& font, ShapeFeatures const& features)
{
auto glyph_run = shape_text({}, 0, string, font, GlyphRun::TextType::Common);
auto glyph_run = shape_text({}, 0, string, font, GlyphRun::TextType::Common, features);
return glyph_run->width();
}

View file

@ -26,6 +26,13 @@ struct DrawGlyph {
}
};
typedef struct ShapeFeature {
char tag[4];
u32 value;
} ShapeFeature;
using ShapeFeatures = Vector<ShapeFeature, 4>;
class GlyphRun : public RefCounted<GlyphRun> {
public:
enum class TextType {
@ -60,7 +67,7 @@ private:
float m_width { 0 };
};
RefPtr<GlyphRun> shape_text(FloatPoint baseline_start, float letter_spacing, Utf8View string, Gfx::Font const& font, GlyphRun::TextType);
float measure_text_width(Utf8View const& string, Gfx::Font const& font);
RefPtr<GlyphRun> shape_text(FloatPoint baseline_start, float letter_spacing, Utf8View string, Gfx::Font const& font, GlyphRun::TextType, ShapeFeatures const& features);
float measure_text_width(Utf8View const& string, Gfx::Font const& font, ShapeFeatures const& features);
}

View file

@ -8,7 +8,6 @@
#include <AK/Base64.h>
#include <AK/StringBuilder.h>
#include <LibHTTP/HttpRequest.h>
#include <LibURL/Parser.h>
namespace HTTP {

View file

@ -11,7 +11,6 @@
#include <AK/ByteString.h>
#include <AK/Noncopyable.h>
#include <AK/Optional.h>
#include <AK/Vector.h>
#include <LibCore/Forward.h>
#include <LibHTTP/HeaderMap.h>
#include <LibURL/URL.h>

View file

@ -7,8 +7,6 @@
#pragma once
#include <AK/ByteString.h>
#include <AK/HashMap.h>
#include <LibCore/NetworkResponse.h>
#include <LibHTTP/HeaderMap.h>

View file

@ -5,7 +5,6 @@
*/
#include "FFmpegLoader.h"
#include <AK/BitStream.h>
#include <AK/NumericLimits.h>
#include <LibCore/System.h>

View file

@ -13,7 +13,6 @@
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/samplefmt.h>
}
namespace Audio {

View file

@ -7,7 +7,6 @@
#include "PlaybackStream.h"
#include <AK/Platform.h>
#include <LibCore/ThreadedPromise.h>
#if defined(HAVE_PULSEAUDIO)
# include "PlaybackStreamPulseAudio.h"

View file

@ -9,12 +9,9 @@
#include "SampleFormats.h"
#include <AK/AtomicRefCounted.h>
#include <AK/Function.h>
#include <AK/Queue.h>
#include <AK/Time.h>
#include <LibCore/Forward.h>
#include <LibThreading/ConditionVariable.h>
#include <LibThreading/MutexProtected.h>
#include <LibThreading/Thread.h>
#include <LibCore/ThreadedPromise.h>
namespace Audio {

View file

@ -8,6 +8,9 @@
#include "PlaybackStream.h"
#include "PulseAudioWrappers.h"
#include <AK/Queue.h>
#include <LibThreading/ConditionVariable.h>
#include <LibThreading/Mutex.h>
namespace Audio {

View file

@ -8,7 +8,6 @@
#include "Forward.h"
#include "PlaybackStream.h"
#include "SampleFormats.h"
#include <AK/AtomicRefCounted.h>
#include <AK/Error.h>
#include <AK/NonnullRefPtr.h>

View file

@ -5,6 +5,7 @@
*/
#include "SampleFormats.h"
#include <AK/Assertions.h>
namespace Audio {

View file

@ -6,7 +6,6 @@
#pragma once
#include <AK/ByteString.h>
#include <AK/Types.h>
namespace Audio {

View file

@ -4,8 +4,8 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Math.h>
#include <AK/StdLibExtras.h>
#include <LibGfx/Matrix.h>
#include <LibGfx/Matrix3x3.h>
#include <LibGfx/Matrix4x4.h>
#include <LibMedia/Color/ColorPrimaries.h>
#include <LibMedia/Color/TransferCharacteristics.h>

View file

@ -7,6 +7,7 @@
#include <AK/Debug.h>
#include <AK/Function.h>
#include <AK/IntegralMath.h>
#include <AK/Math.h>
#include <AK/Optional.h>
#include <AK/Time.h>

View file

@ -7,9 +7,9 @@
#pragma once
#include <AK/IntegralMath.h>
#include <AK/NonnullOwnPtr.h>
#include <AK/NonnullRefPtr.h>
#include <AK/Optional.h>
#include <AK/OwnPtr.h>
#include <LibCore/MappedFile.h>
#include <LibMedia/DecoderError.h>

View file

@ -13,7 +13,6 @@
#include <AK/Time.h>
#include <LibCore/SharedCircularQueue.h>
#include <LibGfx/Bitmap.h>
#include <LibMedia/Containers/Matroska/Document.h>
#include <LibMedia/Demuxer.h>
#include <LibThreading/ConditionVariable.h>
#include <LibThreading/Mutex.h>

View file

@ -4,8 +4,8 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/FixedArray.h>
#include <AK/NonnullOwnPtr.h>
#include <AK/OwnPtr.h>
#include <LibMedia/Color/ColorConverter.h>
#include "VideoFrame.h"

View file

@ -6,8 +6,6 @@
#pragma once
#include <AK/ByteBuffer.h>
#include <AK/FixedArray.h>
#include <AK/Time.h>
#include <LibGfx/Bitmap.h>
#include <LibGfx/Size.h>

View file

@ -8,15 +8,11 @@
#include "RegexBytecodeStreamOptimizer.h"
#include "RegexMatch.h"
#include "RegexOptions.h"
#include <AK/Concepts.h>
#include <AK/DisjointChunks.h>
#include <AK/Forward.h>
#include <AK/HashMap.h>
#include <AK/NonnullOwnPtr.h>
#include <AK/OwnPtr.h>
#include <AK/Traits.h>
#include <AK/TypeCasts.h>
#include <AK/Types.h>
#include <AK/Vector.h>

View file

@ -8,7 +8,6 @@
#include <AK/Assertions.h>
#include <AK/Debug.h>
#include <AK/Format.h>
#include <stdio.h>
namespace regex {

View file

@ -13,9 +13,6 @@
#include <AK/Forward.h>
#include <AK/GenericLexer.h>
#include <AK/HashMap.h>
#include <AK/Types.h>
#include <AK/Utf32View.h>
#include <AK/Vector.h>
#include <ctype.h>

View file

@ -16,7 +16,6 @@
#include <AK/StringBuilder.h>
#include <AK/StringUtils.h>
#include <AK/TemporaryChange.h>
#include <AK/Utf16View.h>
#include <LibUnicode/CharacterTypes.h>
namespace regex {

View file

@ -12,7 +12,6 @@
#include "RegexOptions.h"
#include <AK/Forward.h>
#include <AK/StringBuilder.h>
#include <AK/Types.h>
#include <AK/Vector.h>
#include <LibUnicode/Forward.h>

View file

@ -7,6 +7,7 @@
#include <AK/Debug.h>
#include <AK/Endian.h>
#include <AK/MemoryStream.h>
#include <AK/Random.h>
#include <LibCore/EventLoop.h>
#include <LibCore/Timer.h>
#include <LibTLS/TLSv12.h>

View file

@ -9,8 +9,7 @@
#include <AK/Function.h>
#include <AK/HashMap.h>
#include <AK/HashTable.h>
#include <AK/OwnPtr.h>
#include <AK/Result.h>
#include <AK/NonnullOwnPtr.h>
#include <AK/StackInfo.h>
#include <AK/UFixedBigInt.h>
#include <LibWasm/Types.h>

View file

@ -5,7 +5,6 @@
*/
#include <AK/HashTable.h>
#include <AK/Result.h>
#include <AK/SourceLocation.h>
#include <AK/TemporaryChange.h>
#include <AK/Try.h>

View file

@ -9,7 +9,6 @@
#include <AK/Endian.h>
#include <AK/LEB128.h>
#include <AK/MemoryStream.h>
#include <AK/ScopeGuard.h>
#include <AK/ScopeLogger.h>
#include <AK/UFixedBigInt.h>
#include <LibWasm/Types.h>

View file

@ -8,13 +8,10 @@
#include <AK/Debug.h>
#include <AK/FlyString.h>
#include <AK/Random.h>
#include <AK/SourceLocation.h>
#include <AK/Span.h>
#include <AK/Tuple.h>
#include <LibCore/File.h>
#include <LibWasm/AbstractMachine/Interpreter.h>
#include <LibWasm/Printer/Printer.h>
#include <LibWasm/AbstractMachine/Configuration.h>
#include <LibWasm/Wasi.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <time.h>

View file

@ -102,8 +102,13 @@ Optional<StyleProperty> PropertyOwningCSSStyleDeclaration::property(PropertyID p
}
// https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-setproperty
WebIDL::ExceptionOr<void> PropertyOwningCSSStyleDeclaration::set_property(PropertyID property_id, StringView value, StringView priority)
WebIDL::ExceptionOr<void> PropertyOwningCSSStyleDeclaration::set_property(StringView property_name, StringView value, StringView priority)
{
auto maybe_property_id = property_id_from_string(property_name);
if (!maybe_property_id.has_value())
return {};
auto property_id = maybe_property_id.value();
// 1. If the computed flag is set, then throw a NoModificationAllowedError exception.
// NOTE: This is handled by the virtual override in ResolvedCSSStyleDeclaration.
@ -114,7 +119,7 @@ WebIDL::ExceptionOr<void> PropertyOwningCSSStyleDeclaration::set_property(Proper
// 3. If value is the empty string, invoke removeProperty() with property as argument and return.
if (value.is_empty()) {
MUST(remove_property(property_id));
MUST(remove_property(property_name));
return {};
}
@ -146,10 +151,22 @@ WebIDL::ExceptionOr<void> PropertyOwningCSSStyleDeclaration::set_property(Proper
}
// 9. Otherwise,
else {
// let updated be the result of set the CSS declaration property with value component value list,
// with the important flag set if priority is not the empty string, and unset otherwise,
// and with the list of declarations being the declarations.
updated = set_a_css_declaration(property_id, *component_value_list, !priority.is_empty() ? Important::Yes : Important::No);
if (property_id == PropertyID::Custom) {
auto custom_name = FlyString::from_utf8_without_validation(property_name.bytes());
StyleProperty style_property {
.important = !priority.is_empty() ? Important::Yes : Important::No,
.property_id = property_id,
.value = component_value_list.release_nonnull(),
.custom_name = custom_name,
};
m_custom_properties.set(custom_name, style_property);
updated = true;
} else {
// let updated be the result of set the CSS declaration property with value component value list,
// with the important flag set if priority is not the empty string, and unset otherwise,
// and with the list of declarations being the declarations.
updated = set_a_css_declaration(property_id, *component_value_list, !priority.is_empty() ? Important::Yes : Important::No);
}
}
// 10. If updated is true, update style attribute for the CSS declaration block.
@ -160,8 +177,12 @@ WebIDL::ExceptionOr<void> PropertyOwningCSSStyleDeclaration::set_property(Proper
}
// https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-removeproperty
WebIDL::ExceptionOr<String> PropertyOwningCSSStyleDeclaration::remove_property(PropertyID property_id)
WebIDL::ExceptionOr<String> PropertyOwningCSSStyleDeclaration::remove_property(StringView property_name)
{
auto property_id = property_id_from_string(property_name);
if (!property_id.has_value())
return String {};
// 1. If the computed flag is set, then throw a NoModificationAllowedError exception.
// NOTE: This is handled by the virtual override in ResolvedCSSStyleDeclaration.
@ -169,8 +190,7 @@ WebIDL::ExceptionOr<String> PropertyOwningCSSStyleDeclaration::remove_property(P
// NOTE: We've already converted it to a PropertyID enum value.
// 3. Let value be the return value of invoking getPropertyValue() with property as argument.
// FIXME: The trip through string_from_property_id() here is silly.
auto value = get_property_value(string_from_property_id(property_id));
auto value = get_property_value(property_name);
// 4. Let removed be false.
bool removed = false;
@ -180,7 +200,12 @@ WebIDL::ExceptionOr<String> PropertyOwningCSSStyleDeclaration::remove_property(P
// 2. Remove that CSS declaration and let removed be true.
// 6. Otherwise, if property is a case-sensitive match for a property name of a CSS declaration in the declarations, remove that CSS declaration and let removed be true.
removed = m_properties.remove_first_matching([&](auto& entry) { return entry.property_id == property_id; });
if (property_id == PropertyID::Custom) {
auto custom_name = FlyString::from_utf8_without_validation(property_name.bytes());
removed = m_custom_properties.remove(custom_name);
} else {
removed = m_properties.remove_first_matching([&](auto& entry) { return entry.property_id == property_id; });
}
// 7. If removed is true, Update style attribute for the CSS declaration block.
if (removed)
@ -241,6 +266,14 @@ String CSSStyleDeclaration::get_property_value(StringView property_name) const
if (!property_id.has_value())
return {};
if (property_id.value() == PropertyID::Custom) {
auto maybe_custom_property = custom_property(FlyString::from_utf8_without_validation(property_name.bytes()));
if (maybe_custom_property.has_value()) {
return maybe_custom_property.value().value->to_string();
}
return {};
}
// 2. If property is a shorthand property, then follow these substeps:
if (property_is_shorthand(property_id.value())) {
// 1. Let list be a new empty array.
@ -285,26 +318,26 @@ StringView CSSStyleDeclaration::get_property_priority(StringView property_name)
auto property_id = property_id_from_string(property_name);
if (!property_id.has_value())
return {};
if (property_id.value() == PropertyID::Custom) {
auto maybe_custom_property = custom_property(FlyString::from_utf8_without_validation(property_name.bytes()));
if (!maybe_custom_property.has_value())
return {};
return maybe_custom_property.value().important == Important::Yes ? "important"sv : ""sv;
}
auto maybe_property = property(property_id.value());
if (!maybe_property.has_value())
return {};
return maybe_property->important == Important::Yes ? "important"sv : ""sv;
}
WebIDL::ExceptionOr<void> CSSStyleDeclaration::set_property(StringView property_name, StringView css_text, StringView priority)
WebIDL::ExceptionOr<void> CSSStyleDeclaration::set_property(PropertyID property_id, StringView css_text, StringView priority)
{
auto property_id = property_id_from_string(property_name);
if (!property_id.has_value())
return {};
return set_property(property_id.value(), css_text, priority);
return set_property(string_from_property_id(property_id), css_text, priority);
}
WebIDL::ExceptionOr<String> CSSStyleDeclaration::remove_property(StringView property_name)
WebIDL::ExceptionOr<String> CSSStyleDeclaration::remove_property(PropertyID property_name)
{
auto property_id = property_id_from_string(property_name);
if (!property_id.has_value())
return String {};
return remove_property(property_id.value());
return remove_property(string_from_property_id(property_name));
}
// https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-csstext

View file

@ -29,12 +29,13 @@ public:
virtual String item(size_t index) const = 0;
virtual Optional<StyleProperty> property(PropertyID) const = 0;
virtual Optional<StyleProperty> custom_property(FlyString const& custom_property_name) const = 0;
virtual WebIDL::ExceptionOr<void> set_property(PropertyID, StringView css_text, StringView priority = ""sv) = 0;
virtual WebIDL::ExceptionOr<String> remove_property(PropertyID) = 0;
virtual WebIDL::ExceptionOr<void> set_property(PropertyID, StringView css_text, StringView priority = ""sv);
virtual WebIDL::ExceptionOr<String> remove_property(PropertyID);
virtual WebIDL::ExceptionOr<void> set_property(StringView property_name, StringView css_text, StringView priority);
virtual WebIDL::ExceptionOr<String> remove_property(StringView property_name);
virtual WebIDL::ExceptionOr<void> set_property(StringView property_name, StringView css_text, StringView priority) = 0;
virtual WebIDL::ExceptionOr<String> remove_property(StringView property_name) = 0;
String get_property_value(StringView property) const;
StringView get_property_priority(StringView property) const;
@ -75,13 +76,13 @@ public:
virtual String item(size_t index) const override;
virtual Optional<StyleProperty> property(PropertyID) const override;
virtual Optional<StyleProperty> custom_property(FlyString const& custom_property_name) const override { return m_custom_properties.get(custom_property_name); }
virtual WebIDL::ExceptionOr<void> set_property(PropertyID, StringView css_text, StringView priority) override;
virtual WebIDL::ExceptionOr<String> remove_property(PropertyID) override;
virtual WebIDL::ExceptionOr<void> set_property(StringView property_name, StringView css_text, StringView priority) override;
virtual WebIDL::ExceptionOr<String> remove_property(StringView property_name) override;
Vector<StyleProperty> const& properties() const { return m_properties; }
HashMap<FlyString, StyleProperty> const& custom_properties() const { return m_custom_properties; }
Optional<StyleProperty> custom_property(FlyString const& custom_property_name) const { return m_custom_properties.get(custom_property_name); }
size_t custom_property_count() const { return m_custom_properties.size(); }
virtual String serialized() const final override;

View file

@ -481,4 +481,165 @@ int CSSStyleValue::to_font_width() const
return width;
}
Gfx::FontVariantAlternates CSSStyleValue::to_font_variant_alternates() const
{
VERIFY(is_keyword());
switch (as_keyword().keyword()) {
case Keyword::Normal:
return Gfx::FontVariantAlternates { .normal = true };
case Keyword::HistoricalForms:
return Gfx::FontVariantAlternates { .historical_forms = true };
default:
VERIFY_NOT_REACHED();
}
}
Optional<FontVariantCaps> CSSStyleValue::to_font_variant_caps() const
{
VERIFY(is_keyword());
return keyword_to_font_variant_caps(as_keyword().keyword());
}
Gfx::FontVariantEastAsian CSSStyleValue::to_font_variant_east_asian() const
{
VERIFY(is_value_list());
auto& list = as_value_list();
Gfx::FontVariantEastAsian east_asian {};
for (auto& value : list.values()) {
VERIFY(value->is_keyword());
switch (value->as_keyword().keyword()) {
case Keyword::Normal:
east_asian.normal = true;
return east_asian;
case Keyword::Jis78:
east_asian.variant = Gfx::FontVariantEastAsian::Variant::Jis78;
break;
case Keyword::Jis83:
east_asian.variant = Gfx::FontVariantEastAsian::Variant::Jis83;
break;
case Keyword::Jis90:
east_asian.variant = Gfx::FontVariantEastAsian::Variant::Jis90;
break;
case Keyword::Jis04:
east_asian.variant = Gfx::FontVariantEastAsian::Variant::Jis04;
break;
case Keyword::Simplified:
east_asian.variant = Gfx::FontVariantEastAsian::Variant::Simplified;
break;
case Keyword::Traditional:
east_asian.variant = Gfx::FontVariantEastAsian::Variant::Traditional;
break;
case Keyword::FullWidth:
east_asian.width = Gfx::FontVariantEastAsian::Width::FullWidth;
break;
case Keyword::ProportionalWidth:
east_asian.width = Gfx::FontVariantEastAsian::Width::Proportional;
break;
case Keyword::Ruby:
east_asian.ruby = true;
break;
default:
VERIFY_NOT_REACHED();
break;
}
}
return east_asian;
}
Gfx::FontVariantLigatures CSSStyleValue::to_font_variant_ligatures() const
{
VERIFY(is_value_list());
auto& list = as_value_list();
Gfx::FontVariantLigatures ligatures;
for (auto& value : list.values()) {
VERIFY(value->is_keyword());
switch (value->as_keyword().keyword()) {
case Keyword::Normal:
ligatures.normal = true;
return ligatures;
case Keyword::None:
ligatures.none = true;
return ligatures;
case Keyword::CommonLigatures:
ligatures.common = Gfx::FontVariantLigatures::Common::Common;
break;
case Keyword::NoCommonLigatures:
ligatures.common = Gfx::FontVariantLigatures::Common::NoCommon;
break;
case Keyword::DiscretionaryLigatures:
ligatures.discretionary = Gfx::FontVariantLigatures::Discretionary::Discretionary;
break;
case Keyword::NoDiscretionaryLigatures:
ligatures.discretionary = Gfx::FontVariantLigatures::Discretionary::NoDiscretionary;
break;
case Keyword::HistoricalLigatures:
ligatures.historical = Gfx::FontVariantLigatures::Historical::Historical;
break;
case Keyword::NoHistoricalLigatures:
ligatures.historical = Gfx::FontVariantLigatures::Historical::NoHistorical;
break;
case Keyword::Contextual:
ligatures.contextual = Gfx::FontVariantLigatures::Contextual::Contextual;
break;
case Keyword::NoContextual:
ligatures.contextual = Gfx::FontVariantLigatures::Contextual::NoContextual;
break;
default:
VERIFY_NOT_REACHED();
break;
}
}
return ligatures;
}
Gfx::FontVariantNumeric CSSStyleValue::to_font_variant_numeric() const
{
VERIFY(is_value_list());
auto& list = as_value_list();
Gfx::FontVariantNumeric numeric {};
for (auto& value : list.values()) {
VERIFY(value->is_keyword());
switch (value->as_keyword().keyword()) {
case Keyword::Normal:
numeric.normal = true;
return numeric;
case Keyword::Ordinal:
numeric.ordinal = true;
break;
case Keyword::SlashedZero:
numeric.slashed_zero = true;
break;
case Keyword::OldstyleNums:
numeric.figure = Gfx::FontVariantNumeric::Figure::Oldstyle;
break;
case Keyword::LiningNums:
numeric.figure = Gfx::FontVariantNumeric::Figure::Lining;
break;
case Keyword::ProportionalNums:
numeric.spacing = Gfx::FontVariantNumeric::Spacing::Proportional;
break;
case Keyword::TabularNums:
numeric.spacing = Gfx::FontVariantNumeric::Spacing::Tabular;
break;
case Keyword::DiagonalFractions:
numeric.fraction = Gfx::FontVariantNumeric::Fraction::Diagonal;
break;
case Keyword::StackedFractions:
numeric.fraction = Gfx::FontVariantNumeric::Fraction::Stacked;
break;
default:
VERIFY_NOT_REACHED();
break;
}
}
return numeric;
}
Optional<FontVariantPosition> CSSStyleValue::to_font_variant_position() const
{
VERIFY(is_keyword());
return keyword_to_font_variant_position(as_keyword().keyword());
}
}

View file

@ -20,6 +20,7 @@
#include <AK/Vector.h>
#include <AK/WeakPtr.h>
#include <LibGfx/Color.h>
#include <LibGfx/Font/FontVariant.h>
#include <LibURL/URL.h>
#include <LibWeb/CSS/Enums.h>
#include <LibWeb/CSS/Keyword.h>
@ -104,6 +105,7 @@ public:
Edge,
FilterValueList,
Flex,
FontVariant,
Frequency,
GridAutoFlow,
GridTemplateArea,
@ -355,6 +357,12 @@ public:
[[nodiscard]] int to_font_weight() const;
[[nodiscard]] int to_font_slope() const;
[[nodiscard]] int to_font_width() const;
[[nodiscard]] Gfx::FontVariantAlternates to_font_variant_alternates() const;
[[nodiscard]] Optional<FontVariantCaps> to_font_variant_caps() const;
[[nodiscard]] Gfx::FontVariantEastAsian to_font_variant_east_asian() const;
[[nodiscard]] Gfx::FontVariantLigatures to_font_variant_ligatures() const;
[[nodiscard]] Gfx::FontVariantNumeric to_font_variant_numeric() const;
[[nodiscard]] Optional<FontVariantPosition> to_font_variant_position() const;
virtual bool equals(CSSStyleValue const& other) const = 0;

View file

@ -97,7 +97,6 @@ public:
static AspectRatio aspect_ratio() { return AspectRatio { true, {} }; }
static CSSPixels font_size() { return 16; }
static int font_weight() { return 400; }
static CSS::FontVariant font_variant() { return CSS::FontVariant::Normal; }
static CSSPixels line_height() { return 0; }
static CSS::Float float_() { return CSS::Float::None; }
static CSS::Length border_spacing() { return CSS::Length::make_px(0); }
@ -511,7 +510,12 @@ public:
Gfx::FontCascadeList const& font_list() const { return *m_inherited.font_list; }
CSSPixels font_size() const { return m_inherited.font_size; }
int font_weight() const { return m_inherited.font_weight; }
CSS::FontVariant font_variant() const { return m_inherited.font_variant; }
Gfx::FontVariantAlternates font_variant_alternates() const { return m_inherited.font_variant_alternates; }
FontVariantCaps font_variant_caps() const { return m_inherited.font_variant_caps; }
Gfx::FontVariantEastAsian font_variant_east_asian() const { return m_inherited.font_variant_east_asian; }
Gfx::FontVariantLigatures font_variant_ligatures() const { return m_inherited.font_variant_ligatures; }
Gfx::FontVariantNumeric font_variant_numeric() const { return m_inherited.font_variant_numeric; }
FontVariantPosition font_variant_position() const { return m_inherited.font_variant_position; }
Optional<FlyString> font_language_override() const { return m_inherited.font_language_override; }
Optional<HashMap<FlyString, IntegerOrCalculated>> font_feature_settings() const { return m_inherited.font_feature_settings; }
Optional<HashMap<FlyString, NumberOrCalculated>> font_variation_settings() const { return m_inherited.font_variation_settings; }
@ -545,7 +549,12 @@ protected:
RefPtr<Gfx::FontCascadeList> font_list {};
CSSPixels font_size { InitialValues::font_size() };
int font_weight { InitialValues::font_weight() };
CSS::FontVariant font_variant { InitialValues::font_variant() };
Gfx::FontVariantAlternates font_variant_alternates { .normal = true };
FontVariantCaps font_variant_caps { FontVariantCaps::Normal };
Gfx::FontVariantEastAsian font_variant_east_asian { .normal = true };
Gfx::FontVariantLigatures font_variant_ligatures { .normal = true };
Gfx::FontVariantNumeric font_variant_numeric { .normal = true };
FontVariantPosition font_variant_position { FontVariantPosition::Normal };
Optional<FlyString> font_language_override;
Optional<HashMap<FlyString, IntegerOrCalculated>> font_feature_settings;
Optional<HashMap<FlyString, NumberOrCalculated>> font_variation_settings;
@ -717,7 +726,12 @@ public:
void set_font_list(NonnullRefPtr<Gfx::FontCascadeList> font_list) { m_inherited.font_list = move(font_list); }
void set_font_size(CSSPixels font_size) { m_inherited.font_size = font_size; }
void set_font_weight(int font_weight) { m_inherited.font_weight = font_weight; }
void set_font_variant(CSS::FontVariant font_variant) { m_inherited.font_variant = font_variant; }
void set_font_variant_alternates(Gfx::FontVariantAlternates font_variant_alternates) { m_inherited.font_variant_alternates = font_variant_alternates; }
void set_font_variant_caps(FontVariantCaps font_variant_caps) { m_inherited.font_variant_caps = font_variant_caps; }
void set_font_variant_east_asian(Gfx::FontVariantEastAsian font_variant_east_asian) { m_inherited.font_variant_east_asian = font_variant_east_asian; }
void set_font_variant_ligatures(Gfx::FontVariantLigatures font_variant_ligatures) { m_inherited.font_variant_ligatures = font_variant_ligatures; }
void set_font_variant_numeric(Gfx::FontVariantNumeric font_variant_numeric) { m_inherited.font_variant_numeric = font_variant_numeric; }
void set_font_variant_position(FontVariantPosition font_variant_position) { m_inherited.font_variant_position = font_variant_position; }
void set_font_language_override(Optional<FlyString> font_language_override) { m_inherited.font_language_override = font_language_override; }
void set_font_feature_settings(Optional<HashMap<FlyString, IntegerOrCalculated>> value) { m_inherited.font_feature_settings = move(value); }
void set_font_variation_settings(Optional<HashMap<FlyString, NumberOrCalculated>> value) { m_inherited.font_variation_settings = move(value); }

View file

@ -221,9 +221,64 @@
"fallback",
"optional"
],
"font-variant": [
"font-variant-alternates": [
"normal",
"small-caps"
"historical-forms"
],
"font-variant-caps": [
"normal",
"small-caps",
"all-small-caps",
"petite-caps",
"all-petite-caps",
"unicase",
"titling-caps"
],
"font-variant-east-asian": [
"normal",
"ruby",
"jis78",
"jis83",
"jis90",
"jis04",
"simplified",
"traditional",
"full-width",
"proportional-width"
],
"font-variant-emoji": [
"normal",
"text",
"emoji",
"unicode"
],
"font-variant-ligatures": [
"normal",
"none",
"common-ligatures",
"no-common-ligatures",
"discretionary-ligatures",
"no-discretionary-ligatures",
"historical-ligatures",
"no-historical-ligatures",
"contextual",
"no-contextual"
],
"font-variant-numeric": [
"normal",
"ordinal",
"slashed-zero",
"lining-nums",
"oldstyle-nums",
"proportional-nums",
"tabular-nums",
"diagonal-fractions",
"stacked-fractions"
],
"font-variant-position": [
"normal",
"sub",
"super"
],
"font-width": [
"ultra-condensed",

View file

@ -28,7 +28,7 @@ namespace Web::CSS {
GC_DEFINE_ALLOCATOR(FontFaceSet);
// https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-fontfaceset
GC::Ref<FontFaceSet> FontFaceSet::construct_impl(JS::Realm& realm, Vector<GC::Root<FontFace>> const& initial_faces)
GC::Ref<FontFaceSet> FontFaceSet::construct_impl(Web::Page& page, JS::Realm& realm, Vector<GC::Root<FontFace>> const& initial_faces)
{
auto ready_promise = WebIDL::create_promise(realm);
auto set_entries = JS::Set::create(realm);
@ -37,16 +37,17 @@ GC::Ref<FontFaceSet> FontFaceSet::construct_impl(JS::Realm& realm, Vector<GC::Ro
for (auto const& face : initial_faces)
set_entries->set_add(face);
return realm.create<FontFaceSet>(realm, ready_promise, set_entries);
return realm.create<FontFaceSet>(page, realm, ready_promise, set_entries);
}
GC::Ref<FontFaceSet> FontFaceSet::create(JS::Realm& realm)
GC::Ref<FontFaceSet> FontFaceSet::create(Web::Page& page, JS::Realm& realm)
{
return construct_impl(realm, {});
return construct_impl(page, realm, {});
}
FontFaceSet::FontFaceSet(JS::Realm& realm, GC::Ref<WebIDL::Promise> ready_promise, GC::Ref<JS::Set> set_entries)
FontFaceSet::FontFaceSet(Web::Page& page, JS::Realm& realm, GC::Ref<WebIDL::Promise> ready_promise, GC::Ref<JS::Set> set_entries)
: DOM::EventTarget(realm)
, m_page(page)
, m_set_entries(set_entries)
, m_ready_promise(ready_promise)
, m_status(Bindings::FontFaceSetLoadStatus::Loaded)
@ -63,6 +64,7 @@ void FontFaceSet::initialize(JS::Realm& realm)
void FontFaceSet::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_page);
visitor.visit(m_set_entries);
visitor.visit(m_ready_promise);
visitor.visit(m_loading_fonts);
@ -289,7 +291,10 @@ GC::Ref<WebIDL::Promise> FontFaceSet::ready() const
void FontFaceSet::resolve_ready_promise()
{
dbgln("FontFaceSet::resolve_ready_promise(): {}", m_page->url());
WebIDL::resolve_promise(realm(), m_ready_promise);
m_page->client().page_did_finish_loading_page_and_fonts(m_page->url());
}
}

View file

@ -13,6 +13,8 @@
#include <LibWeb/Bindings/PlatformObject.h>
#include <LibWeb/CSS/FontFace.h>
#include <LibWeb/DOM/EventTarget.h>
#include <LibWeb/HTML/TraversableNavigable.h>
#include <LibWeb/Page/Page.h>
namespace Web::CSS {
@ -21,8 +23,8 @@ class FontFaceSet final : public DOM::EventTarget {
GC_DECLARE_ALLOCATOR(FontFaceSet);
public:
[[nodiscard]] static GC::Ref<FontFaceSet> construct_impl(JS::Realm&, Vector<GC::Root<FontFace>> const& initial_faces);
[[nodiscard]] static GC::Ref<FontFaceSet> create(JS::Realm&);
[[nodiscard]] static GC::Ref<FontFaceSet> construct_impl(Web::Page&, JS::Realm&, Vector<GC::Root<FontFace>> const& initial_faces);
[[nodiscard]] static GC::Ref<FontFaceSet> create(Web::Page&, JS::Realm&);
virtual ~FontFaceSet() override = default;
GC::Ref<JS::Set> set_entries() const { return m_set_entries; }
@ -46,11 +48,12 @@ public:
void resolve_ready_promise();
private:
FontFaceSet(JS::Realm&, GC::Ref<WebIDL::Promise> ready_promise, GC::Ref<JS::Set> set_entries);
FontFaceSet(Web::Page&, JS::Realm&, GC::Ref<WebIDL::Promise> ready_promise, GC::Ref<JS::Set> set_entries);
virtual void initialize(JS::Realm&) override;
virtual void visit_edges(Cell::Visitor&) override;
GC::Ref<Web::Page> m_page;
GC::Ref<JS::Set> m_set_entries;
GC::Ref<WebIDL::Promise> m_ready_promise; // [[ReadyPromise]]

View file

@ -67,7 +67,9 @@
"additive",
"alias",
"all",
"all-petite-caps",
"all-scroll",
"all-small-caps",
"alpha",
"alternate",
"alternate-reverse",
@ -114,6 +116,7 @@
"collapse",
"column",
"column-reverse",
"common-ligatures",
"compact",
"condensed",
"contain",
@ -121,6 +124,7 @@
"content-box",
"contents",
"context-menu",
"contextual",
"copy",
"cover",
"crisp-edges",
@ -133,7 +137,9 @@
"decimal",
"decimal-leading-zero",
"default",
"diagonal-fractions",
"disc",
"discretionary-ligatures",
"disclosure-closed",
"disclosure-open",
"distribute",
@ -147,6 +153,7 @@
"ease-out",
"ellipsis",
"embed",
"emoji",
"enabled",
"end",
"evenodd",
@ -185,6 +192,8 @@
"high-quality",
"highlight",
"highlighttext",
"historical-forms",
"historical-ligatures",
"horizontal-tb",
"hover",
"inactiveborder",
@ -213,6 +222,10 @@
"isolate",
"isolate-override",
"italic",
"jis04",
"jis78",
"jis83",
"jis90",
"jump-both",
"jump-end",
"jump-none",
@ -229,6 +242,7 @@
"lighter",
"line-through",
"linear",
"lining-nums",
"linktext",
"list-item",
"listbox",
@ -262,8 +276,12 @@
"nearest",
"nesw-resize",
"no-close-quote",
"no-common-ligatures",
"no-contextual",
"no-discretionary-ligatures",
"no-drop",
"no-open-quote",
"no-historical-ligatures",
"no-preference",
"no-repeat",
"none",
@ -276,12 +294,14 @@
"nwse-resize",
"oblique",
"off",
"oldstyle-nums",
"on",
"opaque",
"open-quote",
"optimizequality",
"optimizespeed",
"optional",
"ordinal",
"outset",
"outside",
"overline",
@ -289,6 +309,7 @@
"padding-box",
"paged",
"paused",
"petite-caps",
"pixelated",
"plaintext",
"pointer",
@ -299,6 +320,8 @@
"progress",
"progress-bar",
"progressive",
"proportional-nums",
"proportional-width",
"push-button",
"radio",
"rec2020",
@ -342,6 +365,8 @@
"serif",
"sideways-lr",
"sideways-rl",
"simplified",
"slashed-zero",
"slider-horizontal",
"slow",
"small",
@ -357,6 +382,7 @@
"square-button",
"srgb",
"stable",
"stacked-fractions",
"standalone",
"standard",
"start",
@ -378,6 +404,7 @@
"table-header-group",
"table-row",
"table-row-group",
"tabular-nums",
"text",
"text-bottom",
"text-top",
@ -385,6 +412,8 @@
"textfield",
"thick",
"thin",
"titling-caps",
"traditional",
"threeddarkshadow",
"threedface",
"threedhighlight",
@ -399,6 +428,8 @@
"ultra-condensed",
"ultra-expanded",
"underline",
"unicase",
"unicode",
"unsafe",
"unset",
"up",

View file

@ -5903,6 +5903,455 @@ RefPtr<CSSStyleValue> Parser::parse_font_variation_settings_value(TokenStream<Co
return StyleValueList::create(move(axis_tags), StyleValueList::Separator::Comma);
}
RefPtr<CSSStyleValue> Parser::parse_font_variant(TokenStream<ComponentValue>& tokens)
{
// 6.11 https://drafts.csswg.org/css-fonts/#propdef-font-variant
// normal | none |
// [ [ <common-lig-values> || <discretionary-lig-values> || <historical-lig-values> || <contextual-alt-values> ]
// || [ small-caps | all-small-caps | petite-caps | all-petite-caps | unicase | titling-caps ] ||
// [ FIXME: stylistic(<feature-value-name>) ||
// historical-forms ||
// FIXME: styleset(<feature-value-name>#) ||
// FIXME: character-variant(<feature-value-name>#) ||
// FIXME: swash(<feature-value-name>) ||
// FIXME: ornaments(<feature-value-name>) ||
// FIXME: annotation(<feature-value-name>) ] ||
// [ <numeric-figure-values> || <numeric-spacing-values> || <numeric-fraction-values> ||
// ordinal || slashed-zero ] || [ <east-asian-variant-values> || <east-asian-width-values> || ruby ] ||
// [ sub | super ] || [ text | emoji | unicode ] ]
bool has_caps = false;
bool has_alternates = false;
bool has_common_ligatures = false;
bool has_discretionary_ligatures = false;
bool has_historical_ligatures = false;
bool has_contextual = false;
bool has_numeric_figures = false;
bool has_numeric_spacing = false;
bool has_numeric_fractions = false;
bool has_numeric_ordinals = false;
bool has_numeric_slashed_zero = false;
bool has_east_asian_variant = false;
bool has_east_asian_width = false;
bool has_east_asian_ruby = false;
bool has_position = false;
Keyword alternates_value = Keyword::Normal;
Keyword caps_value = Keyword::Normal;
Keyword position_value = Keyword::Normal;
StyleValueVector east_asian_values;
StyleValueVector ligatures_values;
StyleValueVector numeric_values;
StyleValueVector position_values;
// normal
if (auto parsed_value = parse_all_as_single_keyword_value(tokens, Keyword::Normal)) {
/* do nothing */
// none
} else if (auto parsed_value = parse_all_as_single_keyword_value(tokens, Keyword::None)) {
// FIXME
} else {
while (tokens.has_next_token()) {
auto maybe_value = parse_keyword_value(tokens);
if (!maybe_value)
break;
auto value = maybe_value.release_nonnull();
if (!value->is_keyword()) {
// FIXME: alternate functions such as stylistic()
return nullptr;
}
auto keyword = value->to_keyword();
switch (keyword) {
// <common-lig-values> = [ common-ligatures | no-common-ligatures ]
case Keyword::CommonLigatures:
case Keyword::NoCommonLigatures:
if (has_common_ligatures)
return nullptr;
ligatures_values.append(value);
has_common_ligatures = true;
break;
// <discretionary-lig-values> = [ discretionary-ligatures | no-discretionary-ligatures ]
case Keyword::DiscretionaryLigatures:
case Keyword::NoDiscretionaryLigatures:
if (has_discretionary_ligatures)
return nullptr;
ligatures_values.append(value);
has_discretionary_ligatures = true;
break;
// <historical-lig-values> = [ historical-ligatures | no-historical-ligatures ]
case Keyword::HistoricalLigatures:
case Keyword::NoHistoricalLigatures:
if (has_historical_ligatures)
return nullptr;
ligatures_values.append(value);
has_historical_ligatures = true;
break;
// <contextual-alt-values> = [ contextual | no-contextual ]
case Keyword::Contextual:
case Keyword::NoContextual:
if (has_contextual)
return nullptr;
ligatures_values.append(value);
has_contextual = true;
break;
// historical-forms
case Keyword::HistoricalForms:
if (has_alternates)
return nullptr;
alternates_value = keyword;
has_alternates = true;
break;
// [ small-caps | all-small-caps | petite-caps | all-petite-caps | unicase | titling-caps ]
case Keyword::SmallCaps:
case Keyword::AllSmallCaps:
case Keyword::PetiteCaps:
case Keyword::AllPetiteCaps:
case Keyword::Unicase:
case Keyword::TitlingCaps:
if (has_caps)
return nullptr;
caps_value = keyword;
has_caps = true;
break;
// <numeric-figure-values> = [ lining-nums | oldstyle-nums ]
case Keyword::LiningNums:
case Keyword::OldstyleNums:
if (has_numeric_figures)
return nullptr;
numeric_values.append(value);
has_numeric_figures = true;
break;
// <numeric-spacing-values> = [ proportional-nums | tabular-nums ]
case Keyword::ProportionalNums:
case Keyword::TabularNums:
if (has_numeric_spacing)
return nullptr;
numeric_values.append(value);
has_numeric_spacing = true;
break;
// <numeric-fraction-values> = [ diagonal-fractions | stacked-fractions]
case Keyword::DiagonalFractions:
case Keyword::StackedFractions:
if (has_numeric_fractions)
return nullptr;
numeric_values.append(value);
has_numeric_fractions = true;
break;
// ordinal
case Keyword::Ordinal:
if (has_numeric_ordinals)
return nullptr;
numeric_values.append(value);
has_numeric_ordinals = true;
break;
case Keyword::SlashedZero:
if (has_numeric_slashed_zero)
return nullptr;
numeric_values.append(value);
has_numeric_slashed_zero = true;
break;
// <east-asian-variant-values> = [ jis78 | jis83 | jis90 | jis04 | simplified | traditional ]
case Keyword::Jis78:
case Keyword::Jis83:
case Keyword::Jis90:
case Keyword::Jis04:
case Keyword::Simplified:
case Keyword::Traditional:
if (has_east_asian_variant)
return nullptr;
east_asian_values.append(value);
has_east_asian_variant = true;
break;
// <east-asian-width-values> = [ full-width | proportional-width ]
case Keyword::FullWidth:
case Keyword::ProportionalWidth:
if (has_east_asian_width)
return nullptr;
east_asian_values.append(value);
has_east_asian_width = true;
break;
// ruby
case Keyword::Ruby:
if (has_east_asian_ruby)
return nullptr;
east_asian_values.append(value);
has_east_asian_ruby = true;
break;
// sub | super
case Keyword::Sub:
case Keyword::Super:
if (has_position)
return nullptr;
position_value = keyword;
has_position = true;
break;
default:
break;
}
}
}
if (ligatures_values.is_empty())
ligatures_values.append(CSSKeywordValue::create(Keyword::Normal));
if (numeric_values.is_empty())
numeric_values.append(CSSKeywordValue::create(Keyword::Normal));
if (east_asian_values.is_empty())
east_asian_values.append(CSSKeywordValue::create(Keyword::Normal));
return ShorthandStyleValue::create(PropertyID::FontVariant,
{ PropertyID::FontVariantAlternates,
PropertyID::FontVariantCaps,
PropertyID::FontVariantEastAsian,
PropertyID::FontVariantLigatures,
PropertyID::FontVariantNumeric,
PropertyID::FontVariantPosition },
{
CSSKeywordValue::create(alternates_value),
CSSKeywordValue::create(caps_value),
StyleValueList::create(move(east_asian_values), StyleValueList::Separator::Space),
StyleValueList::create(move(ligatures_values), StyleValueList::Separator::Space),
StyleValueList::create(move(numeric_values), StyleValueList::Separator::Space),
CSSKeywordValue::create(position_value),
});
}
RefPtr<CSSStyleValue> Parser::parse_font_variant_alternates_value(TokenStream<ComponentValue>& tokens)
{
// 6.8 https://drafts.csswg.org/css-fonts/#font-variant-alternates-prop
// normal |
// [ FIXME: stylistic(<feature-value-name>) ||
// historical-forms ||
// FIXME: styleset(<feature-value-name>#) ||
// FIXME: character-variant(<feature-value-name>#) ||
// FIXME: swash(<feature-value-name>) ||
// FIXME: ornaments(<feature-value-name>) ||
// FIXME: annotation(<feature-value-name>) ]
// normal
if (auto normal = parse_all_as_single_keyword_value(tokens, Keyword::Normal))
return normal;
// historical-forms
// FIXME: Support this together with other values when we parse them.
if (auto historical_forms = parse_all_as_single_keyword_value(tokens, Keyword::HistoricalForms))
return historical_forms;
dbgln_if(CSS_PARSER_DEBUG, "CSSParser: @font-variant-alternate: parsing {} not implemented.", tokens.next_token().to_debug_string());
return nullptr;
}
RefPtr<CSSStyleValue> Parser::parse_font_variant_caps_value(TokenStream<ComponentValue>& tokens)
{
// https://drafts.csswg.org/css-fonts/#propdef-font-variant-caps
// normal | small-caps | all-small-caps | petite-caps | all-petite-caps | unicase | titling-caps
bool has_token = false;
while (tokens.has_next_token()) {
if (has_token)
return nullptr;
auto maybe_value = parse_keyword_value(tokens);
if (!maybe_value)
break;
auto value = maybe_value.release_nonnull();
auto font_variant = keyword_to_font_variant_caps(value->to_keyword());
if (font_variant.has_value()) {
return value;
}
return nullptr;
}
return nullptr;
}
RefPtr<CSSStyleValue> Parser::parse_font_variant_east_asian_value(TokenStream<ComponentValue>& tokens)
{
// 6.10 https://drafts.csswg.org/css-fonts/#propdef-font-variant-east-asian
// normal | [ <east-asian-variant-values> || <east-asian-width-values> || ruby ]
// <east-asian-variant-values> = [ jis78 | jis83 | jis90 | jis04 | simplified | traditional ]
// <east-asian-width-values> = [ full-width | proportional-width ]
StyleValueVector value_list;
bool has_ruby = false;
bool has_variant = false;
bool has_width = false;
// normal | ...
if (auto normal = parse_all_as_single_keyword_value(tokens, Keyword::Normal)) {
value_list.append(normal.release_nonnull());
} else {
while (tokens.has_next_token()) {
auto maybe_value = parse_keyword_value(tokens);
if (!maybe_value)
break;
auto value = maybe_value.release_nonnull();
auto font_variant = keyword_to_font_variant_east_asian(value->to_keyword());
if (!font_variant.has_value()) {
return nullptr;
}
auto keyword = value->to_keyword();
if (keyword == Keyword::Ruby) {
if (has_ruby)
return nullptr;
has_ruby = true;
} else if (keyword == Keyword::FullWidth || keyword == Keyword::ProportionalWidth) {
if (has_width)
return nullptr;
has_width = true;
} else {
if (has_variant)
return nullptr;
has_variant = true;
}
value_list.append(value);
}
}
if (value_list.is_empty())
return nullptr;
return StyleValueList::create(move(value_list), StyleValueList::Separator::Space);
}
RefPtr<CSSStyleValue> Parser::parse_font_variant_ligatures_value(TokenStream<ComponentValue>& tokens)
{
// 6.4 https://drafts.csswg.org/css-fonts/#propdef-font-variant-ligatures
// normal | none | [ <common-lig-values> || <discretionary-lig-values> || <historical-lig-values> || <contextual-alt-values> ]
// <common-lig-values> = [ common-ligatures | no-common-ligatures ]
// <discretionary-lig-values> = [ discretionary-ligatures | no-discretionary-ligatures ]
// <historical-lig-values> = [ historical-ligatures | no-historical-ligatures ]
// <contextual-alt-values> = [ contextual | no-contextual ]
StyleValueVector value_list;
bool has_common_ligatures = false;
bool has_discretionary_ligatures = false;
bool has_historical_ligatures = false;
bool has_contextual = false;
// normal | ...
if (auto normal = parse_all_as_single_keyword_value(tokens, Keyword::Normal)) {
value_list.append(normal.release_nonnull());
// none | ...
} else if (auto none = parse_all_as_single_keyword_value(tokens, Keyword::None)) {
value_list.append(none.release_nonnull());
} else {
while (tokens.has_next_token()) {
auto maybe_value = parse_keyword_value(tokens);
if (!maybe_value)
break;
auto value = maybe_value.release_nonnull();
switch (value->to_keyword()) {
// <common-lig-values> = [ common-ligatures | no-common-ligatures ]
case Keyword::CommonLigatures:
case Keyword::NoCommonLigatures:
if (has_common_ligatures)
return nullptr;
has_common_ligatures = true;
break;
// <discretionary-lig-values> = [ discretionary-ligatures | no-discretionary-ligatures ]
case Keyword::DiscretionaryLigatures:
case Keyword::NoDiscretionaryLigatures:
if (has_discretionary_ligatures)
return nullptr;
has_discretionary_ligatures = true;
break;
// <historical-lig-values> = [ historical-ligatures | no-historical-ligatures ]
case Keyword::HistoricalLigatures:
case Keyword::NoHistoricalLigatures:
if (has_historical_ligatures)
return nullptr;
has_historical_ligatures = true;
break;
// <contextual-alt-values> = [ contextual | no-contextual ]
case Keyword::Contextual:
case Keyword::NoContextual:
if (has_contextual)
return nullptr;
has_contextual = true;
break;
default:
return nullptr;
}
value_list.append(value);
}
}
if (value_list.is_empty())
return nullptr;
return StyleValueList::create(move(value_list), StyleValueList::Separator::Space);
}
RefPtr<CSSStyleValue> Parser::parse_font_variant_numeric_value(TokenStream<ComponentValue>& tokens)
{
// 6.7 https://drafts.csswg.org/css-fonts/#propdef-font-variant-numeric
// normal | [ <numeric-figure-values> || <numeric-spacing-values> || <numeric-fraction-values> || ordinal || slashed-zero]
// <numeric-figure-values> = [ lining-nums | oldstyle-nums ]
// <numeric-spacing-values> = [ proportional-nums | tabular-nums ]
// <numeric-fraction-values> = [ diagonal-fractions | stacked-fractions ]
StyleValueVector value_list;
bool has_figures = false;
bool has_spacing = false;
bool has_fractions = false;
bool has_ordinals = false;
bool has_slashed_zero = false;
// normal | ...
if (auto normal = parse_all_as_single_keyword_value(tokens, Keyword::Normal)) {
value_list.append(normal.release_nonnull());
} else {
while (tokens.has_next_token()) {
auto maybe_value = parse_keyword_value(tokens);
if (!maybe_value)
break;
auto value = maybe_value.release_nonnull();
switch (value->to_keyword()) {
// ... || ordinal
case Keyword::Ordinal:
if (has_ordinals)
return nullptr;
has_ordinals = true;
break;
// ... || slashed-zero
case Keyword::SlashedZero:
if (has_slashed_zero)
return nullptr;
has_slashed_zero = true;
break;
// <numeric-figure-values> = [ lining-nums | oldstyle-nums ]
case Keyword::LiningNums:
case Keyword::OldstyleNums:
if (has_figures)
return nullptr;
has_figures = true;
break;
// <numeric-spacing-values> = [ proportional-nums | tabular-nums ]
case Keyword::ProportionalNums:
case Keyword::TabularNums:
if (has_spacing)
return nullptr;
has_spacing = true;
break;
// <numeric-fraction-values> = [ diagonal-fractions | stacked-fractions ]
case Keyword::DiagonalFractions:
case Keyword::StackedFractions:
if (has_fractions)
return nullptr;
has_fractions = true;
break;
default:
return nullptr;
}
value_list.append(value);
}
}
if (value_list.is_empty())
return nullptr;
return StyleValueList::create(move(value_list), StyleValueList::Separator::Space);
}
Vector<ParsedFontFace::Source> Parser::parse_as_font_face_src()
{
return parse_font_face_src(m_token_stream);
@ -7789,6 +8238,30 @@ Parser::ParseErrorOr<NonnullRefPtr<CSSStyleValue>> Parser::parse_css_value(Prope
if (auto parsed_value = parse_font_variation_settings_value(tokens); parsed_value && !tokens.has_next_token())
return parsed_value.release_nonnull();
return ParseError::SyntaxError;
case PropertyID::FontVariant:
if (auto parsed_value = parse_font_variant(tokens); parsed_value && !tokens.has_next_token())
return parsed_value.release_nonnull();
return ParseError::SyntaxError;
case PropertyID::FontVariantAlternates:
if (auto parsed_value = parse_font_variant_alternates_value(tokens); parsed_value && !tokens.has_next_token())
return parsed_value.release_nonnull();
return ParseError::SyntaxError;
case PropertyID::FontVariantCaps:
if (auto parsed_value = parse_font_variant_caps_value(tokens); parsed_value && !tokens.has_next_token())
return parsed_value.release_nonnull();
return ParseError::SyntaxError;
case PropertyID::FontVariantEastAsian:
if (auto parsed_value = parse_font_variant_east_asian_value(tokens); parsed_value && !tokens.has_next_token())
return parsed_value.release_nonnull();
return ParseError::SyntaxError;
case PropertyID::FontVariantLigatures:
if (auto parsed_value = parse_font_variant_ligatures_value(tokens); parsed_value && !tokens.has_next_token())
return parsed_value.release_nonnull();
return ParseError::SyntaxError;
case PropertyID::FontVariantNumeric:
if (auto parsed_value = parse_font_variant_numeric_value(tokens); parsed_value && !tokens.has_next_token())
return parsed_value.release_nonnull();
return ParseError::SyntaxError;
case PropertyID::GridArea:
if (auto parsed_value = parse_grid_area_shorthand_value(tokens); parsed_value && !tokens.has_next_token())
return parsed_value.release_nonnull();

View file

@ -322,6 +322,12 @@ private:
RefPtr<CSSStyleValue> parse_font_language_override_value(TokenStream<ComponentValue>&);
RefPtr<CSSStyleValue> parse_font_feature_settings_value(TokenStream<ComponentValue>&);
RefPtr<CSSStyleValue> parse_font_variation_settings_value(TokenStream<ComponentValue>&);
RefPtr<CSSStyleValue> parse_font_variant(TokenStream<ComponentValue>&);
RefPtr<CSSStyleValue> parse_font_variant_alternates_value(TokenStream<ComponentValue>&);
RefPtr<CSSStyleValue> parse_font_variant_caps_value(TokenStream<ComponentValue>&);
RefPtr<CSSStyleValue> parse_font_variant_east_asian_value(TokenStream<ComponentValue>&);
RefPtr<CSSStyleValue> parse_font_variant_ligatures_value(TokenStream<ComponentValue>&);
RefPtr<CSSStyleValue> parse_font_variant_numeric_value(TokenStream<ComponentValue>&);
RefPtr<CSSStyleValue> parse_list_style_value(TokenStream<ComponentValue>&);
RefPtr<CSSStyleValue> parse_math_depth_value(TokenStream<ComponentValue>&);
RefPtr<CSSStyleValue> parse_overflow_value(TokenStream<ComponentValue>&);

View file

@ -1247,7 +1247,69 @@
"inherited": true,
"initial": "normal",
"valid-types": [
"font-variant"
"font-variant-alternates",
"font-variant-caps",
"font-variant-east-asian",
"font-variant-emoji",
"font-variant-ligatures",
"font-variant-numeric",
"font-variant-position"
]
},
"font-variant-alternates": {
"animation-type": "discrete",
"inherited": true,
"initial": "normal",
"valid-types": [
"font-variant-alternates"
]
},
"font-variant-caps": {
"animation-type": "discrete",
"inherited": true,
"initial": "normal",
"valid-types": [
"font-variant-caps"
]
},
"font-variant-east-asian": {
"animation-type": "discrete",
"inherited": true,
"initial": "normal",
"valid-types": [
"font-variant-east-asian"
]
},
"font-variant-emoji": {
"animation-type": "discrete",
"inherited": true,
"initial": "normal",
"valid-types": [
"font-variant-emoji"
]
},
"font-variant-ligatures": {
"animation-type": "discrete",
"inherited": true,
"initial": "normal",
"valid-types": [
"font-variant-ligatures"
]
},
"font-variant-numeric": {
"animation-type": "discrete",
"inherited": true,
"initial": "normal",
"valid-types": [
"font-variant-numeric"
]
},
"font-variant-position": {
"animation-type": "discrete",
"inherited": true,
"initial": "normal",
"valid-types": [
"font-variant-position"
]
},
"font-variation-settings": {

View file

@ -601,6 +601,12 @@ Optional<StyleProperty> ResolvedCSSStyleDeclaration::property(PropertyID propert
};
}
Optional<StyleProperty> ResolvedCSSStyleDeclaration::custom_property(FlyString const&) const
{
dbgln("FIXME: ResolvedCSSStyleDeclaration::custom_property is not implemented");
return {};
}
static WebIDL::ExceptionOr<void> cannot_modify_computed_property_error(JS::Realm& realm)
{
return WebIDL::NoModificationAllowedError::create(realm, "Cannot modify properties in result of getComputedStyle()"_string);

View file

@ -24,6 +24,7 @@ public:
virtual String item(size_t index) const override;
virtual Optional<StyleProperty> property(PropertyID) const override;
virtual Optional<StyleProperty> custom_property(FlyString const& custom_property_name) const override;
virtual WebIDL::ExceptionOr<void> set_property(PropertyID, StringView css_text, StringView priority) override;
virtual WebIDL::ExceptionOr<void> set_property(StringView property_name, StringView css_text, StringView priority) override;
virtual WebIDL::ExceptionOr<String> remove_property(PropertyID) override;

View file

@ -260,7 +260,7 @@ ErrorOr<NonnullRefPtr<Gfx::Typeface>> FontLoader::try_load_font()
mime_type = MimeSniff::Resource::sniff(resource()->encoded_data(), Web::MimeSniff::SniffingConfiguration { .sniffing_context = Web::MimeSniff::SniffingContext::Font });
}
if (mime_type.has_value()) {
if (mime_type->essence() == "font/ttf"sv || mime_type->essence() == "application/x-font-ttf"sv) {
if (mime_type->essence() == "font/ttf"sv || mime_type->essence() == "application/x-font-ttf"sv || mime_type->essence() == "font/otf"sv) {
if (auto result = Gfx::Typeface::try_load_from_externally_owned_memory(resource()->encoded_data()); !result.is_error()) {
return result;
}
@ -2111,6 +2111,13 @@ void StyleComputer::compute_font(StyleProperties& style, DOM::Element const* ele
compute_defaulted_property_value(style, element, CSS::PropertyID::FontStyle, pseudo_element);
compute_defaulted_property_value(style, element, CSS::PropertyID::FontWeight, pseudo_element);
compute_defaulted_property_value(style, element, CSS::PropertyID::LineHeight, pseudo_element);
compute_defaulted_property_value(style, element, CSS::PropertyID::FontVariant, pseudo_element);
compute_defaulted_property_value(style, element, CSS::PropertyID::FontVariantAlternates, pseudo_element);
compute_defaulted_property_value(style, element, CSS::PropertyID::FontVariantCaps, pseudo_element);
compute_defaulted_property_value(style, element, CSS::PropertyID::FontVariantEastAsian, pseudo_element);
compute_defaulted_property_value(style, element, CSS::PropertyID::FontVariantLigatures, pseudo_element);
compute_defaulted_property_value(style, element, CSS::PropertyID::FontVariantNumeric, pseudo_element);
compute_defaulted_property_value(style, element, CSS::PropertyID::FontVariantPosition, pseudo_element);
auto const& font_family = style.property(CSS::PropertyID::FontFamily);
auto const& font_size = style.property(CSS::PropertyID::FontSize);

View file

@ -1143,12 +1143,6 @@ Variant<CSS::VerticalAlign, CSS::LengthPercentage> StyleProperties::vertical_ali
VERIFY_NOT_REACHED();
}
Optional<CSS::FontVariant> StyleProperties::font_variant() const
{
auto const& value = property(CSS::PropertyID::FontVariant);
return keyword_to_font_variant(value.to_keyword());
}
Optional<FlyString> StyleProperties::font_language_override() const
{
auto const& value = property(CSS::PropertyID::FontLanguageOverride);
@ -1157,6 +1151,42 @@ Optional<FlyString> StyleProperties::font_language_override() const
return {};
}
Gfx::FontVariantAlternates StyleProperties::font_variant_alternates() const
{
auto const& value = property(CSS::PropertyID::FontVariantAlternates);
return value.to_font_variant_alternates();
}
Optional<FontVariantCaps> StyleProperties::font_variant_caps() const
{
auto const& value = property(CSS::PropertyID::FontVariantCaps);
return value.to_font_variant_caps();
}
Gfx::FontVariantEastAsian StyleProperties::font_variant_east_asian() const
{
auto const& value = property(CSS::PropertyID::FontVariantEastAsian);
return value.to_font_variant_east_asian();
}
Gfx::FontVariantLigatures StyleProperties::font_variant_ligatures() const
{
auto const& value = property(CSS::PropertyID::FontVariantLigatures);
return value.to_font_variant_ligatures();
}
Gfx::FontVariantNumeric StyleProperties::font_variant_numeric() const
{
auto const& value = property(CSS::PropertyID::FontVariantNumeric);
return value.to_font_variant_numeric();
}
Optional<FontVariantPosition> StyleProperties::font_variant_position() const
{
auto const& value = property(CSS::PropertyID::FontVariantPosition);
return value.to_font_variant_position();
}
Optional<HashMap<FlyString, IntegerOrCalculated>> StyleProperties::font_feature_settings() const
{
auto const& value = property(PropertyID::FontFeatureSettings);

View file

@ -149,7 +149,12 @@ public:
Optional<CSS::BoxSizing> box_sizing() const;
Optional<CSS::PointerEvents> pointer_events() const;
Variant<CSS::VerticalAlign, CSS::LengthPercentage> vertical_align() const;
Optional<CSS::FontVariant> font_variant() const;
Gfx::FontVariantAlternates font_variant_alternates() const;
Optional<FontVariantCaps> font_variant_caps() const;
Gfx::FontVariantEastAsian font_variant_east_asian() const;
Gfx::FontVariantLigatures font_variant_ligatures() const;
Gfx::FontVariantNumeric font_variant_numeric() const;
Optional<FontVariantPosition> font_variant_position() const;
Optional<FlyString> font_language_override() const;
Optional<HashMap<FlyString, IntegerOrCalculated>> font_feature_settings() const;
Optional<HashMap<FlyString, NumberOrCalculated>> font_variation_settings() const;

View file

@ -45,7 +45,7 @@ ValueComparingNonnullRefPtr<CSSColorValue> CSSColorValue::create_from_color(Colo
return make_rgb_color(color);
}
Optional<float> CSSColorValue::resolve_hue(CSSStyleValue const& style_value)
Optional<double> CSSColorValue::resolve_hue(CSSStyleValue const& style_value)
{
// <number> | <angle> | none
auto normalized = [](double number) {
@ -67,11 +67,11 @@ Optional<float> CSSColorValue::resolve_hue(CSSStyleValue const& style_value)
return {};
}
Optional<float> CSSColorValue::resolve_with_reference_value(CSSStyleValue const& style_value, float one_hundred_percent_value)
Optional<double> CSSColorValue::resolve_with_reference_value(CSSStyleValue const& style_value, float one_hundred_percent_value)
{
// <percentage> | <number> | none
auto normalize_percentage = [one_hundred_percent_value](Percentage const& percentage) {
return static_cast<float>(percentage.as_fraction()) * one_hundred_percent_value;
return percentage.as_fraction() * one_hundred_percent_value;
};
if (style_value.is_percentage())
@ -94,7 +94,7 @@ Optional<float> CSSColorValue::resolve_with_reference_value(CSSStyleValue const&
return {};
}
Optional<float> CSSColorValue::resolve_alpha(CSSStyleValue const& style_value)
Optional<double> CSSColorValue::resolve_alpha(CSSStyleValue const& style_value)
{
// <number> | <percentage> | none
auto normalized = [](double number) {

View file

@ -48,9 +48,9 @@ protected:
{
}
static Optional<float> resolve_hue(CSSStyleValue const&);
static Optional<float> resolve_with_reference_value(CSSStyleValue const&, float one_hundred_percent_value);
static Optional<float> resolve_alpha(CSSStyleValue const&);
static Optional<double> resolve_hue(CSSStyleValue const&);
static Optional<double> resolve_with_reference_value(CSSStyleValue const&, float one_hundred_percent_value);
static Optional<double> resolve_alpha(CSSStyleValue const&);
private:
ColorType m_color_type;

View file

@ -25,8 +25,8 @@ Color CSSHWB::to_color(Optional<Layout::NodeWithStyle const&>) const
return Color(gray, gray, gray, to_byte(alpha_val));
}
float value = 1 - b_val;
float saturation = 1 - (w_val / value);
auto value = 1 - b_val;
auto saturation = 1 - (w_val / value);
return Color::from_hsv(h_val, saturation, value).with_opacity(alpha_val);
}

View file

@ -119,6 +119,60 @@ String ShorthandStyleValue::to_string() const
longhand(PropertyID::FontSize)->to_string(),
longhand(PropertyID::LineHeight)->to_string(),
longhand(PropertyID::FontFamily)->to_string()));
case PropertyID::FontVariant: {
Vector<StringView> values;
auto alternates = longhand(PropertyID::FontVariantAlternates)->to_font_variant_alternates();
if (alternates.historical_forms)
values.append("historical-forms"sv);
auto caps_or_null = longhand(PropertyID::FontVariantCaps)->to_font_variant_caps();
if (caps_or_null.has_value() && caps_or_null.value() != CSS::FontVariantCaps::Normal) {
values.append(CSS::to_string(caps_or_null.release_value()));
}
auto east_asian = longhand(PropertyID::FontVariantEastAsian)->to_font_variant_east_asian();
if (!east_asian.normal) {
if (east_asian.variant != Gfx::FontVariantEastAsian::Variant::Unset)
values.append(Gfx::font_variant_east_asian_to_string(east_asian));
if (east_asian.width != Gfx::FontVariantEastAsian::Width::Unset)
values.append(Gfx::font_variant_east_asian_to_string(east_asian));
}
auto ligatures = longhand(PropertyID::FontVariantLigatures)->to_font_variant_ligatures();
if (!ligatures.normal && !ligatures.none) {
if (ligatures.common != Gfx::FontVariantLigatures::Common::Unset)
values.append(Gfx::font_variant_ligatures_to_string(ligatures));
if (ligatures.discretionary != Gfx::FontVariantLigatures::Discretionary::Unset) {
values.append(Gfx::font_variant_ligatures_to_string(ligatures));
}
if (ligatures.historical != Gfx::FontVariantLigatures::Historical::Unset) {
values.append(Gfx::font_variant_ligatures_to_string(ligatures));
}
if (ligatures.contextual != Gfx::FontVariantLigatures::Contextual::Unset) {
values.append(Gfx::font_variant_ligatures_to_string(ligatures));
}
}
auto numeric = longhand(PropertyID::FontVariantNumeric)->to_font_variant_numeric();
if (!numeric.normal) {
if (numeric.ordinal)
values.append("ordinal"sv);
if (numeric.slashed_zero)
values.append("slashed-zero"sv);
if (numeric.figure != Gfx::FontVariantNumeric::Figure::Unset)
values.append(Gfx::font_variant_numeric_to_string(numeric));
if (numeric.spacing != Gfx::FontVariantNumeric::Spacing::Unset)
values.append(Gfx::font_variant_numeric_to_string(numeric));
if (numeric.fraction != Gfx::FontVariantNumeric::Fraction::Unset)
values.append(Gfx::font_variant_numeric_to_string(numeric));
}
auto position_or_null = longhand(PropertyID::FontVariantPosition)->to_font_variant_position();
if (position_or_null.has_value() && position_or_null.value() != CSS::FontVariantPosition::Normal) {
values.append(CSS::to_string(position_or_null.release_value()));
}
StringBuilder builder;
if (values.is_empty())
builder.append("normal"sv);
else
builder.join(' ', values);
return MUST(builder.to_string());
}
case PropertyID::GridArea: {
auto& row_start = longhand(PropertyID::GridRowStart)->as_grid_track_placement();
auto& column_start = longhand(PropertyID::GridColumnStart)->as_grid_track_placement();

View file

@ -2526,6 +2526,106 @@ WebIDL::ExceptionOr<JS::Value> ECDSA::verify(AlgorithmParams const& params, GC::
return JS::Value(result);
}
// https://w3c.github.io/webcrypto/#ecdh-operations
WebIDL::ExceptionOr<Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>>> ECDH::generate_key(AlgorithmParams const& params, bool extractable, Vector<Bindings::KeyUsage> const& key_usages)
{
// 1. If usages contains an entry which is not "deriveKey" or "deriveBits" then throw a SyntaxError.
for (auto const& usage : key_usages) {
if (usage != Bindings::KeyUsage::Derivekey && usage != Bindings::KeyUsage::Derivebits) {
return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
}
}
auto const& normalized_algorithm = static_cast<EcKeyGenParams const&>(params);
// 2. If the namedCurve member of normalizedAlgorithm is "P-256", "P-384" or "P-521":
// Generate an Elliptic Curve key pair, as defined in [RFC6090]
// with domain parameters for the curve identified by the namedCurve member of normalizedAlgorithm.
Variant<Empty, ::Crypto::Curves::SECP256r1, ::Crypto::Curves::SECP384r1> curve;
if (normalized_algorithm.named_curve.is_one_of("P-256"sv, "P-384"sv, "P-521"sv)) {
if (normalized_algorithm.named_curve.equals_ignoring_ascii_case("P-256"sv))
curve = ::Crypto::Curves::SECP256r1 {};
if (normalized_algorithm.named_curve.equals_ignoring_ascii_case("P-384"sv))
curve = ::Crypto::Curves::SECP384r1 {};
// FIXME: Support P-521
if (normalized_algorithm.named_curve.equals_ignoring_ascii_case("P-521"sv))
return WebIDL::NotSupportedError::create(m_realm, "'P-521' is not supported yet"_string);
} else {
// If the namedCurve member of normalizedAlgorithm is a value specified in an applicable specification
// that specifies the use of that value with ECDH:
// Perform the ECDH generation steps specified in that specification,
// passing in normalizedAlgorithm and resulting in an elliptic curve key pair.
// Otherwise: throw a NotSupportedError
return WebIDL::NotSupportedError::create(m_realm, "Only 'P-256', 'P-384' and 'P-521' is supported"_string);
}
// 3. If performing the operation results in an error, then throw a OperationError.
auto maybe_private_key_data = curve.visit(
[](Empty const&) -> ErrorOr<ByteBuffer> { return Error::from_string_literal("noop error"); },
[](auto instance) { return instance.generate_private_key(); });
if (maybe_private_key_data.is_error())
return WebIDL::OperationError::create(m_realm, "Failed to create valid crypto instance"_string);
auto private_key_data = maybe_private_key_data.release_value();
auto maybe_public_key_data = curve.visit(
[](Empty const&) -> ErrorOr<ByteBuffer> { return Error::from_string_literal("noop error"); },
[&](auto instance) { return instance.generate_public_key(private_key_data); });
if (maybe_public_key_data.is_error())
return WebIDL::OperationError::create(m_realm, "Failed to create valid crypto instance"_string);
auto public_key_data = maybe_public_key_data.release_value();
// 4. Let algorithm be a new EcKeyAlgorithm object.
auto algorithm = EcKeyAlgorithm::create(m_realm);
// 5. Set the name attribute of algorithm to "ECDH".
algorithm->set_name("ECDH"_string);
// 6. Set the namedCurve attribute of algorithm to equal the namedCurve member of normalizedAlgorithm.
algorithm->set_named_curve(normalized_algorithm.named_curve);
// 7. Let publicKey be a new CryptoKey representing the public key of the generated key pair.
auto public_key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { public_key_data });
// 8. Set the [[type]] internal slot of publicKey to "public"
public_key->set_type(Bindings::KeyType::Public);
// 9. Set the [[algorithm]] internal slot of publicKey to algorithm.
public_key->set_algorithm(algorithm);
// 10. Set the [[extractable]] internal slot of publicKey to true.
public_key->set_extractable(true);
// 11. Set the [[usages]] internal slot of publicKey to be the empty list.
public_key->set_usages({});
// 12. Let privateKey be a new CryptoKey representing the private key of the generated key pair.
auto private_key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { private_key_data });
// 13. Set the [[type]] internal slot of privateKey to "private"
private_key->set_type(Bindings::KeyType::Private);
// 14. Set the [[algorithm]] internal slot of privateKey to algorithm.
private_key->set_algorithm(algorithm);
// 15. Set the [[extractable]] internal slot of privateKey to extractable.
private_key->set_extractable(extractable);
// 16. Set the [[usages]] internal slot of privateKey to be the usage intersection of usages and [ "deriveKey", "deriveBits" ].
private_key->set_usages(usage_intersection(key_usages, { { Bindings::KeyUsage::Derivekey, Bindings::KeyUsage::Derivebits } }));
// 17. Let result be a new CryptoKeyPair dictionary.
// 18. Set the publicKey attribute of result to be publicKey.
// 19. Set the privateKey attribute of result to be privateKey.
// 20. Return the result of converting result to an ECMAScript Object, as defined by [WebIDL].
return Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>> { CryptoKeyPair::create(m_realm, public_key, private_key) };
}
// https://wicg.github.io/webcrypto-secure-curves/#ed25519-operations
WebIDL::ExceptionOr<Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>>> ED25519::generate_key([[maybe_unused]] AlgorithmParams const& params, bool extractable, Vector<Bindings::KeyUsage> const& key_usages)
{

View file

@ -493,6 +493,22 @@ private:
}
};
class ECDH : public AlgorithmMethods {
public:
virtual WebIDL::ExceptionOr<Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>>> generate_key(AlgorithmParams const&, bool, Vector<Bindings::KeyUsage> const&) override;
// TODO: virtual WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> derive_bits(AlgorithmParams const&, GC::Ref<CryptoKey>, Optional<u32>) override;
// TODO: virtual WebIDL::ExceptionOr<GC::Ref<CryptoKey>> import_key(AlgorithmParams const&, Bindings::KeyFormat, CryptoKey::InternalKeyData, bool, Vector<Bindings::KeyUsage> const&) override;
// TODO: virtual WebIDL::ExceptionOr<GC::Ref<JS::Object>> export_key(Bindings::KeyFormat, GC::Ref<CryptoKey>) override;
static NonnullOwnPtr<AlgorithmMethods> create(JS::Realm& realm) { return adopt_own(*new ECDH(realm)); }
private:
explicit ECDH(JS::Realm& realm)
: AlgorithmMethods(realm)
{
}
};
class ED25519 : public AlgorithmMethods {
public:
virtual WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> sign(AlgorithmParams const&, GC::Ref<CryptoKey>, ByteBuffer const&) override;

View file

@ -801,10 +801,10 @@ SupportedAlgorithmsMap supported_algorithms()
// FIXME: define_an_algorithm<ECDSA>("exportKey"_string, "ECDSA"_string);
// https://w3c.github.io/webcrypto/#ecdh-registration
// FIXME: define_an_algorithm<ECDH, EcKeyGenParams>("generateKey"_string, "ECDH"_string);
// FIXME: define_an_algorithm<ECDH, EcdhKeyDerivePrams>("deriveBits"_string, "ECDH"_string);
// FIXME: define_an_algorithm<ECDH, EcKeyImportParams>("importKey"_string, "ECDH"_string);
// FIXME: define_an_algorithm<ECDH>("exportKey"_string, "ECDH"_string);
define_an_algorithm<ECDH, EcKeyGenParams>("generateKey"_string, "ECDH"_string);
// https://w3c.github.io/webcrypto/#aes-ctr-registration
define_an_algorithm<AesCtr, AesCtrParams>("encrypt"_string, "AES-CTR"_string);

View file

@ -1606,7 +1606,7 @@ GC::Ref<HTML::HTMLAllCollection> Document::all()
GC::Ref<CSS::FontFaceSet> Document::fonts()
{
if (!m_fonts)
m_fonts = CSS::FontFaceSet::create(realm());
m_fonts = CSS::FontFaceSet::create(page(), realm());
return *m_fonts;
}

View file

@ -575,7 +575,7 @@ CanvasRenderingContext2D::PreparedText CanvasRenderingContext2D::prepare_text(By
Gfx::FloatPoint anchor { 0, 0 };
auto physical_alignment = Gfx::TextAlignment::CenterLeft;
auto glyph_run = Gfx::shape_text(anchor, 0, replaced_text.code_points(), *font, Gfx::GlyphRun::TextType::Ltr);
auto glyph_run = Gfx::shape_text(anchor, 0, replaced_text.code_points(), *font, Gfx::GlyphRun::TextType::Ltr, {});
// 8. Let result be an array constructed by iterating over each glyph in the inline box from left to right (if any), adding to the array, for each glyph, the shape of the glyph as it is in the inline box, positioned on a coordinate space using CSS pixels with its origin is at the anchor point.
PreparedText prepared_text { glyph_run, physical_alignment, { 0, 0, static_cast<int>(glyph_run->width()), static_cast<int>(height) } };

View file

@ -161,7 +161,7 @@ ENUMERATE_WORKER_GLOBAL_SCOPE_EVENT_HANDLERS(__ENUMERATE)
GC::Ref<CSS::FontFaceSet> WorkerGlobalScope::fonts()
{
if (!m_fonts)
m_fonts = CSS::FontFaceSet::create(realm());
m_fonts = CSS::FontFaceSet::create(*page(), realm());
return *m_fonts;
}

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibGfx/Font/FontVariant.h>
#include <LibWeb/Layout/BreakNode.h>
#include <LibWeb/Layout/InlineFormattingContext.h>
#include <LibWeb/Layout/InlineLevelIterator.h>
@ -200,6 +201,255 @@ Gfx::GlyphRun::TextType InlineLevelIterator::resolve_text_direction_from_context
return Gfx::GlyphRun::TextType::ContextDependent;
}
HashMap<StringView, u8> InlineLevelIterator::shape_features_map() const
{
HashMap<StringView, u8> features;
auto& computed_values = m_current_node->computed_values();
// 6.4 https://drafts.csswg.org/css-fonts/#font-variant-ligatures-prop
auto ligature = computed_values.font_variant_ligatures();
if (ligature.normal) {
// A value of normal specifies that common default features are enabled, as described in detail in the next section.
features.set("liga"sv, 1);
features.set("clig"sv, 1);
} else if (ligature.none) {
/* nothing */
} else {
switch (ligature.common) {
case Gfx::FontVariantLigatures::Common::Common:
// Enables display of common ligatures (OpenType features: liga, clig).
features.set("liga"sv, 1);
features.set("clig"sv, 1);
break;
case Gfx::FontVariantLigatures::Common::NoCommon:
// Disables display of common ligatures (OpenType features: liga, clig).
features.set("liga"sv, 0);
features.set("clig"sv, 0);
break;
case Gfx::FontVariantLigatures::Common::Unset:
break;
}
switch (ligature.discretionary) {
case Gfx::FontVariantLigatures::Discretionary::Discretionary:
// Enables display of discretionary ligatures (OpenType feature: dlig).
features.set("dlig"sv, 1);
break;
case Gfx::FontVariantLigatures::Discretionary::NoDiscretionary:
// Disables display of discretionary ligatures (OpenType feature: dlig).
features.set("dlig"sv, 0);
break;
case Gfx::FontVariantLigatures::Discretionary::Unset:
break;
}
switch (ligature.historical) {
case Gfx::FontVariantLigatures::Historical::Historical:
// Enables display of historical ligatures (OpenType feature: hlig).
features.set("hlig"sv, 1);
break;
case Gfx::FontVariantLigatures::Historical::NoHistorical:
// Disables display of historical ligatures (OpenType feature: hlig).
features.set("hlig"sv, 0);
break;
case Gfx::FontVariantLigatures::Historical::Unset:
break;
}
switch (ligature.contextual) {
case Gfx::FontVariantLigatures::Contextual::Contextual:
// Enables display of contextual ligatures (OpenType feature: calt).
features.set("calt"sv, 1);
break;
case Gfx::FontVariantLigatures::Contextual::NoContextual:
// Disables display of contextual ligatures (OpenType feature: calt).
features.set("calt"sv, 0);
break;
case Gfx::FontVariantLigatures::Contextual::Unset:
break;
}
}
// 6.5 https://drafts.csswg.org/css-fonts/#font-variant-position-prop
switch (computed_values.font_variant_position()) {
case CSS::FontVariantPosition::Normal:
// None of the features listed below are enabled.
break;
case CSS::FontVariantPosition::Sub:
// Enables display of subscripts (OpenType feature: subs).
features.set("subs"sv, 1);
break;
case CSS::FontVariantPosition::Super:
// Enables display of superscripts (OpenType feature: sups).
features.set("sups"sv, 1);
break;
default:
break;
}
// 6.6 https://drafts.csswg.org/css-fonts/#font-variant-caps-prop
switch (computed_values.font_variant_caps()) {
case CSS::FontVariantCaps::Normal:
// None of the features listed below are enabled.
break;
case CSS::FontVariantCaps::SmallCaps:
// Enables display of small capitals (OpenType feature: smcp). Small-caps glyphs typically use the form of uppercase letters but are reduced to the size of lowercase letters.
features.set("smcp"sv, 1);
break;
case CSS::FontVariantCaps::AllSmallCaps:
// Enables display of small capitals for both upper and lowercase letters (OpenType features: c2sc, smcp).
features.set("c2sc"sv, 1);
features.set("smcp"sv, 1);
break;
case CSS::FontVariantCaps::PetiteCaps:
// Enables display of petite capitals (OpenType feature: pcap).
features.set("pcap"sv, 1);
break;
case CSS::FontVariantCaps::AllPetiteCaps:
// Enables display of petite capitals for both upper and lowercase letters (OpenType features: c2pc, pcap).
features.set("c2pc"sv, 1);
features.set("pcap"sv, 1);
break;
case CSS::FontVariantCaps::Unicase:
// Enables display of mixture of small capitals for uppercase letters with normal lowercase letters (OpenType feature: unic).
features.set("unic"sv, 1);
break;
case CSS::FontVariantCaps::TitlingCaps:
// Enables display of titling capitals (OpenType feature: titl).
features.set("titl"sv, 1);
break;
default:
break;
}
// 6.7 https://drafts.csswg.org/css-fonts/#font-variant-numeric-prop
auto numeric = computed_values.font_variant_numeric();
// None of the features listed below are enabled.
if (numeric.normal) {
/* passthrough */
}
if (numeric.figure == Gfx::FontVariantNumeric::Figure::Oldstyle) {
// Enables display of old-style numerals (OpenType feature: onum).
features.set("onum"sv, 1);
} else if (numeric.figure == Gfx::FontVariantNumeric::Figure::Lining) {
// Enables display of lining numerals (OpenType feature: lnum).
features.set("lnum"sv, 1);
}
if (numeric.spacing == Gfx::FontVariantNumeric::Spacing::Proportional) {
// Enables display of proportional numerals (OpenType feature: pnum).
features.set("pnum"sv, 1);
} else if (numeric.spacing == Gfx::FontVariantNumeric::Spacing::Tabular) {
// Enables display of tabular numerals (OpenType feature: tnum).
features.set("tnum"sv, 1);
}
if (numeric.fraction == Gfx::FontVariantNumeric::Fraction::Diagonal) {
// Enables display of diagonal fractions (OpenType feature: frac).
features.set("frac"sv, 1);
} else if (numeric.fraction == Gfx::FontVariantNumeric::Fraction::Stacked) {
// Enables display of stacked fractions (OpenType feature: afrc).
features.set("afrc"sv, 1);
}
if (numeric.ordinal) {
// Enables display of letter forms used with ordinal numbers (OpenType feature: ordn).
features.set("ordn"sv, 1);
}
if (numeric.slashed_zero) {
// Enables display of slashed zeros (OpenType feature: zero).
features.set("zero"sv, 1);
}
// 6.10 https://drafts.csswg.org/css-fonts/#font-variant-east-asian-prop
auto east_asian = computed_values.font_variant_east_asian();
switch (east_asian.variant) {
case Gfx::FontVariantEastAsian::Variant::Jis78:
// Enables display of JIS78 forms (OpenType feature: jp78).
features.set("jp78"sv, 1);
break;
case Gfx::FontVariantEastAsian::Variant::Jis83:
// Enables display of JIS83 forms (OpenType feature: jp83).
features.set("jp83"sv, 1);
break;
case Gfx::FontVariantEastAsian::Variant::Jis90:
// Enables display of JIS90 forms (OpenType feature: jp90).
features.set("jp90"sv, 1);
break;
case Gfx::FontVariantEastAsian::Variant::Jis04:
// Enables display of JIS04 forms (OpenType feature: jp04).
features.set("jp04"sv, 1);
break;
case Gfx::FontVariantEastAsian::Variant::Simplified:
// Enables display of simplified forms (OpenType feature: smpl).
features.set("smpl"sv, 1);
break;
case Gfx::FontVariantEastAsian::Variant::Traditional:
// Enables display of traditional forms (OpenType feature: trad).
features.set("trad"sv, 1);
break;
default:
break;
}
switch (east_asian.width) {
case Gfx::FontVariantEastAsian::Width::FullWidth:
// Enables display of full-width forms (OpenType feature: fwid).
features.set("fwid"sv, 1);
break;
case Gfx::FontVariantEastAsian::Width::Proportional:
// Enables display of proportional-width forms (OpenType feature: pwid).
features.set("pwid"sv, 1);
break;
default:
break;
}
if (east_asian.ruby) {
// Enables display of ruby forms (OpenType feature: ruby).
features.set("ruby"sv, 1);
}
return features;
}
Gfx::ShapeFeatures InlineLevelIterator::create_and_merge_font_features() const
{
HashMap<StringView, u8> merged_features;
auto& computed_values = m_inline_formatting_context.containing_block().computed_values();
// https://www.w3.org/TR/css-fonts-3/#feature-precedence
// FIXME 1. Font features enabled by default, including features required for a given script.
// FIXME 2. If the font is defined via an @font-face rule, the font features implied by the font-feature-settings descriptor in the @font-face rule.
// 3. Font features implied by the value of the font-variant property, the related font-variant subproperties and any other CSS property that uses OpenType features (e.g. the font-kerning property).
for (auto& it : shape_features_map()) {
merged_features.set(it.key, it.value);
}
// FIXME 4. Feature settings determined by properties other than font-variant or font-feature-settings. For example, setting a non-default value for the letter-spacing property disables common ligatures.
// 5. Font features implied by the value of font-feature-settings property.
auto font_feature_settings = computed_values.font_feature_settings();
if (font_feature_settings.has_value()) {
auto const& feature_settings = font_feature_settings.value();
for (auto const& [key, feature_value] : feature_settings) {
merged_features.set(key, feature_value.resolved(*m_current_node.ptr()));
}
}
Gfx::ShapeFeatures shape_features;
shape_features.ensure_capacity(merged_features.size());
for (auto& it : merged_features) {
shape_features.append({ { it.key[0], it.key[1], it.key[2], it.key[3] }, static_cast<u32>(it.value) });
}
return shape_features;
}
Optional<InlineLevelIterator::Item> InlineLevelIterator::next_without_lookahead()
{
if (!m_current_node)
@ -293,7 +543,8 @@ Optional<InlineLevelIterator::Item> InlineLevelIterator::next_without_lookahead(
x = tab_stop_dist.to_float();
}
auto glyph_run = Gfx::shape_text({ x, 0 }, letter_spacing.to_float(), chunk.view, chunk.font, text_type);
auto shape_features = create_and_merge_font_features();
auto glyph_run = Gfx::shape_text({ x, 0 }, letter_spacing.to_float(), chunk.view, chunk.font, text_type, shape_features);
CSSPixels chunk_width = CSSPixels::nearest_value_for(glyph_run->width());

View file

@ -68,6 +68,9 @@ private:
void add_extra_box_model_metrics_to_item(Item&, bool add_leading_metrics, bool add_trailing_metrics);
HashMap<StringView, u8> shape_features_map() const;
Gfx::ShapeFeatures create_and_merge_font_features() const;
Layout::Node const* next_inline_node_in_pre_order(Layout::Node const& current, Layout::Node const* stay_within);
Layout::InlineFormattingContext& m_inline_formatting_context;

View file

@ -458,10 +458,20 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style)
if (auto box_sizing = computed_style.box_sizing(); box_sizing.has_value())
computed_values.set_box_sizing(box_sizing.release_value());
if (auto maybe_font_variant = computed_style.font_variant(); maybe_font_variant.has_value())
computed_values.set_font_variant(maybe_font_variant.release_value());
if (auto maybe_font_language_override = computed_style.font_language_override(); maybe_font_language_override.has_value())
computed_values.set_font_language_override(maybe_font_language_override.release_value());
if (auto font_variant_alternates = computed_style.font_variant_alternates(); !font_variant_alternates.normal)
computed_values.set_font_variant_alternates(font_variant_alternates);
if (auto maybe_font_variant_caps = computed_style.font_variant_caps(); maybe_font_variant_caps.has_value())
computed_values.set_font_variant_caps(maybe_font_variant_caps.release_value());
if (auto font_variant_east_asian = computed_style.font_variant_east_asian(); !font_variant_east_asian.normal)
computed_values.set_font_variant_east_asian(font_variant_east_asian);
if (auto font_variant_ligatures = computed_style.font_variant_ligatures(); !font_variant_ligatures.normal)
computed_values.set_font_variant_ligatures(font_variant_ligatures);
if (auto font_variant_numeric = computed_style.font_variant_numeric(); !font_variant_numeric.normal)
computed_values.set_font_variant_numeric(font_variant_numeric);
if (auto maybe_font_variant_position = computed_style.font_variant_position(); maybe_font_variant_position.has_value())
computed_values.set_font_variant_position(maybe_font_variant_position.release_value());
if (auto maybe_font_feature_settings = computed_style.font_feature_settings(); maybe_font_feature_settings.has_value())
computed_values.set_font_feature_settings(maybe_font_feature_settings.release_value());
if (auto maybe_font_variation_settings = computed_style.font_variation_settings(); maybe_font_variation_settings.has_value())

View file

@ -177,8 +177,6 @@ EventResult EventHandler::handle_mousewheel(CSSPixelPoint viewport_position, CSS
if (!m_navigable->active_document()->is_fully_active())
return EventResult::Dropped;
auto position = viewport_position;
m_navigable->active_document()->update_layout();
if (!paint_root())
@ -190,20 +188,20 @@ EventResult EventHandler::handle_mousewheel(CSSPixelPoint viewport_position, CSS
auto handled_event = EventResult::Dropped;
GC::Ptr<Painting::Paintable> paintable;
if (auto result = target_for_mouse_position(position); result.has_value())
if (auto result = target_for_mouse_position(viewport_position); result.has_value())
paintable = result->paintable;
if (paintable) {
auto* containing_block = paintable->containing_block();
while (containing_block) {
auto handled_scroll_event = containing_block->handle_mousewheel({}, position, buttons, modifiers, wheel_delta_x, wheel_delta_y);
auto handled_scroll_event = containing_block->handle_mousewheel({}, viewport_position, buttons, modifiers, wheel_delta_x, wheel_delta_y);
if (handled_scroll_event)
return EventResult::Handled;
containing_block = containing_block->containing_block();
}
if (paintable->handle_mousewheel({}, position, buttons, modifiers, wheel_delta_x, wheel_delta_y))
if (paintable->handle_mousewheel({}, viewport_position, buttons, modifiers, wheel_delta_x, wheel_delta_y))
return EventResult::Handled;
auto node = dom_node_for_event_dispatch(*paintable);
@ -212,7 +210,7 @@ EventResult EventHandler::handle_mousewheel(CSSPixelPoint viewport_position, CSS
// FIXME: Support wheel events in nested browsing contexts.
if (is<HTML::HTMLIFrameElement>(*node)) {
auto& iframe = static_cast<HTML::HTMLIFrameElement&>(*node);
auto position_in_iframe = position.translated(compute_mouse_event_offset({}, paintable->layout_node()));
auto position_in_iframe = viewport_position.translated(compute_mouse_event_offset({}, paintable->layout_node()));
iframe.content_navigable()->event_handler().handle_mousewheel(position_in_iframe, screen_position, button, buttons, modifiers, wheel_delta_x, wheel_delta_y);
return EventResult::Dropped;
}
@ -222,10 +220,9 @@ EventResult EventHandler::handle_mousewheel(CSSPixelPoint viewport_position, CSS
if (!parent_element_for_event_dispatch(*paintable, node, layout_node))
return EventResult::Dropped;
auto offset = compute_mouse_event_offset(position, *layout_node);
auto client_offset = compute_mouse_event_client_offset(position);
auto page_offset = compute_mouse_event_page_offset(client_offset);
if (node->dispatch_event(UIEvents::WheelEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::wheel, screen_position, page_offset, client_offset, offset, wheel_delta_x, wheel_delta_y, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors())) {
auto page_offset = compute_mouse_event_page_offset(viewport_position);
auto offset = compute_mouse_event_offset(page_offset, *layout_node);
if (node->dispatch_event(UIEvents::WheelEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::wheel, screen_position, page_offset, viewport_position, offset, wheel_delta_x, wheel_delta_y, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors())) {
m_navigable->active_window()->scroll_by(wheel_delta_x, wheel_delta_y);
}
@ -246,26 +243,24 @@ EventResult EventHandler::handle_mouseup(CSSPixelPoint viewport_position, CSSPix
if (!m_navigable->active_document()->is_fully_active())
return EventResult::Dropped;
auto position = viewport_position;
m_navigable->active_document()->update_layout();
if (!paint_root())
return EventResult::Dropped;
GC::Ptr<Painting::Paintable> paintable;
if (auto result = target_for_mouse_position(position); result.has_value())
if (auto result = target_for_mouse_position(viewport_position); result.has_value())
paintable = result->paintable;
if (paintable && paintable->wants_mouse_events()) {
if (paintable->handle_mouseup({}, position, button, modifiers) == Painting::Paintable::DispatchEventOfSameName::No)
if (paintable->handle_mouseup({}, viewport_position, button, modifiers) == Painting::Paintable::DispatchEventOfSameName::No)
return EventResult::Cancelled;
// Things may have changed as a consequence of Layout::Node::handle_mouseup(). Hit test again.
if (!paint_root())
return EventResult::Handled;
if (auto result = paint_root()->hit_test(position, Painting::HitTestType::Exact); result.has_value())
if (auto result = paint_root()->hit_test(viewport_position, Painting::HitTestType::Exact); result.has_value())
paintable = result->paintable;
}
@ -277,7 +272,7 @@ EventResult EventHandler::handle_mouseup(CSSPixelPoint viewport_position, CSSPix
if (node) {
if (is<HTML::HTMLIFrameElement>(*node)) {
if (auto content_navigable = static_cast<HTML::HTMLIFrameElement&>(*node).content_navigable())
return content_navigable->event_handler().handle_mouseup(position.translated(compute_mouse_event_offset({}, paintable->layout_node())), screen_position, button, buttons, modifiers);
return content_navigable->event_handler().handle_mouseup(viewport_position.translated(compute_mouse_event_offset({}, paintable->layout_node())), screen_position, button, buttons, modifiers);
return EventResult::Dropped;
}
@ -290,22 +285,21 @@ EventResult EventHandler::handle_mouseup(CSSPixelPoint viewport_position, CSSPix
goto after_node_use;
}
auto offset = compute_mouse_event_offset(position, *layout_node);
auto client_offset = compute_mouse_event_client_offset(position);
auto page_offset = compute_mouse_event_page_offset(client_offset);
node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::mouseup, screen_position, page_offset, client_offset, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
auto page_offset = compute_mouse_event_page_offset(viewport_position);
auto offset = compute_mouse_event_offset(page_offset, *layout_node);
node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::mouseup, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
handled_event = EventResult::Handled;
bool run_activation_behavior = false;
if (node.ptr() == m_mousedown_target) {
if (button == UIEvents::MouseButton::Primary) {
run_activation_behavior = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::click, screen_position, page_offset, client_offset, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
run_activation_behavior = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::click, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
} else if (button == UIEvents::MouseButton::Middle) {
run_activation_behavior = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::auxclick, screen_position, page_offset, client_offset, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
run_activation_behavior = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::auxclick, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
} else if (button == UIEvents::MouseButton::Secondary) {
// Allow the user to bypass custom context menus by holding shift, like Firefox.
if ((modifiers & UIEvents::Mod_Shift) == 0)
run_activation_behavior = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::contextmenu, screen_position, page_offset, client_offset, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
run_activation_behavior = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::contextmenu, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
else
run_activation_behavior = true;
}
@ -378,8 +372,6 @@ EventResult EventHandler::handle_mousedown(CSSPixelPoint viewport_position, CSSP
if (!m_navigable->active_document()->is_fully_active())
return EventResult::Dropped;
auto position = viewport_position;
m_navigable->active_document()->update_layout();
if (!paint_root())
@ -390,7 +382,7 @@ EventResult EventHandler::handle_mousedown(CSSPixelPoint viewport_position, CSSP
{
GC::Ptr<Painting::Paintable> paintable;
if (auto result = target_for_mouse_position(position); result.has_value())
if (auto result = target_for_mouse_position(viewport_position); result.has_value())
paintable = result->paintable;
else
return EventResult::Dropped;
@ -403,7 +395,7 @@ EventResult EventHandler::handle_mousedown(CSSPixelPoint viewport_position, CSSP
document->set_hovered_node(node);
if (paintable->wants_mouse_events()) {
if (paintable->handle_mousedown({}, position, button, modifiers) == Painting::Paintable::DispatchEventOfSameName::No)
if (paintable->handle_mousedown({}, viewport_position, button, modifiers) == Painting::Paintable::DispatchEventOfSameName::No)
return EventResult::Cancelled;
}
@ -412,7 +404,7 @@ EventResult EventHandler::handle_mousedown(CSSPixelPoint viewport_position, CSSP
if (is<HTML::HTMLIFrameElement>(*node)) {
if (auto content_navigable = static_cast<HTML::HTMLIFrameElement&>(*node).content_navigable())
return content_navigable->event_handler().handle_mousedown(position.translated(compute_mouse_event_offset({}, paintable->layout_node())), screen_position, button, buttons, modifiers);
return content_navigable->event_handler().handle_mousedown(viewport_position.translated(compute_mouse_event_offset({}, paintable->layout_node())), screen_position, button, buttons, modifiers);
return EventResult::Dropped;
}
@ -426,10 +418,9 @@ EventResult EventHandler::handle_mousedown(CSSPixelPoint viewport_position, CSSP
return EventResult::Dropped;
m_mousedown_target = node.ptr();
auto offset = compute_mouse_event_offset(position, *layout_node);
auto client_offset = compute_mouse_event_client_offset(position);
auto page_offset = compute_mouse_event_page_offset(client_offset);
node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::mousedown, screen_position, page_offset, client_offset, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
auto page_offset = compute_mouse_event_page_offset(viewport_position);
auto offset = compute_mouse_event_offset(page_offset, *layout_node);
node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::mousedown, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
}
// NOTE: Dispatching an event may have disturbed the world.
@ -437,7 +428,7 @@ EventResult EventHandler::handle_mousedown(CSSPixelPoint viewport_position, CSSP
return EventResult::Accepted;
if (button == UIEvents::MouseButton::Primary) {
if (auto result = paint_root()->hit_test(position, Painting::HitTestType::TextCursor); result.has_value()) {
if (auto result = paint_root()->hit_test(viewport_position, Painting::HitTestType::TextCursor); result.has_value()) {
auto paintable = result->paintable;
auto dom_node = paintable->dom_node();
if (dom_node) {
@ -494,8 +485,6 @@ EventResult EventHandler::handle_mousemove(CSSPixelPoint viewport_position, CSSP
if (!m_navigable->active_document()->is_fully_active())
return EventResult::Dropped;
auto position = viewport_position;
m_navigable->active_document()->update_layout();
if (!paint_root())
@ -510,7 +499,7 @@ EventResult EventHandler::handle_mousemove(CSSPixelPoint viewport_position, CSSP
GC::Ptr<Painting::Paintable> paintable;
Optional<int> start_index;
if (auto result = target_for_mouse_position(position); result.has_value()) {
if (auto result = target_for_mouse_position(viewport_position); result.has_value()) {
paintable = result->paintable;
start_index = result->index_in_node;
}
@ -519,7 +508,7 @@ EventResult EventHandler::handle_mousemove(CSSPixelPoint viewport_position, CSSP
if (paintable) {
if (paintable->wants_mouse_events()) {
document.set_hovered_node(paintable->dom_node());
if (paintable->handle_mousemove({}, position, buttons, modifiers) == Painting::Paintable::DispatchEventOfSameName::No)
if (paintable->handle_mousemove({}, viewport_position, buttons, modifiers) == Painting::Paintable::DispatchEventOfSameName::No)
return EventResult::Cancelled;
// FIXME: It feels a bit aggressive to always update the cursor like this.
@ -530,7 +519,7 @@ EventResult EventHandler::handle_mousemove(CSSPixelPoint viewport_position, CSSP
if (node && is<HTML::HTMLIFrameElement>(*node)) {
if (auto content_navigable = static_cast<HTML::HTMLIFrameElement&>(*node).content_navigable())
return content_navigable->event_handler().handle_mousemove(position.translated(compute_mouse_event_offset({}, paintable->layout_node())), screen_position, buttons, modifiers);
return content_navigable->event_handler().handle_mousemove(viewport_position.translated(compute_mouse_event_offset({}, paintable->layout_node())), screen_position, buttons, modifiers);
return EventResult::Dropped;
}
@ -563,14 +552,13 @@ EventResult EventHandler::handle_mousemove(CSSPixelPoint viewport_position, CSSP
hovered_node_cursor = cursor_css_to_gfx(cursor);
}
auto offset = compute_mouse_event_offset(position, *layout_node);
auto client_offset = compute_mouse_event_client_offset(position);
auto page_offset = compute_mouse_event_page_offset(client_offset);
auto page_offset = compute_mouse_event_page_offset(viewport_position);
auto offset = compute_mouse_event_offset(page_offset, *layout_node);
auto movement = compute_mouse_event_movement(screen_position);
m_mousemove_previous_screen_position = screen_position;
bool continue_ = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::mousemove, screen_position, page_offset, client_offset, offset, movement, UIEvents::MouseButton::Primary, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
bool continue_ = node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::mousemove, screen_position, page_offset, viewport_position, offset, movement, UIEvents::MouseButton::Primary, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
if (!continue_)
return EventResult::Cancelled;
@ -580,7 +568,7 @@ EventResult EventHandler::handle_mousemove(CSSPixelPoint viewport_position, CSSP
}
if (m_in_mouse_selection) {
auto hit = paint_root()->hit_test(position, Painting::HitTestType::TextCursor);
auto hit = paint_root()->hit_test(viewport_position, Painting::HitTestType::TextCursor);
if (m_mouse_selection_target) {
if (hit.has_value()) {
m_mouse_selection_target->set_selection_focus(*hit->paintable->dom_node(), hit->index_in_node);
@ -635,16 +623,13 @@ EventResult EventHandler::handle_doubleclick(CSSPixelPoint viewport_position, CS
auto& document = *m_navigable->active_document();
auto scroll_offset = document.navigable()->viewport_scroll_offset();
auto position = viewport_position.translated(scroll_offset);
document.update_layout();
if (!paint_root())
return EventResult::Dropped;
GC::Ptr<Painting::Paintable> paintable;
if (auto result = target_for_mouse_position(position); result.has_value())
if (auto result = target_for_mouse_position(viewport_position); result.has_value())
paintable = result->paintable;
else
return EventResult::Dropped;
@ -665,7 +650,7 @@ EventResult EventHandler::handle_doubleclick(CSSPixelPoint viewport_position, CS
if (is<HTML::HTMLIFrameElement>(*node)) {
if (auto content_navigable = static_cast<HTML::HTMLIFrameElement&>(*node).content_navigable())
return content_navigable->event_handler().handle_doubleclick(position.translated(compute_mouse_event_offset({}, paintable->layout_node())), screen_position, button, buttons, modifiers);
return content_navigable->event_handler().handle_doubleclick(viewport_position.translated(compute_mouse_event_offset({}, paintable->layout_node())), screen_position, button, buttons, modifiers);
return EventResult::Dropped;
}
@ -675,17 +660,16 @@ EventResult EventHandler::handle_doubleclick(CSSPixelPoint viewport_position, CS
if (!parent_element_for_event_dispatch(*paintable, node, layout_node))
return EventResult::Dropped;
auto offset = compute_mouse_event_offset(position, *layout_node);
auto client_offset = compute_mouse_event_client_offset(position);
auto page_offset = compute_mouse_event_page_offset(client_offset);
node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::dblclick, screen_position, page_offset, client_offset, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
auto page_offset = compute_mouse_event_page_offset(viewport_position);
auto offset = compute_mouse_event_offset(page_offset, *layout_node);
node->dispatch_event(UIEvents::MouseEvent::create_from_platform_event(node->realm(), UIEvents::EventNames::dblclick, screen_position, page_offset, viewport_position, offset, {}, button, buttons, modifiers).release_value_but_fixme_should_propagate_errors());
// NOTE: Dispatching an event may have disturbed the world.
if (!paint_root() || paint_root() != node->document().paintable_box())
return EventResult::Accepted;
if (button == UIEvents::MouseButton::Primary) {
if (auto result = paint_root()->hit_test(position, Painting::HitTestType::TextCursor); result.has_value()) {
if (auto result = paint_root()->hit_test(viewport_position, Painting::HitTestType::TextCursor); result.has_value()) {
if (!result->paintable->dom_node())
return EventResult::Accepted;
if (!is<Painting::TextPaintable>(*result->paintable))
@ -738,19 +722,18 @@ EventResult EventHandler::handle_drag_and_drop_event(DragEvent::Type type, CSSPi
return EventResult::Dropped;
}
auto offset = compute_mouse_event_offset(viewport_position, paintable->layout_node());
auto client_offset = compute_mouse_event_client_offset(viewport_position);
auto page_offset = compute_mouse_event_page_offset(client_offset);
auto page_offset = compute_mouse_event_page_offset(viewport_position);
auto offset = compute_mouse_event_offset(page_offset, paintable->layout_node());
switch (type) {
case DragEvent::Type::DragStart:
return m_drag_and_drop_event_handler->handle_drag_start(document.realm(), screen_position, page_offset, client_offset, offset, button, buttons, modifiers, move(files));
return m_drag_and_drop_event_handler->handle_drag_start(document.realm(), screen_position, page_offset, viewport_position, offset, button, buttons, modifiers, move(files));
case DragEvent::Type::DragMove:
return m_drag_and_drop_event_handler->handle_drag_move(document.realm(), document, *node, screen_position, page_offset, client_offset, offset, button, buttons, modifiers);
return m_drag_and_drop_event_handler->handle_drag_move(document.realm(), document, *node, screen_position, page_offset, viewport_position, offset, button, buttons, modifiers);
case DragEvent::Type::DragEnd:
return m_drag_and_drop_event_handler->handle_drag_leave(document.realm(), screen_position, page_offset, client_offset, offset, button, buttons, modifiers);
return m_drag_and_drop_event_handler->handle_drag_leave(document.realm(), screen_position, page_offset, viewport_position, offset, button, buttons, modifiers);
case DragEvent::Type::Drop:
return m_drag_and_drop_event_handler->handle_drop(document.realm(), screen_position, page_offset, client_offset, offset, button, buttons, modifiers);
return m_drag_and_drop_event_handler->handle_drop(document.realm(), screen_position, page_offset, viewport_position, offset, button, buttons, modifiers);
}
VERIFY_NOT_REACHED();
@ -1113,15 +1096,6 @@ void EventHandler::set_mouse_event_tracking_paintable(Painting::Paintable* paint
m_mouse_event_tracking_paintable = paintable;
}
CSSPixelPoint EventHandler::compute_mouse_event_client_offset(CSSPixelPoint event_page_position) const
{
// https://w3c.github.io/csswg-drafts/cssom-view/#dom-mouseevent-clientx
// The clientX attribute must return the x-coordinate of the position where the event occurred relative to the origin of the viewport.
auto scroll_offset = m_navigable->active_document()->navigable()->viewport_scroll_offset();
return event_page_position.translated(-scroll_offset);
}
CSSPixelPoint EventHandler::compute_mouse_event_page_offset(CSSPixelPoint event_client_offset) const
{
// https://w3c.github.io/csswg-drafts/cssom-view/#dom-mouseevent-pagex

View file

@ -578,6 +578,14 @@ Vector<GC::Root<DOM::Document>> Page::documents_in_active_window() const
return documents;
}
URL::URL Page::url() const
{
if (!top_level_traversable_is_initialized())
return {};
return top_level_traversable()->active_document()->url();
}
void Page::clear_selection()
{
for (auto const& document : documents_in_active_window()) {

View file

@ -212,6 +212,8 @@ public:
FindInPageResult find_in_page_previous_match();
Optional<FindInPageQuery> last_find_in_page_query() const { return m_last_find_in_page_query; }
URL::URL url() const;
private:
explicit Page(GC::Ref<PageClient>);
virtual void visit_edges(Visitor&) override;
@ -368,6 +370,7 @@ public:
virtual void page_did_request_select_dropdown([[maybe_unused]] Web::CSSPixelPoint content_position, [[maybe_unused]] Web::CSSPixels minimum_width, [[maybe_unused]] Vector<Web::HTML::SelectItem> items) { }
virtual void page_did_finish_text_test([[maybe_unused]] String const& text) { }
virtual void page_did_finish_loading_page_and_fonts([[maybe_unused]] URL::URL const& url) { }
virtual void page_did_change_theme_color(Gfx::Color) { }

View file

@ -220,7 +220,7 @@ void DisplayListRecorder::draw_text(Gfx::IntRect const& rect, String raw_text, G
if (rect.is_empty())
return;
auto glyph_run = Gfx::shape_text({}, 0, raw_text.code_points(), font, Gfx::GlyphRun::TextType::Ltr);
auto glyph_run = Gfx::shape_text({}, 0, raw_text.code_points(), font, Gfx::GlyphRun::TextType::Ltr, {});
float baseline_x = 0;
if (alignment == Gfx::TextAlignment::CenterLeft) {
baseline_x = rect.x();

View file

@ -6,6 +6,7 @@
#pragma once
#include <LibCore/Timer.h>
#include <LibMedia/Audio/PlaybackStream.h>
#include <LibWeb/Platform/AudioCodecPlugin.h>

View file

@ -7,11 +7,8 @@
#pragma once
#include <AK/Vector.h>
#include <LibCore/EventReceiver.h>
#include <LibHTTP/HeaderMap.h>
#include <LibTLS/TLSv12.h>
#include <LibURL/URL.h>
#include <LibWebSocket/Message.h>
namespace WebSocket {

View file

@ -8,6 +8,7 @@
#include <LibCore/EventLoop.h>
#include <LibCore/Socket.h>
#include <LibTLS/TLSv12.h>
#include <LibWebSocket/Impl/WebSocketImplSerenity.h>
namespace WebSocket {

View file

@ -10,7 +10,6 @@
#include <LibCrypto/Hash/HashManager.h>
#include <LibWebSocket/Impl/WebSocketImplSerenity.h>
#include <LibWebSocket/WebSocket.h>
#include <unistd.h>
namespace WebSocket {

View file

@ -231,11 +231,14 @@ public:
Function<void(String const&)> on_inspector_executed_console_script;
Function<void(String const&)> on_inspector_exported_inspector_html;
Function<void()> on_web_content_crashed;
Function<void(URL::URL const&)> on_loading_page_and_fonts_finish;
virtual Web::DevicePixelSize viewport_size() const = 0;
virtual Gfx::IntPoint to_content_position(Gfx::IntPoint widget_position) const = 0;
virtual Gfx::IntPoint to_widget_position(Gfx::IntPoint content_position) const = 0;
u64 page_id() const;
protected:
static constexpr auto ZOOM_MIN_LEVEL = 0.3f;
static constexpr auto ZOOM_MAX_LEVEL = 5.0f;
@ -245,7 +248,6 @@ protected:
WebContentClient& client();
WebContentClient const& client() const;
u64 page_id() const;
virtual void update_zoom() = 0;
void handle_resize();

View file

@ -93,6 +93,15 @@ void WebContentClient::did_finish_text_test(u64 page_id, String const& text)
}
}
void WebContentClient::did_finish_loading_page_and_fonts(u64 page_id, URL::URL const& url)
{
if (auto view = view_for_page_id(page_id); view.has_value()) {
if (view->on_loading_page_and_fonts_finish)
view->on_loading_page_and_fonts_finish(url);
}
}
void WebContentClient::did_find_in_page(u64 page_id, size_t current_match_index, Optional<size_t> const& total_match_count)
{
if (auto view = view_for_page_id(page_id); view.has_value()) {

View file

@ -108,6 +108,7 @@ private:
virtual void did_request_select_dropdown(u64 page_id, Gfx::IntPoint content_position, i32 minimum_width, Vector<Web::HTML::SelectItem> const& items) override;
virtual void did_finish_handling_input_event(u64 page_id, Web::EventResult event_result) override;
virtual void did_finish_text_test(u64 page_id, String const& text) override;
virtual void did_finish_loading_page_and_fonts(u64 page_id, URL::URL const& url) override;
virtual void did_find_in_page(u64 page_id, size_t current_match_index, Optional<size_t> const& total_match_count) override;
virtual void did_change_theme_color(u64 page_id, Gfx::Color color) override;
virtual void did_insert_clipboard_entry(u64 page_id, String const& data, String const& presentation_style, String const& mime_type) override;

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Format.h>
#include <LibCrypto/ASN1/PEM.h>
#include <stddef.h>
#include <stdint.h>

View file

@ -402,6 +402,7 @@ ErrorOr<void> generate_implementation_file(JsonObject& properties, Core::File& f
#include <LibWeb/CSS/Enums.h>
#include <LibWeb/CSS/Parser/Parser.h>
#include <LibWeb/CSS/PropertyID.h>
#include <LibWeb/CSS/PropertyName.h>
#include <LibWeb/CSS/CSSStyleValue.h>
#include <LibWeb/CSS/StyleValues/PercentageStyleValue.h>
#include <LibWeb/CSS/StyleValues/TimeStyleValue.h>
@ -436,6 +437,9 @@ Optional<PropertyID> property_id_from_camel_case_string(StringView string)
Optional<PropertyID> property_id_from_string(StringView string)
{
if (is_a_custom_property_name_string(string))
return PropertyID::Custom;
if (Infra::is_ascii_case_insensitive_match(string, "all"sv))
return PropertyID::All;
)~~~");

Some files were not shown because too many files have changed in this diff Show more