mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-21 23:20:20 +00:00
Merge 4c1d4aa678
into d6bcd3fb0b
This commit is contained in:
commit
a7231f874a
56 changed files with 2405 additions and 231 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
176
Libraries/LibGfx/Font/FontVariant.cpp
Normal file
176
Libraries/LibGfx/Font/FontVariant.cpp
Normal 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());
|
||||
}
|
||||
|
||||
}
|
90
Libraries/LibGfx/Font/FontVariant.h
Normal file
90
Libraries/LibGfx/Font/FontVariant.h
Normal 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);
|
||||
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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]]
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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>&);
|
||||
|
|
|
@ -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": {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) } };
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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) { }
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -140,6 +140,7 @@ void ConnectionFromClient::update_screen_rects(u64 page_id, Vector<Web::DevicePi
|
|||
|
||||
void ConnectionFromClient::load_url(u64 page_id, const URL::URL& url)
|
||||
{
|
||||
dbgln("ConnectionFromClient::load_url({}, {})", page_id, url);
|
||||
auto page = this->page(page_id);
|
||||
if (!page.has_value())
|
||||
return;
|
||||
|
|
|
@ -355,6 +355,12 @@ void PageClient::page_did_finish_text_test(String const& text)
|
|||
client().async_did_finish_text_test(m_id, text);
|
||||
}
|
||||
|
||||
void PageClient::page_did_finish_loading_page_and_fonts(URL::URL const& url)
|
||||
{
|
||||
dbgln("PageClient::page_did_finish_loading_page_and_fonts: {}", url);
|
||||
client().async_did_finish_loading_page_and_fonts(m_id, url);
|
||||
}
|
||||
|
||||
void PageClient::page_did_request_context_menu(Web::CSSPixelPoint content_position)
|
||||
{
|
||||
client().async_did_request_context_menu(m_id, page().css_to_device_point(content_position).to_type<int>());
|
||||
|
|
|
@ -155,6 +155,7 @@ private:
|
|||
virtual void page_did_request_file_picker(Web::HTML::FileFilter accepted_file_types, Web::HTML::AllowMultipleFiles) override;
|
||||
virtual void page_did_request_select_dropdown(Web::CSSPixelPoint content_position, Web::CSSPixels minimum_width, Vector<Web::HTML::SelectItem> items) override;
|
||||
virtual void page_did_finish_text_test(String const& text) override;
|
||||
virtual void page_did_finish_loading_page_and_fonts(URL::URL const& url) override;
|
||||
virtual void page_did_change_theme_color(Gfx::Color color) override;
|
||||
virtual void page_did_insert_clipboard_entry(String data, String presentation_style, String mime_type) override;
|
||||
virtual void page_did_change_audio_play_state(Web::HTML::AudioPlayState) override;
|
||||
|
|
|
@ -95,7 +95,7 @@ endpoint WebContentClient
|
|||
did_get_js_console_messages(u64 page_id, i32 start_index, Vector<ByteString> message_types, Vector<ByteString> messages) =|
|
||||
|
||||
did_finish_text_test(u64 page_id, String text) =|
|
||||
|
||||
did_finish_loading_page_and_fonts(u64 page_id, URL::URL url) =|
|
||||
did_find_in_page(u64 page_id, size_t current_match_index, Optional<size_t> total_match_count) =|
|
||||
|
||||
request_worker_agent(u64 page_id) => (IPC::File socket) // FIXME: Add required attributes to select a SharedWorker Agent
|
||||
|
|
63
Tests/LibWeb/Ref/data/font-variant-features.css
Normal file
63
Tests/LibWeb/Ref/data/font-variant-features.css
Normal file
|
@ -0,0 +1,63 @@
|
|||
body { margin: 10px; }
|
||||
|
||||
@font-face {
|
||||
font-family: gsub-test;
|
||||
src: url(gsubtest-lookup3.otf);
|
||||
}
|
||||
|
||||
td.prop {
|
||||
font-family: Menlo, monospace;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
td.features {
|
||||
font-family: gsub-test;
|
||||
}
|
||||
|
||||
.invalid {
|
||||
color: red;
|
||||
}
|
||||
|
||||
@font-feature-values gsub-test {
|
||||
@styleset { ok-alt-a: 1 3 5; ok-alt-b: 19; }
|
||||
@character-variant { ok-1: 78 2; }
|
||||
@character-variant { ok-3: 23; }
|
||||
@character-variant { not-good: 0 2; }
|
||||
@annotation { ok-4: 1; }
|
||||
@annotation { bogus-font-doesnt-support: 23; }
|
||||
@annotation { circled: 1; }
|
||||
@character-variant { multi-def: 4; }
|
||||
@annotation { multi-def: 3; }
|
||||
@styleset { multi-def2: 3 4 5; }
|
||||
@styleset { MULTI-def2: 2 6; }
|
||||
@styleset { out-of-bounds1: 0; out-of-bounds2: 100; }
|
||||
}
|
||||
|
||||
@font-feature-values bogus-family {
|
||||
@styleset { bogus: 3 4 7; }
|
||||
}
|
||||
|
||||
@font-feature-values GSUB-tEsT {
|
||||
@styleset { mixed-case: 3 4 7; }
|
||||
}
|
||||
|
||||
@font-feature-values gSuB-tEsT {
|
||||
@styleset { 3blah: 1 3; }
|
||||
}
|
||||
|
||||
@font-feature-values gSuB-tEsT {
|
||||
@styleset { moxie: 14; }
|
||||
@styleset { 3blah: 1; }
|
||||
}
|
||||
|
||||
@font-feature-values gSUB-TeST {
|
||||
@styleset { moxie2: 14; }
|
||||
@bongo { blah: 1; }
|
||||
}
|
||||
|
||||
@font-feature-values gSUB-TEst {
|
||||
@bongo { blah2: 1; }
|
||||
@styleset { moxie3: 14; }
|
||||
}
|
218
Tests/LibWeb/Ref/data/font-variant-features.js
Normal file
218
Tests/LibWeb/Ref/data/font-variant-features.js
Normal file
|
@ -0,0 +1,218 @@
|
|||
|
||||
// data associated with gsubtest test font for testing font features
|
||||
|
||||
// prefix
|
||||
gPrefix = "";
|
||||
|
||||
// equivalent properties
|
||||
// setting prop: value should match the specific feature settings listed
|
||||
//
|
||||
// each of these tests evaluate whether a given feature is enabled as required
|
||||
// and also whether features that shouldn't be enabled are or not.
|
||||
var gPropertyData = [
|
||||
// font-variant-caps
|
||||
// valid values
|
||||
{ prop: "font-variant-caps", value: "normal", features: {"smcp": 0} },
|
||||
{ prop: "font-variant-caps", value: "small-caps", features: {"smcp": 1, "c2sc": 0} },
|
||||
{ prop: "font-variant-caps", value: "all-small-caps", features: {"smcp": 1, "c2sc": 1, "pcap": 0} },
|
||||
{ prop: "font-variant-caps", value: "petite-caps", features: {"pcap": 1, "smcp": 0} },
|
||||
{ prop: "font-variant-caps", value: "all-petite-caps", features: {"c2pc": 1, "pcap": 1, "smcp": 0} },
|
||||
{ prop: "font-variant-caps", value: "titling-caps", features: {"titl": 1, "smcp": 0} },
|
||||
{ prop: "font-variant-caps", value: "unicase", features: {"unic": 1, "titl": 0} },
|
||||
|
||||
// invalid values
|
||||
{ prop: "font-variant-caps", value: "normal small-caps", features: {"smcp": 0}, invalid: true },
|
||||
{ prop: "font-variant-caps", value: "small-caps potato", features: {"smcp": 0}, invalid: true },
|
||||
{ prop: "font-variant-caps", value: "small-caps petite-caps", features: {"smcp": 0, "pcap": 0}, invalid: true },
|
||||
{ prop: "font-variant-caps", value: "small-caps all-small-caps", features: {"smcp": 0, "c2sc": 0}, invalid: true },
|
||||
{ prop: "font-variant-caps", value: "small-cap", features: {"smcp": 0}, invalid: true },
|
||||
|
||||
// font-variant-east-asian
|
||||
// valid values
|
||||
{ prop: "font-variant-east-asian", value: "jis78", features: {"jp78": 1, "jp04": 0} },
|
||||
{ prop: "font-variant-east-asian", value: "jis83", features: {"jp83": 1, "jp04": 0} },
|
||||
{ prop: "font-variant-east-asian", value: "jis90", features: {"jp90": 1, "jp04": 0} },
|
||||
{ prop: "font-variant-east-asian", value: "jis04", features: {"jp04": 1, "jp78": 0} },
|
||||
{ prop: "font-variant-east-asian", value: "simplified", features: {"smpl": 1, "jp04": 0} },
|
||||
{ prop: "font-variant-east-asian", value: "traditional", features: {"trad": 1, "jp04": 0} },
|
||||
{ prop: "font-variant-east-asian", value: "full-width", features: {"fwid": 1, "jp04": 0} },
|
||||
{ prop: "font-variant-east-asian", value: "proportional-width", features: {"pwid": 1, "jp04": 0} },
|
||||
{ prop: "font-variant-east-asian", value: "ruby", features: {"ruby": 1, "jp04": 0} },
|
||||
{ prop: "font-variant-east-asian", value: "jis78 full-width", features: {"jp78": 1, "fwid": 1, "jp83": 0} },
|
||||
{ prop: "font-variant-east-asian", value: "jis78 full-width ruby", features: {"jp78": 1, "fwid": 1, "jp83": 0, "ruby": 1} },
|
||||
{ prop: "font-variant-east-asian", value: "simplified proportional-width", features: {"smpl": 1, "pwid": 1, "jp83": 0} },
|
||||
{ prop: "font-variant-east-asian", value: "ruby simplified", features: {"ruby": 1, "smpl": 1, "trad": 0} },
|
||||
|
||||
// invalid values
|
||||
{ prop: "font-variant-east-asian", value: "ruby normal", features: {"ruby": 0}, invalid: true },
|
||||
{ prop: "font-variant-east-asian", value: "jis90 jis04", features: {"jp90": 0, "jp04": 0}, invalid: true },
|
||||
{ prop: "font-variant-east-asian", value: "simplified traditional", features: {"smpl": 0, "trad": 0}, invalid: true },
|
||||
{ prop: "font-variant-east-asian", value: "full-width proportional-width", features: {"fwid": 0, "pwid": 0}, invalid: true },
|
||||
{ prop: "font-variant-east-asian", value: "ruby simplified ruby", features: {"ruby": 0, "smpl": 0, "jp04": 0}, invalid: true },
|
||||
{ prop: "font-variant-east-asian", value: "jis78 ruby simplified", features: {"ruby": 0, "smpl": 0, "jp78": 0}, invalid: true },
|
||||
|
||||
// font-variant-ligatures
|
||||
// valid values
|
||||
{ prop: "font-variant-ligatures", value: "normal", features: {"liga": 1, "dlig": 0} },
|
||||
{ prop: "font-variant-ligatures", value: "common-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0, "hlig": 0, "calt": 1} },
|
||||
{ prop: "font-variant-ligatures", value: "no-common-ligatures", features: {"liga": 0, "clig": 0, "dlig": 0, "hlig": 0, "calt": 1} },
|
||||
{ prop: "font-variant-ligatures", value: "discretionary-ligatures", features: {"liga": 1, "clig": 1, "dlig": 1, "hlig": 0, "calt": 1} },
|
||||
{ prop: "font-variant-ligatures", value: "no-discretionary-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0, "hlig": 0, "calt": 1} },
|
||||
{ prop: "font-variant-ligatures", value: "historical-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0, "hlig": 1, "calt": 1} },
|
||||
{ prop: "font-variant-ligatures", value: "no-historical-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0, "hlig": 0, "calt": 1} },
|
||||
{ prop: "font-variant-ligatures", value: "contextual", features: {"liga": 1, "clig": 1, "dlig": 0, "hlig": 0, "calt": 1} },
|
||||
{ prop: "font-variant-ligatures", value: "no-contextual", features: {"liga": 1, "clig": 1, "dlig": 0, "hlig": 0, "calt": 0} },
|
||||
{ prop: "font-variant-ligatures", value: "common-ligatures no-discretionary-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0, "hlig": 0, "calt": 1} },
|
||||
{ prop: "font-variant-ligatures", value: "historical-ligatures no-common-ligatures", features: {"clig": 0, "liga": 0, "dlig": 0, "hlig": 1, "calt": 1} },
|
||||
{ prop: "font-variant-ligatures", value: "no-historical-ligatures discretionary-ligatures", features: {"liga": 1, "clig": 1, "dlig": 1, "hlig": 0, "calt": 1} },
|
||||
{ prop: "font-variant-ligatures", value: "common-ligatures no-discretionary-ligatures historical-ligatures no-contextual", features: {"clig": 1, "dlig": 0, "hlig": 1, "liga": 1, "calt": 0} },
|
||||
|
||||
// invalid values
|
||||
{ prop: "font-variant-ligatures", value: "common-ligatures normal", features: {"liga": 1, "clig": 1, "dlig": 0}, invalid: true },
|
||||
{ prop: "font-variant-ligatures", value: "common-ligatures no-common-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0}, invalid: true },
|
||||
{ prop: "font-variant-ligatures", value: "common-ligatures common-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0}, invalid: true },
|
||||
{ prop: "font-variant-ligatures", value: "no-historical-ligatures historical-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0, "hlig": 0}, invalid: true },
|
||||
{ prop: "font-variant-ligatures", value: "no-contextual contextual", features: {"liga": 1, "clig": 1, "dlig": 0, "hlig": 0}, invalid: true },
|
||||
{ prop: "font-variant-ligatures", value: "no-discretionary-ligatures discretionary-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0}, invalid: true },
|
||||
{ prop: "font-variant-ligatures", value: "common-ligatures no-discretionary-ligatures no-common-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0}, invalid: true },
|
||||
|
||||
// font-variant-numeric
|
||||
// valid values
|
||||
{ prop: "font-variant-numeric", value: "normal", features: {"lnum": 0, "tnum": 0, "pnum": 0, "onum": 0} },
|
||||
{ prop: "font-variant-numeric", value: "lining-nums", features: {"lnum": 1, "onum": 0, "pnum": 0} },
|
||||
{ prop: "font-variant-numeric", value: "oldstyle-nums", features: {"lnum": 0, "onum": 1, "pnum": 0} },
|
||||
{ prop: "font-variant-numeric", value: "proportional-nums", features: {"lnum": 0, "onum": 0, "pnum": 1, "tnum": 0} },
|
||||
{ prop: "font-variant-numeric", value: "proportional-nums oldstyle-nums", features: {"lnum": 0, "onum": 1, "pnum": 1, "tnum": 0} },
|
||||
{ prop: "font-variant-numeric", value: "tabular-nums", features: {"tnum": 1, "onum": 0, "pnum": 0} },
|
||||
{ prop: "font-variant-numeric", value: "diagonal-fractions", features: {"frac": 1, "afrc": 0, "pnum": 0} },
|
||||
{ prop: "font-variant-numeric", value: "stacked-fractions", features: {"frac": 0, "afrc": 1, "pnum": 0} },
|
||||
{ prop: "font-variant-numeric", value: "slashed-zero", features: {"zero": 1, "pnum": 0} },
|
||||
{ prop: "font-variant-numeric", value: "ordinal", features: {"ordn": 1, "pnum": 0} },
|
||||
{ prop: "font-variant-numeric", value: "lining-nums diagonal-fractions", features: {"frac": 1, "afrc": 0, "lnum": 1} },
|
||||
{ prop: "font-variant-numeric", value: "tabular-nums stacked-fractions", features: {"frac": 0, "afrc": 1, "tnum": 1} },
|
||||
{ prop: "font-variant-numeric", value: "tabular-nums slashed-zero stacked-fractions", features: {"frac": 0, "afrc": 1, "tnum": 1, "zero": 1} },
|
||||
{ prop: "font-variant-numeric", value: "proportional-nums slashed-zero diagonal-fractions oldstyle-nums ordinal", features: {"frac": 1, "afrc": 0, "tnum": 0, "pnum": 1, "onum": 1, "ordn": 1, "zero": 1} },
|
||||
|
||||
// invalid values
|
||||
{ prop: "font-variant-numeric", value: "lining-nums normal", features: {"lnum": 0, "onum": 0}, invalid: true },
|
||||
{ prop: "font-variant-numeric", value: "lining-nums oldstyle-nums", features: {"lnum": 0, "onum": 0}, invalid: true },
|
||||
{ prop: "font-variant-numeric", value: "lining-nums normal slashed-zero ordinal", features: {"lnum": 0, "onum": 0, "zero": 0}, invalid: true },
|
||||
{ prop: "font-variant-numeric", value: "proportional-nums tabular-nums", features: {"pnum": 0, "tnum": 0}, invalid: true },
|
||||
{ prop: "font-variant-numeric", value: "diagonal-fractions stacked-fractions", features: {"frac": 0, "afrc": 0}, invalid: true },
|
||||
{ prop: "font-variant-numeric", value: "slashed-zero diagonal-fractions slashed-zero", features: {"frac": 0, "afrc": 0, "zero": 0}, invalid: true },
|
||||
{ prop: "font-variant-numeric", value: "lining-nums slashed-zero diagonal-fractions oldstyle-nums", features: {"frac": 0, "afrc": 0, "zero": 0, "onum": 0}, invalid: true },
|
||||
|
||||
// font-variant-position
|
||||
// valid values
|
||||
{ prop: "font-variant-position", value: "normal", features: {"subs": 0, "sups": 0} },
|
||||
{ prop: "font-variant-position", value: "super", features: {"subs": 0, "sups": 1} },
|
||||
{ prop: "font-variant-position", value: "sub", features: {"subs": 1, "sups": 0} },
|
||||
|
||||
// invalid values
|
||||
{ prop: "font-variant-position", value: "super sub", features: {"subs": 0, "sups": 0}, invalid: true },
|
||||
];
|
||||
|
||||
// note: the code below requires an array "gFeatures" from :
|
||||
// support/fonts/gsubtest-features.js
|
||||
|
||||
// The font defines feature lookups for all OpenType features for a
|
||||
// specific set of PUA codepoints, as listed in the gFeatures array.
|
||||
// Using these codepoints and feature combinations, tests can be
|
||||
// constructed to detect when certain features are enabled or not.
|
||||
|
||||
// return a created table containing tests for a given property
|
||||
//
|
||||
// Ex: { prop: "font-variant-ligatures", value: "common-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0, "hlig": 0} }
|
||||
//
|
||||
// This means that for the property 'font-variant-ligatures' with the value 'common-ligatures', the features listed should
|
||||
// either be explicitly enabled or disabled.
|
||||
|
||||
// propData is the prop/value list with corresponding feature assertions
|
||||
// whichProp is either "all" or a specific subproperty (i.e. "font-variant-position")
|
||||
// isRef is true when this is the reference
|
||||
// debug outputs the prop/value pair along with the tests
|
||||
|
||||
function createFeatureTestTable(propData, whichProp, isRef, debug)
|
||||
{
|
||||
var table = document.createElement("table");
|
||||
|
||||
if (typeof(isRef) == "undefined") {
|
||||
isRef = false;
|
||||
}
|
||||
|
||||
if (typeof(debug) == "undefined") {
|
||||
debug = false;
|
||||
}
|
||||
|
||||
var doAll = (whichProp == "all");
|
||||
for (var i in propData) {
|
||||
var data = propData[i];
|
||||
|
||||
if (!doAll && data.prop != whichProp) continue;
|
||||
|
||||
var row = document.createElement("tr");
|
||||
var invalid = false;
|
||||
if ("invalid" in data) {
|
||||
invalid = true;
|
||||
row.className = "invalid";
|
||||
}
|
||||
|
||||
var cell = document.createElement("td");
|
||||
cell.className = "prop";
|
||||
var styledecl = gPrefix + data.prop + ": " + data.value + ";";
|
||||
cell.innerHTML = styledecl;
|
||||
row.appendChild(cell);
|
||||
if (debug) {
|
||||
table.appendChild(row);
|
||||
}
|
||||
|
||||
row = document.createElement("tr");
|
||||
if (invalid) {
|
||||
row.className = "invalid";
|
||||
}
|
||||
|
||||
cell = document.createElement("td");
|
||||
cell.className = "features";
|
||||
if (!isRef) {
|
||||
cell.style.cssText = styledecl;
|
||||
}
|
||||
|
||||
for (var f in data.features) {
|
||||
var feature = data.features[f];
|
||||
|
||||
var cp, unsupported = "F".charCodeAt(0);
|
||||
var basecp = gFeatures[f];
|
||||
|
||||
if (typeof(basecp) == "undefined") {
|
||||
cp = unsupported;
|
||||
} else {
|
||||
switch(feature) {
|
||||
case 0:
|
||||
cp = basecp;
|
||||
break;
|
||||
case 1:
|
||||
cp = basecp + 1;
|
||||
break;
|
||||
case 2:
|
||||
cp = basecp + 2;
|
||||
break;
|
||||
case 3:
|
||||
cp = basecp + 3;
|
||||
break;
|
||||
default:
|
||||
cp = basecp + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var span = document.createElement("span");
|
||||
span.innerHTML = (isRef ? "P " : "&#x" + cp.toString(16) + "; ");
|
||||
span.title = f + "=" + feature;
|
||||
cell.appendChild(span);
|
||||
}
|
||||
row.appendChild(cell);
|
||||
table.appendChild(row);
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
85
Tests/LibWeb/Ref/data/gsubtest-features.js
Normal file
85
Tests/LibWeb/Ref/data/gsubtest-features.js
Normal file
|
@ -0,0 +1,85 @@
|
|||
|
||||
/* This file is autogenerated by makegsubfonts.py */
|
||||
|
||||
/*
|
||||
Features defined in gsubtest fonts with associated base
|
||||
codepoints for each feature:
|
||||
|
||||
cp = codepoint for feature featX
|
||||
|
||||
cp default PASS
|
||||
cp featX=1 FAIL
|
||||
cp featX=2 FAIL
|
||||
|
||||
cp+1 default FAIL
|
||||
cp+1 featX=1 PASS
|
||||
cp+1 featX=2 FAIL
|
||||
|
||||
cp+2 default FAIL
|
||||
cp+2 featX=1 FAIL
|
||||
cp+2 featX=2 PASS
|
||||
|
||||
*/
|
||||
|
||||
var gFeatures = {
|
||||
"MWL1": 0xe000, "NUM2": 0xe004, "PRIV": 0xe008, "T3ST": 0xe00c,
|
||||
"TPSP": 0xe010, "abvf": 0xe014, "abvm": 0xe018, "abvs": 0xe01c,
|
||||
"afrc": 0xe020, "akhn": 0xe024, "blwf": 0xe028, "blwm": 0xe02c,
|
||||
"blws": 0xe030, "c2pc": 0xe034, "c2sc": 0xe038, "calt": 0xe03c,
|
||||
"case": 0xe040, "ccmp": 0xe044, "cfar": 0xe048, "cjct": 0xe04c,
|
||||
"clig": 0xe050, "cpct": 0xe054, "cpsp": 0xe058, "cswh": 0xe05c,
|
||||
"curs": 0xe060, "cv00": 0xe064, "cv01": 0xe068, "cv02": 0xe06c,
|
||||
"cv03": 0xe070, "cv04": 0xe074, "cv05": 0xe078, "cv06": 0xe07c,
|
||||
"cv07": 0xe080, "cv08": 0xe084, "cv09": 0xe088, "cv10": 0xe08c,
|
||||
"cv11": 0xe090, "cv12": 0xe094, "cv13": 0xe098, "cv14": 0xe09c,
|
||||
"cv15": 0xe0a0, "cv16": 0xe0a4, "cv17": 0xe0a8, "cv18": 0xe0ac,
|
||||
"cv19": 0xe0b0, "cv20": 0xe0b4, "cv21": 0xe0b8, "cv22": 0xe0bc,
|
||||
"cv23": 0xe0c0, "cv24": 0xe0c4, "cv25": 0xe0c8, "cv26": 0xe0cc,
|
||||
"cv27": 0xe0d0, "cv28": 0xe0d4, "cv29": 0xe0d8, "cv30": 0xe0dc,
|
||||
"cv31": 0xe0e0, "cv32": 0xe0e4, "cv33": 0xe0e8, "cv34": 0xe0ec,
|
||||
"cv35": 0xe0f0, "cv36": 0xe0f4, "cv37": 0xe0f8, "cv38": 0xe0fc,
|
||||
"cv39": 0xe100, "cv40": 0xe104, "cv41": 0xe108, "cv42": 0xe10c,
|
||||
"cv43": 0xe110, "cv44": 0xe114, "cv45": 0xe118, "cv46": 0xe11c,
|
||||
"cv47": 0xe120, "cv48": 0xe124, "cv49": 0xe128, "cv50": 0xe12c,
|
||||
"cv51": 0xe130, "cv52": 0xe134, "cv53": 0xe138, "cv54": 0xe13c,
|
||||
"cv55": 0xe140, "cv56": 0xe144, "cv57": 0xe148, "cv58": 0xe14c,
|
||||
"cv59": 0xe150, "cv60": 0xe154, "cv61": 0xe158, "cv62": 0xe15c,
|
||||
"cv63": 0xe160, "cv64": 0xe164, "cv65": 0xe168, "cv66": 0xe16c,
|
||||
"cv67": 0xe170, "cv68": 0xe174, "cv69": 0xe178, "cv70": 0xe17c,
|
||||
"cv71": 0xe180, "cv72": 0xe184, "cv73": 0xe188, "cv74": 0xe18c,
|
||||
"cv75": 0xe190, "cv76": 0xe194, "cv77": 0xe198, "cv78": 0xe19c,
|
||||
"cv79": 0xe1a0, "cv80": 0xe1a4, "cv81": 0xe1a8, "cv82": 0xe1ac,
|
||||
"cv83": 0xe1b0, "cv84": 0xe1b4, "cv85": 0xe1b8, "cv86": 0xe1bc,
|
||||
"cv87": 0xe1c0, "cv88": 0xe1c4, "cv89": 0xe1c8, "cv90": 0xe1cc,
|
||||
"cv91": 0xe1d0, "cv92": 0xe1d4, "cv93": 0xe1d8, "cv94": 0xe1dc,
|
||||
"cv95": 0xe1e0, "cv96": 0xe1e4, "cv97": 0xe1e8, "cv98": 0xe1ec,
|
||||
"cv99": 0xe1f0, "dist": 0xe1f4, "dlig": 0xe1f8, "dnom": 0xe1fc,
|
||||
"expt": 0xe200, "falt": 0xe204, "fin2": 0xe208, "fin3": 0xe20c,
|
||||
"fina": 0xe210, "frac": 0xe214, "fwid": 0xe218, "half": 0xe21c,
|
||||
"haln": 0xe220, "halt": 0xe224, "hist": 0xe228, "hkna": 0xe22c,
|
||||
"hlig": 0xe230, "hngl": 0xe234, "hojo": 0xe238, "hwid": 0xe23c,
|
||||
"init": 0xe240, "isol": 0xe244, "ital": 0xe248, "jalt": 0xe24c,
|
||||
"jp04": 0xe250, "jp78": 0xe254, "jp83": 0xe258, "jp90": 0xe25c,
|
||||
"kern": 0xe260, "lfbd": 0xe264, "liga": 0xe268, "ljmo": 0xe26c,
|
||||
"lnum": 0xe270, "locl": 0xe274, "ltra": 0xe278, "ltrm": 0xe27c,
|
||||
"mark": 0xe280, "med2": 0xe284, "medi": 0xe288, "mgrk": 0xe28c,
|
||||
"mkmk": 0xe290, "mset": 0xe294, "nalt": 0xe298, "nlck": 0xe29c,
|
||||
"nukt": 0xe2a0, "numr": 0xe2a4, "onum": 0xe2a8, "opbd": 0xe2ac,
|
||||
"ordn": 0xe2b0, "ornm": 0xe2b4, "palt": 0xe2b8, "pcap": 0xe2bc,
|
||||
"pkna": 0xe2c0, "pnum": 0xe2c4, "pref": 0xe2c8, "pres": 0xe2cc,
|
||||
"pstf": 0xe2d0, "psts": 0xe2d4, "pwid": 0xe2d8, "qwid": 0xe2dc,
|
||||
"rand": 0xe2e0, "rkrf": 0xe2e4, "rlig": 0xe2e8, "rphf": 0xe2ec,
|
||||
"rtbd": 0xe2f0, "rtla": 0xe2f4, "rtlm": 0xe2f8, "ruby": 0xe2fc,
|
||||
"salt": 0xe300, "sinf": 0xe304, "size": 0xe308, "smcp": 0xe30c,
|
||||
"smpl": 0xe310, "ss00": 0xe314, "ss01": 0xe318, "ss02": 0xe31c,
|
||||
"ss03": 0xe320, "ss04": 0xe324, "ss05": 0xe328, "ss06": 0xe32c,
|
||||
"ss07": 0xe330, "ss08": 0xe334, "ss09": 0xe338, "ss10": 0xe33c,
|
||||
"ss11": 0xe340, "ss12": 0xe344, "ss13": 0xe348, "ss14": 0xe34c,
|
||||
"ss15": 0xe350, "ss16": 0xe354, "ss17": 0xe358, "ss18": 0xe35c,
|
||||
"ss19": 0xe360, "ss20": 0xe364, "ss21": 0xe368, "subs": 0xe36c,
|
||||
"sups": 0xe370, "swsh": 0xe374, "titl": 0xe378, "tjmo": 0xe37c,
|
||||
"tnam": 0xe380, "tnum": 0xe384, "trad": 0xe388, "twid": 0xe38c,
|
||||
"unic": 0xe390, "valt": 0xe394, "vatu": 0xe398, "vert": 0xe39c,
|
||||
"vhal": 0xe3a0, "vjmo": 0xe3a4, "vkna": 0xe3a8, "vkrn": 0xe3ac,
|
||||
"vpal": 0xe3b0, "vrt2": 0xe3b4, "zero": 0xe3b8
|
||||
};
|
BIN
Tests/LibWeb/Ref/data/gsubtest-lookup3.otf
Normal file
BIN
Tests/LibWeb/Ref/data/gsubtest-lookup3.otf
Normal file
Binary file not shown.
|
@ -0,0 +1,21 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>CSS Test: feature value matching for font-variant-caps</title>
|
||||
<link rel="author" title="John Daggett" href="mailto:jdaggett@mozilla.com"/>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<script type="text/javascript" src="../../../../data/gsubtest-features.js"></script>
|
||||
<script type="text/javascript" src="../../../../data/font-variant-features.js"></script>
|
||||
<link rel="stylesheet" href="../../../../data/font-variant-features.css" type="text/css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content"></div>
|
||||
<script type="text/javascript">
|
||||
document.fonts.ready.then(() => {
|
||||
internals.finishLoading();
|
||||
})
|
||||
internals.disableAutomaticPageFinish();
|
||||
document.getElementById("content").appendChild(createFeatureTestTable(gPropertyData, "font-variant-caps", true, false));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,21 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>CSS Test: feature value matching for font-variant-east-asian</title>
|
||||
<link rel="author" title="John Daggett" href="mailto:jdaggett@mozilla.com"/>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<script type="text/javascript" src="../../../../data/gsubtest-features.js"></script>
|
||||
<script type="text/javascript" src="../../../../data/font-variant-features.js"></script>
|
||||
<link rel="stylesheet" href="../../../../data/font-variant-features.css" type="text/css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content"></div>
|
||||
<script type="text/javascript">
|
||||
document.fonts.ready.then(() => {
|
||||
internals.finishLoading();
|
||||
})
|
||||
internals.disableAutomaticPageFinish();
|
||||
document.getElementById("content").appendChild(createFeatureTestTable(gPropertyData, "font-variant-east-asian", true, false));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,21 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>CSS Test: feature value matching for font-variant-ligatures</title>
|
||||
<link rel="author" title="John Daggett" href="mailto:jdaggett@mozilla.com"/>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<script type="text/javascript" src="../../../../data/gsubtest-features.js"></script>
|
||||
<script type="text/javascript" src="../../../../data/font-variant-features.js"></script>
|
||||
<link rel="stylesheet" href="../../../../data/font-variant-features.css" type="text/css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content"></div>
|
||||
<script type="text/javascript">
|
||||
document.fonts.ready.then(() => {
|
||||
internals.finishLoading();
|
||||
})
|
||||
internals.disableAutomaticPageFinish();
|
||||
document.getElementById("content").appendChild(createFeatureTestTable(gPropertyData, "font-variant-ligatures", true, false));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,24 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>CSS Test: feature value matching for font-variant-numeric</title>
|
||||
<link rel="author" title="John Daggett" href="mailto:jdaggett@mozilla.com"/>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<script type="text/javascript" src="../../../../data/gsubtest-features.js"></script>
|
||||
<script type="text/javascript" src="../../../../data/font-variant-features.js"></script>
|
||||
<link rel="stylesheet" href="../../../../data/font-variant-features.css" type="text/css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content"></div>
|
||||
<script type="text/javascript">
|
||||
window.onload = (event) => {
|
||||
console.log('expectation onload', event.target.location.href);
|
||||
}
|
||||
document.fonts.ready.then(() => {
|
||||
console.log('exceptation document.fonts.ready');
|
||||
})
|
||||
// internals.disableAutomaticPageFinish();
|
||||
document.getElementById("content").appendChild(createFeatureTestTable(gPropertyData, "font-variant-numeric", true, false));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,21 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>CSS Test: feature value matching for font-variant-position</title>
|
||||
<link rel="author" title="John Daggett" href="mailto:jdaggett@mozilla.com"/>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<script type="text/javascript" src="../../../../data/gsubtest-features.js"></script>
|
||||
<script type="text/javascript" src="../../../../data/font-variant-features.js"></script>
|
||||
<link rel="stylesheet" href="../../../../data/font-variant-features.css" type="text/css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content"></div>
|
||||
<script type="text/javascript">
|
||||
document.fonts.ready.then(() => {
|
||||
internals.finishLoading();
|
||||
})
|
||||
internals.disableAutomaticPageFinish();
|
||||
document.getElementById("content").appendChild(createFeatureTestTable(gPropertyData, "font-variant-position", true, false));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,24 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>CSS Test: feature value matching for font-variant-caps</title>
|
||||
<link rel="author" title="John Daggett" href="mailto:jdaggett@mozilla.com"/>
|
||||
<link rel="help" href="http://www.w3.org/TR/css-fonts-3/#font-variant-caps-prop"/>
|
||||
<link rel="match" href="../../../../expected/wpt-import/css/css-fonts/font-variant-caps-ref.html"/>
|
||||
<meta name="assert" content="Values of font-variant-caps should enable specific features without enabling others"/>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<script type="text/javascript" src="../../../../data/gsubtest-features.js"></script>
|
||||
<script type="text/javascript" src="../../../../data/font-variant-features.js"></script>
|
||||
<link rel="stylesheet" href="../../../../data/font-variant-features.css" type="text/css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content"></div>
|
||||
<script type="text/javascript">
|
||||
document.fonts.ready.then(() => {
|
||||
internals.finishLoading();
|
||||
})
|
||||
internals.disableAutomaticPageFinish();
|
||||
document.getElementById("content").appendChild(createFeatureTestTable(gPropertyData, "font-variant-caps", false, false));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,24 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>CSS Test: feature value matching for font-variant-east-asian</title>
|
||||
<link rel="author" title="John Daggett" href="mailto:jdaggett@mozilla.com"/>
|
||||
<link rel="help" href="http://www.w3.org/TR/css-fonts-3/#font-variant-east-asian-prop"/>
|
||||
<link rel="match" href="../../../../expected/wpt-import/css/css-fonts/font-variant-east-asian-ref.html"/>
|
||||
<meta name="assert" content="Values of font-variant-east-asian should enable specific features without enabling others"/>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<script type="text/javascript" src="../../../../data/gsubtest-features.js"></script>
|
||||
<script type="text/javascript" src="../../../../data/font-variant-features.js"></script>
|
||||
<link rel="stylesheet" href="../../../../data/font-variant-features.css" type="text/css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content"></div>
|
||||
<script type="text/javascript">
|
||||
document.fonts.ready.then(() => {
|
||||
internals.finishLoading();
|
||||
})
|
||||
internals.disableAutomaticPageFinish();
|
||||
document.getElementById("content").appendChild(createFeatureTestTable(gPropertyData, "font-variant-east-asian", false, false));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,24 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>CSS Test: feature value matching for font-variant-ligatures</title>
|
||||
<link rel="author" title="John Daggett" href="mailto:jdaggett@mozilla.com"/>
|
||||
<link rel="help" href="http://www.w3.org/TR/css-fonts-3/#font-variant-ligatures-prop"/>
|
||||
<link rel="match" href="../../../../expected/wpt-import/css/css-fonts/font-variant-ligatures-ref.html"/>
|
||||
<meta name="assert" content="Values of font-variant-ligatures should enable specific features without enabling others"/>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<script type="text/javascript" src="../../../../data/gsubtest-features.js"></script>
|
||||
<script type="text/javascript" src="../../../../data/font-variant-features.js"></script>
|
||||
<link rel="stylesheet" href="../../../../data/font-variant-features.css" type="text/css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content"></div>
|
||||
<script type="text/javascript">
|
||||
document.fonts.ready.then(() => {
|
||||
internals.finishLoading();
|
||||
})
|
||||
internals.disableAutomaticPageFinish();
|
||||
document.getElementById("content").appendChild(createFeatureTestTable(gPropertyData, "font-variant-ligatures", false, false));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,26 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>CSS Test: feature value matching for font-variant-numeric</title>
|
||||
<link rel="author" title="John Daggett" href="mailto:jdaggett@mozilla.com"/>
|
||||
<link rel="help" href="http://www.w3.org/TR/css-fonts-3/#font-variant-numeric-prop"/>
|
||||
<link rel="match" href="../../../../expected/wpt-import/css/css-fonts/font-variant-numeric-ref.html"/>
|
||||
<meta name="assert" content="Values of font-variant-numeric should enable specific features without enabling others"/>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<script type="text/javascript" src="../../../../data/gsubtest-features.js"></script>
|
||||
<script type="text/javascript" src="../../../../data/font-variant-features.js"></script>
|
||||
<link rel="stylesheet" href="../../../../data/font-variant-features.css" type="text/css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content"></div>
|
||||
<script type="text/javascript">
|
||||
window.onload = (event) => {
|
||||
console.log('actual onload', event.target.location.href);
|
||||
}
|
||||
document.fonts.ready.then(() => {
|
||||
console.log('actual document.fonts.ready');
|
||||
})
|
||||
document.getElementById("content").appendChild(createFeatureTestTable(gPropertyData, "font-variant-numeric", false, false));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,24 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>CSS Test: feature value matching for font-variant-position</title>
|
||||
<link rel="author" title="John Daggett" href="mailto:jdaggett@mozilla.com"/>
|
||||
<link rel="help" href="http://www.w3.org/TR/css-fonts-3/#font-variant-position-prop"/>
|
||||
<link rel="match" href="../../../../expected/wpt-import/css/css-fonts/font-variant-position-ref.html"/>
|
||||
<meta name="assert" content="Values of font-variant-position should enable specific features without enabling others"/>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<script type="text/javascript" src="../../../../data/gsubtest-features.js"></script>
|
||||
<script type="text/javascript" src="../../../../data/font-variant-features.js"></script>
|
||||
<link rel="stylesheet" href="../../../../data/font-variant-features.css" type="text/css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content"></div>
|
||||
<script type="text/javascript">
|
||||
document.fonts.ready.then(() => {
|
||||
internals.finishLoading();
|
||||
})
|
||||
internals.disableAutomaticPageFinish();
|
||||
document.getElementById("content").appendChild(createFeatureTestTable(gPropertyData, "font-variant-position", false, false));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,6 +1,6 @@
|
|||
All supported properties and their default values exposed from CSSStyleDeclaration from getComputedStyle:
|
||||
'cssText': ''
|
||||
'length': '203'
|
||||
'length': '210'
|
||||
'parentRule': 'null'
|
||||
'cssFloat': 'none'
|
||||
'WebkitAlignContent': 'normal'
|
||||
|
@ -305,6 +305,20 @@ All supported properties and their default values exposed from CSSStyleDeclarati
|
|||
'font-style': 'normal'
|
||||
'fontVariant': 'normal'
|
||||
'font-variant': 'normal'
|
||||
'fontVariantAlternates': 'normal'
|
||||
'font-variant-alternates': 'normal'
|
||||
'fontVariantCaps': 'normal'
|
||||
'font-variant-caps': 'normal'
|
||||
'fontVariantEastAsian': 'normal'
|
||||
'font-variant-east-asian': 'normal'
|
||||
'fontVariantEmoji': 'normal'
|
||||
'font-variant-emoji': 'normal'
|
||||
'fontVariantLigatures': 'normal'
|
||||
'font-variant-ligatures': 'normal'
|
||||
'fontVariantNumeric': 'normal'
|
||||
'font-variant-numeric': 'normal'
|
||||
'fontVariantPosition': 'normal'
|
||||
'font-variant-position': 'normal'
|
||||
'fontVariationSettings': 'normal'
|
||||
'font-variation-settings': 'normal'
|
||||
'fontWeight': '400'
|
||||
|
|
|
@ -18,191 +18,197 @@ All properties associated with getComputedStyle(document.body):
|
|||
"15": "font-size",
|
||||
"16": "font-style",
|
||||
"17": "font-variant",
|
||||
"18": "font-variation-settings",
|
||||
"19": "font-weight",
|
||||
"20": "font-width",
|
||||
"21": "image-rendering",
|
||||
"22": "letter-spacing",
|
||||
"23": "line-height",
|
||||
"24": "list-style-image",
|
||||
"25": "list-style-position",
|
||||
"26": "list-style-type",
|
||||
"27": "math-depth",
|
||||
"28": "math-shift",
|
||||
"29": "math-style",
|
||||
"30": "pointer-events",
|
||||
"31": "quotes",
|
||||
"32": "stroke",
|
||||
"33": "stroke-dashoffset",
|
||||
"34": "stroke-linecap",
|
||||
"35": "stroke-linejoin",
|
||||
"36": "stroke-miterlimit",
|
||||
"37": "stroke-opacity",
|
||||
"38": "stroke-width",
|
||||
"39": "tab-size",
|
||||
"40": "text-align",
|
||||
"41": "text-anchor",
|
||||
"42": "text-decoration-line",
|
||||
"43": "text-indent",
|
||||
"44": "text-justify",
|
||||
"45": "text-shadow",
|
||||
"46": "text-transform",
|
||||
"47": "visibility",
|
||||
"48": "white-space",
|
||||
"49": "word-break",
|
||||
"50": "word-spacing",
|
||||
"51": "word-wrap",
|
||||
"52": "writing-mode",
|
||||
"53": "align-content",
|
||||
"54": "align-items",
|
||||
"55": "align-self",
|
||||
"56": "animation-delay",
|
||||
"57": "animation-direction",
|
||||
"58": "animation-duration",
|
||||
"59": "animation-fill-mode",
|
||||
"60": "animation-iteration-count",
|
||||
"61": "animation-name",
|
||||
"62": "animation-play-state",
|
||||
"63": "animation-timing-function",
|
||||
"64": "appearance",
|
||||
"65": "aspect-ratio",
|
||||
"66": "backdrop-filter",
|
||||
"67": "background-attachment",
|
||||
"68": "background-clip",
|
||||
"69": "background-color",
|
||||
"70": "background-image",
|
||||
"71": "background-origin",
|
||||
"72": "background-position-x",
|
||||
"73": "background-position-y",
|
||||
"74": "background-repeat",
|
||||
"75": "background-size",
|
||||
"76": "border-bottom-color",
|
||||
"77": "border-bottom-left-radius",
|
||||
"78": "border-bottom-right-radius",
|
||||
"79": "border-bottom-style",
|
||||
"80": "border-bottom-width",
|
||||
"81": "border-left-color",
|
||||
"82": "border-left-style",
|
||||
"83": "border-left-width",
|
||||
"84": "border-right-color",
|
||||
"85": "border-right-style",
|
||||
"86": "border-right-width",
|
||||
"87": "border-top-color",
|
||||
"88": "border-top-left-radius",
|
||||
"89": "border-top-right-radius",
|
||||
"90": "border-top-style",
|
||||
"91": "border-top-width",
|
||||
"92": "bottom",
|
||||
"93": "box-shadow",
|
||||
"94": "box-sizing",
|
||||
"95": "clear",
|
||||
"96": "clip",
|
||||
"97": "clip-path",
|
||||
"98": "column-count",
|
||||
"99": "column-gap",
|
||||
"100": "column-span",
|
||||
"101": "column-width",
|
||||
"102": "content",
|
||||
"103": "content-visibility",
|
||||
"104": "counter-increment",
|
||||
"105": "counter-reset",
|
||||
"106": "counter-set",
|
||||
"107": "cx",
|
||||
"108": "cy",
|
||||
"109": "display",
|
||||
"110": "filter",
|
||||
"111": "flex-basis",
|
||||
"112": "flex-direction",
|
||||
"113": "flex-grow",
|
||||
"114": "flex-shrink",
|
||||
"115": "flex-wrap",
|
||||
"116": "float",
|
||||
"117": "grid-auto-columns",
|
||||
"118": "grid-auto-flow",
|
||||
"119": "grid-auto-rows",
|
||||
"120": "grid-column-end",
|
||||
"121": "grid-column-start",
|
||||
"122": "grid-row-end",
|
||||
"123": "grid-row-start",
|
||||
"124": "grid-template-areas",
|
||||
"125": "grid-template-columns",
|
||||
"126": "grid-template-rows",
|
||||
"127": "height",
|
||||
"128": "inline-size",
|
||||
"129": "inset-block-end",
|
||||
"130": "inset-block-start",
|
||||
"131": "inset-inline-end",
|
||||
"132": "inset-inline-start",
|
||||
"133": "justify-content",
|
||||
"134": "justify-items",
|
||||
"135": "justify-self",
|
||||
"136": "left",
|
||||
"137": "margin-block-end",
|
||||
"138": "margin-block-start",
|
||||
"139": "margin-bottom",
|
||||
"140": "margin-inline-end",
|
||||
"141": "margin-inline-start",
|
||||
"142": "margin-left",
|
||||
"143": "margin-right",
|
||||
"144": "margin-top",
|
||||
"145": "mask",
|
||||
"146": "mask-image",
|
||||
"147": "mask-type",
|
||||
"148": "max-height",
|
||||
"149": "max-inline-size",
|
||||
"150": "max-width",
|
||||
"151": "min-height",
|
||||
"152": "min-inline-size",
|
||||
"153": "min-width",
|
||||
"154": "object-fit",
|
||||
"155": "object-position",
|
||||
"156": "opacity",
|
||||
"157": "order",
|
||||
"158": "outline-color",
|
||||
"159": "outline-offset",
|
||||
"160": "outline-style",
|
||||
"161": "outline-width",
|
||||
"162": "overflow-x",
|
||||
"163": "overflow-y",
|
||||
"164": "padding-block-end",
|
||||
"165": "padding-block-start",
|
||||
"166": "padding-bottom",
|
||||
"167": "padding-inline-end",
|
||||
"168": "padding-inline-start",
|
||||
"169": "padding-left",
|
||||
"170": "padding-right",
|
||||
"171": "padding-top",
|
||||
"172": "position",
|
||||
"173": "r",
|
||||
"174": "right",
|
||||
"175": "rotate",
|
||||
"176": "row-gap",
|
||||
"177": "rx",
|
||||
"178": "ry",
|
||||
"179": "scrollbar-gutter",
|
||||
"180": "scrollbar-width",
|
||||
"181": "stop-color",
|
||||
"182": "stop-opacity",
|
||||
"183": "table-layout",
|
||||
"184": "text-decoration-color",
|
||||
"185": "text-decoration-style",
|
||||
"186": "text-decoration-thickness",
|
||||
"187": "text-overflow",
|
||||
"188": "top",
|
||||
"189": "transform",
|
||||
"190": "transform-box",
|
||||
"191": "transform-origin",
|
||||
"192": "transition-delay",
|
||||
"193": "transition-duration",
|
||||
"194": "transition-property",
|
||||
"195": "transition-timing-function",
|
||||
"196": "unicode-bidi",
|
||||
"197": "user-select",
|
||||
"198": "vertical-align",
|
||||
"199": "width",
|
||||
"200": "x",
|
||||
"201": "y",
|
||||
"202": "z-index"
|
||||
"18": "font-variant-alternates",
|
||||
"19": "font-variant-caps",
|
||||
"20": "font-variant-east-asian",
|
||||
"21": "font-variant-emoji",
|
||||
"22": "font-variant-ligatures",
|
||||
"23": "font-variant-numeric",
|
||||
"24": "font-variant-position",
|
||||
"25": "font-variation-settings",
|
||||
"26": "font-weight",
|
||||
"27": "font-width",
|
||||
"28": "image-rendering",
|
||||
"29": "letter-spacing",
|
||||
"30": "line-height",
|
||||
"31": "list-style-image",
|
||||
"32": "list-style-position",
|
||||
"33": "list-style-type",
|
||||
"34": "math-depth",
|
||||
"35": "math-shift",
|
||||
"36": "math-style",
|
||||
"37": "pointer-events",
|
||||
"38": "quotes",
|
||||
"39": "stroke",
|
||||
"40": "stroke-linecap",
|
||||
"41": "stroke-linejoin",
|
||||
"42": "stroke-miterlimit",
|
||||
"43": "stroke-opacity",
|
||||
"44": "stroke-width",
|
||||
"45": "tab-size",
|
||||
"46": "text-align",
|
||||
"47": "text-anchor",
|
||||
"48": "text-decoration-line",
|
||||
"49": "text-indent",
|
||||
"50": "text-justify",
|
||||
"51": "text-shadow",
|
||||
"52": "text-transform",
|
||||
"53": "visibility",
|
||||
"54": "white-space",
|
||||
"55": "word-break",
|
||||
"56": "word-spacing",
|
||||
"57": "word-wrap",
|
||||
"58": "writing-mode",
|
||||
"59": "align-content",
|
||||
"60": "align-items",
|
||||
"61": "align-self",
|
||||
"62": "animation-delay",
|
||||
"63": "animation-direction",
|
||||
"64": "animation-duration",
|
||||
"65": "animation-fill-mode",
|
||||
"66": "animation-iteration-count",
|
||||
"67": "animation-name",
|
||||
"68": "animation-play-state",
|
||||
"69": "animation-timing-function",
|
||||
"70": "appearance",
|
||||
"71": "aspect-ratio",
|
||||
"72": "backdrop-filter",
|
||||
"73": "background-attachment",
|
||||
"74": "background-clip",
|
||||
"75": "background-color",
|
||||
"76": "background-image",
|
||||
"77": "background-origin",
|
||||
"78": "background-position-x",
|
||||
"79": "background-position-y",
|
||||
"80": "background-repeat",
|
||||
"81": "background-size",
|
||||
"82": "border-bottom-color",
|
||||
"83": "border-bottom-left-radius",
|
||||
"84": "border-bottom-right-radius",
|
||||
"85": "border-bottom-style",
|
||||
"86": "border-bottom-width",
|
||||
"87": "border-left-color",
|
||||
"88": "border-left-style",
|
||||
"89": "border-left-width",
|
||||
"90": "border-right-color",
|
||||
"91": "border-right-style",
|
||||
"92": "border-right-width",
|
||||
"93": "border-top-color",
|
||||
"94": "border-top-left-radius",
|
||||
"95": "border-top-right-radius",
|
||||
"96": "border-top-style",
|
||||
"97": "border-top-width",
|
||||
"98": "bottom",
|
||||
"99": "box-shadow",
|
||||
"100": "box-sizing",
|
||||
"101": "clear",
|
||||
"102": "clip",
|
||||
"103": "clip-path",
|
||||
"104": "column-count",
|
||||
"105": "column-gap",
|
||||
"106": "column-span",
|
||||
"107": "column-width",
|
||||
"108": "content",
|
||||
"109": "content-visibility",
|
||||
"110": "counter-increment",
|
||||
"111": "counter-reset",
|
||||
"112": "counter-set",
|
||||
"113": "cx",
|
||||
"114": "cy",
|
||||
"115": "display",
|
||||
"116": "filter",
|
||||
"117": "flex-basis",
|
||||
"118": "flex-direction",
|
||||
"119": "flex-grow",
|
||||
"120": "flex-shrink",
|
||||
"121": "flex-wrap",
|
||||
"122": "float",
|
||||
"123": "grid-auto-columns",
|
||||
"124": "grid-auto-flow",
|
||||
"125": "grid-auto-rows",
|
||||
"126": "grid-column-end",
|
||||
"127": "grid-column-start",
|
||||
"128": "grid-row-end",
|
||||
"129": "grid-row-start",
|
||||
"130": "grid-template-areas",
|
||||
"131": "grid-template-columns",
|
||||
"132": "grid-template-rows",
|
||||
"133": "height",
|
||||
"134": "inline-size",
|
||||
"135": "inset-block-end",
|
||||
"136": "inset-block-start",
|
||||
"137": "inset-inline-end",
|
||||
"138": "inset-inline-start",
|
||||
"139": "justify-content",
|
||||
"140": "justify-items",
|
||||
"141": "justify-self",
|
||||
"142": "left",
|
||||
"143": "margin-block-end",
|
||||
"144": "margin-block-start",
|
||||
"145": "margin-bottom",
|
||||
"146": "margin-inline-end",
|
||||
"147": "margin-inline-start",
|
||||
"148": "margin-left",
|
||||
"149": "margin-right",
|
||||
"150": "margin-top",
|
||||
"151": "mask",
|
||||
"152": "mask-image",
|
||||
"153": "mask-type",
|
||||
"154": "max-height",
|
||||
"155": "max-inline-size",
|
||||
"156": "max-width",
|
||||
"157": "min-height",
|
||||
"158": "min-inline-size",
|
||||
"159": "min-width",
|
||||
"160": "object-fit",
|
||||
"161": "object-position",
|
||||
"162": "opacity",
|
||||
"163": "order",
|
||||
"164": "outline-color",
|
||||
"165": "outline-offset",
|
||||
"166": "outline-style",
|
||||
"167": "outline-width",
|
||||
"168": "overflow-x",
|
||||
"169": "overflow-y",
|
||||
"170": "padding-block-end",
|
||||
"171": "padding-block-start",
|
||||
"172": "padding-bottom",
|
||||
"173": "padding-inline-end",
|
||||
"174": "padding-inline-start",
|
||||
"175": "padding-left",
|
||||
"176": "padding-right",
|
||||
"177": "padding-top",
|
||||
"178": "position",
|
||||
"179": "r",
|
||||
"180": "right",
|
||||
"181": "rotate",
|
||||
"182": "row-gap",
|
||||
"183": "rx",
|
||||
"184": "ry",
|
||||
"185": "scrollbar-gutter",
|
||||
"186": "scrollbar-width",
|
||||
"187": "stop-color",
|
||||
"188": "stop-opacity",
|
||||
"189": "table-layout",
|
||||
"190": "text-decoration-color",
|
||||
"191": "text-decoration-style",
|
||||
"192": "text-decoration-thickness",
|
||||
"193": "text-overflow",
|
||||
"194": "top",
|
||||
"195": "transform",
|
||||
"196": "transform-box",
|
||||
"197": "transform-origin",
|
||||
"198": "transition-delay",
|
||||
"199": "transition-duration",
|
||||
"200": "transition-property",
|
||||
"201": "transition-timing-function",
|
||||
"202": "unicode-bidi",
|
||||
"203": "user-select",
|
||||
"204": "vertical-align",
|
||||
"205": "width",
|
||||
"206": "x",
|
||||
"207": "y",
|
||||
"208": "z-index"
|
||||
}
|
||||
All properties associated with document.body.style by default:
|
||||
{}
|
||||
|
|
|
@ -16,6 +16,13 @@ font-language-override: normal
|
|||
font-size: 16px
|
||||
font-style: normal
|
||||
font-variant: normal
|
||||
font-variant-alternates: normal
|
||||
font-variant-caps: normal
|
||||
font-variant-east-asian: normal
|
||||
font-variant-emoji: normal
|
||||
font-variant-ligatures: normal
|
||||
font-variant-numeric: normal
|
||||
font-variant-position: normal
|
||||
font-variation-settings: normal
|
||||
font-weight: 400
|
||||
font-width: normal
|
||||
|
@ -125,7 +132,7 @@ grid-row-start: auto
|
|||
grid-template-areas: none
|
||||
grid-template-columns: auto
|
||||
grid-template-rows: auto
|
||||
height: 2159px
|
||||
height: 2261px
|
||||
inline-size: auto
|
||||
inset-block-end: auto
|
||||
inset-block-start: auto
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <LibGfx/ImageFormats/PNGWriter.h>
|
||||
#include <LibURL/URL.h>
|
||||
#include <LibWeb/HTML/SelectedFile.h>
|
||||
#include <LibWeb/HTML/Window.h>
|
||||
#include <UI/Headless/Application.h>
|
||||
#include <UI/Headless/HeadlessWebView.h>
|
||||
#include <UI/Headless/Test.h>
|
||||
|
@ -101,6 +102,7 @@ static ErrorOr<void> collect_ref_tests(Vector<Test>& tests, StringView path, Str
|
|||
static void clear_test_callbacks(HeadlessWebView& view)
|
||||
{
|
||||
view.on_load_finish = {};
|
||||
view.on_loading_page_and_fonts_finish = {};
|
||||
view.on_text_test_finish = {};
|
||||
view.on_web_content_crashed = {};
|
||||
}
|
||||
|
@ -239,6 +241,7 @@ static void run_ref_test(HeadlessWebView& view, Test& test, URL::URL const& url,
|
|||
{
|
||||
auto timer = Core::Timer::create_single_shot(timeout_in_milliseconds, [&view, &test]() {
|
||||
view.on_load_finish = {};
|
||||
view.on_loading_page_and_fonts_finish = {};
|
||||
view.on_text_test_finish = {};
|
||||
|
||||
view.on_test_complete({ test, TestResult::Timeout });
|
||||
|
@ -287,20 +290,63 @@ static void run_ref_test(HeadlessWebView& view, Test& test, URL::URL const& url,
|
|||
view.on_test_complete({ test, TestResult::Crashed });
|
||||
};
|
||||
|
||||
view.on_load_finish = [&view, &test, on_test_complete = move(on_test_complete)](auto const&) {
|
||||
view.on_load_finish = [&view, &test, &on_test_complete](auto const&) {
|
||||
dbgln("on loading page: page={}, url={}", test.did_load_page, view.url().serialize_path());
|
||||
test.did_load_page = true;
|
||||
if (!test.did_load_fonts)
|
||||
return;
|
||||
//dbgln("DONE on loading page: fonts={}, {}", test.did_load_fonts, view.url());
|
||||
test.did_load_page = true;
|
||||
if (test.actual_screenshot) {
|
||||
view.take_screenshot()->when_resolved([&test, on_test_complete = move(on_test_complete)](RefPtr<Gfx::Bitmap> screenshot) {
|
||||
//dbgln("Take expectation screenshot <- this happens too early");
|
||||
view.take_screenshot()->when_resolved([&test, &on_test_complete](RefPtr<Gfx::Bitmap> screenshot) {
|
||||
test.expectation_screenshot = move(screenshot);
|
||||
test.did_load_fonts = false;
|
||||
test.did_load_page = false;
|
||||
on_test_complete();
|
||||
});
|
||||
} else {
|
||||
//dbgln("\nTake actual screenshot");
|
||||
view.take_screenshot()->when_resolved([&view, &test](RefPtr<Gfx::Bitmap> screenshot) {
|
||||
test.actual_screenshot = move(screenshot);
|
||||
test.did_load_fonts = false;
|
||||
test.did_load_page = false;
|
||||
test.loading_reference_page = true;
|
||||
dbgln("load-reference-page");
|
||||
view.debug_request("load-reference-page");
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// FIXME: rename to on_fonts_ready
|
||||
view.on_loading_page_and_fonts_finish = [&view, &test, &on_test_complete](auto const&) {
|
||||
dbgln("on fonts finish: load={}, url={}", test.did_load_fonts, view.url().serialize_path());
|
||||
// This callback will be called multiple times, one for normal page load and one for the reference page load.
|
||||
// We only want to take the screenshot once the reference page has loaded its fonts
|
||||
if (test.loading_reference_page && !view.url().serialize_path().ends_with_bytes("-ref.html"sv))
|
||||
return;
|
||||
if (test.did_load_fonts)
|
||||
return;
|
||||
test.did_load_fonts = true;
|
||||
if (!test.did_load_page)
|
||||
return;
|
||||
if (test.actual_screenshot) {
|
||||
view.take_screenshot()->when_resolved([&test, &on_test_complete](RefPtr<Gfx::Bitmap> screenshot) {
|
||||
test.expectation_screenshot = move(screenshot);
|
||||
on_test_complete();
|
||||
});
|
||||
} else {
|
||||
dbgln("\nTake actual screenshot");
|
||||
view.take_screenshot()->when_resolved([&view, &test](RefPtr<Gfx::Bitmap> screenshot) {
|
||||
test.actual_screenshot = move(screenshot);
|
||||
test.did_load_fonts = false;
|
||||
test.did_load_page = false;
|
||||
test.loading_reference_page = true;
|
||||
dbgln("load-reference-page");
|
||||
view.debug_request("load-reference-page");
|
||||
});
|
||||
}
|
||||
};
|
||||
view.on_text_test_finish = [&](auto const&) {
|
||||
dbgln("Unexpected text test finished during ref test for {}", url);
|
||||
};
|
||||
|
|
|
@ -66,9 +66,13 @@ struct Test {
|
|||
String text {};
|
||||
bool did_finish_test { false };
|
||||
bool did_finish_loading { false };
|
||||
|
||||
bool did_load_page { false };
|
||||
bool did_load_fonts { false };
|
||||
bool loading_reference_page { false };
|
||||
RefPtr<Gfx::Bitmap> actual_screenshot {};
|
||||
RefPtr<Gfx::Bitmap> expectation_screenshot {};
|
||||
|
||||
bool is_ref() const { return mode == TestMode::Ref; };
|
||||
};
|
||||
|
||||
struct TestCompletion {
|
||||
|
|
Loading…
Reference in a new issue