diff --git a/Libraries/LibGfx/CMakeLists.txt b/Libraries/LibGfx/CMakeLists.txt index e116e137d7c..794271d0145 100644 --- a/Libraries/LibGfx/CMakeLists.txt +++ b/Libraries/LibGfx/CMakeLists.txt @@ -14,6 +14,7 @@ set(SOURCES Font/Font.cpp Font/FontData.cpp Font/FontDatabase.cpp + Font/FontSupport.cpp Font/PathFontProvider.cpp Font/Typeface.cpp Font/TypefaceSkia.cpp diff --git a/Libraries/LibGfx/Font/FontSupport.cpp b/Libraries/LibGfx/Font/FontSupport.cpp new file mode 100644 index 00000000000..f6113dcd10b --- /dev/null +++ b/Libraries/LibGfx/Font/FontSupport.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2025, Sam Atkins + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include + +#include + +namespace Gfx { + +bool font_format_is_supported(FontFormat const format) +{ + // FIXME: Determine these automatically. + switch (format) { + case FontFormat::EmbeddedOpenType: + return false; + case FontFormat::OpenType: + return true; + case FontFormat::SVG: + return false; + case FontFormat::TrueType: + return true; + case FontFormat::TrueTypeCollection: + return true; + case FontFormat::WOFF: + return true; + case FontFormat::WOFF2: + return true; + } + + return false; +} + +bool font_tech_is_supported(FontTech const font_tech) +{ + // https://drafts.csswg.org/css-fonts-4/#font-tech-definitions + // FIXME: Determine these automatically. + switch (font_tech) { + case FontTech::FeaturesOpentype: + // GSUB and GPOS, supported by HarfBuzz + return true; + case FontTech::FeaturesAat: + // morx and kerx, supported by HarfBuzz + return true; + case FontTech::FeaturesGraphite: + // Silf, Glat , Gloc , Feat and Sill. HarfBuzz may or may not be built with support for it. +#if HB_HAS_GRAPHITE + return true; +#else + return false; +#endif + case FontTech::Variations: + // avar, cvar, fvar, gvar, HVAR, MVAR, STAT, and VVAR, supported by HarfBuzz + return true; + case FontTech::ColorColrv0: + case FontTech::ColorColrv1: + // COLR, supported by HarfBuzz + return true; + case FontTech::ColorSvg: + // SVG, supported by HarfBuzz + return true; + case FontTech::ColorSbix: + // sbix, supported by HarfBuzz + return true; + case FontTech::ColorCbdt: + // CBDT, supported by HarfBuzz + return true; + case FontTech::Palettes: + // CPAL, supported by HarfBuzz + return true; + case FontTech::Incremental: + // Incremental Font Transfer: https://w3c.github.io/IFT/Overview.html + return false; + // https://drafts.csswg.org/css-fonts-5/#font-tech-definitions + case FontTech::Avar2: + // avar version 2, supported by HarfBuzz + return true; + } + return false; +} + +} diff --git a/Libraries/LibGfx/Font/FontSupport.h b/Libraries/LibGfx/Font/FontSupport.h new file mode 100644 index 00000000000..e9b08b134da --- /dev/null +++ b/Libraries/LibGfx/Font/FontSupport.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025, Sam Atkins + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace Gfx { + +enum class FontFormat : u8 { + EmbeddedOpenType, + OpenType, + SVG, + TrueType, + TrueTypeCollection, + WOFF, + WOFF2, +}; + +enum class FontTech : u8 { + Avar2, + ColorCbdt, + ColorColrv0, + ColorColrv1, + ColorSbix, + ColorSvg, + FeaturesAat, + FeaturesGraphite, + FeaturesOpentype, + Incremental, + Palettes, + Variations, +}; + +bool font_format_is_supported(FontFormat); +bool font_tech_is_supported(FontTech); + +} diff --git a/Libraries/LibWeb/CSS/FontFace.cpp b/Libraries/LibWeb/CSS/FontFace.cpp index 510aab3a76d..914df675291 100644 --- a/Libraries/LibWeb/CSS/FontFace.cpp +++ b/Libraries/LibWeb/CSS/FontFace.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -516,54 +517,52 @@ GC::Ref FontFace::load() bool font_format_is_supported(FlyString const& name) { // https://drafts.csswg.org/css-fonts-4/#font-format-definitions - // FIXME: Determine this automatically somehow? if (name.equals_ignoring_ascii_case("collection"sv)) - return false; + return Gfx::font_format_is_supported(Gfx::FontFormat::TrueTypeCollection); if (name.equals_ignoring_ascii_case("embedded-opentype"sv)) - return false; + return Gfx::font_format_is_supported(Gfx::FontFormat::EmbeddedOpenType); if (name.equals_ignoring_ascii_case("opentype"sv)) - return true; + return Gfx::font_format_is_supported(Gfx::FontFormat::OpenType); if (name.equals_ignoring_ascii_case("svg"sv)) - return false; + return Gfx::font_format_is_supported(Gfx::FontFormat::SVG); if (name.equals_ignoring_ascii_case("truetype"sv)) - return true; + return Gfx::font_format_is_supported(Gfx::FontFormat::TrueType); if (name.equals_ignoring_ascii_case("woff"sv)) - return true; + return Gfx::font_format_is_supported(Gfx::FontFormat::WOFF); if (name.equals_ignoring_ascii_case("woff2"sv)) - return true; + return Gfx::font_format_is_supported(Gfx::FontFormat::WOFF2); return false; } bool font_tech_is_supported(FontTech font_tech) { // https://drafts.csswg.org/css-fonts-4/#font-tech-definitions - // FIXME: Determine this automatically somehow? switch (font_tech) { case FontTech::FeaturesOpentype: - return true; + return Gfx::font_tech_is_supported(Gfx::FontTech::FeaturesOpentype); case FontTech::FeaturesAat: - return false; + return Gfx::font_tech_is_supported(Gfx::FontTech::FeaturesAat); case FontTech::FeaturesGraphite: - return false; + return Gfx::font_tech_is_supported(Gfx::FontTech::FeaturesGraphite); case FontTech::Variations: - return true; + return Gfx::font_tech_is_supported(Gfx::FontTech::Variations); case FontTech::ColorColrv0: - return true; + return Gfx::font_tech_is_supported(Gfx::FontTech::ColorColrv0); case FontTech::ColorColrv1: - return true; + return Gfx::font_tech_is_supported(Gfx::FontTech::ColorColrv1); case FontTech::ColorSvg: - return false; + return Gfx::font_tech_is_supported(Gfx::FontTech::ColorSvg); case FontTech::ColorSbix: - return false; + return Gfx::font_tech_is_supported(Gfx::FontTech::ColorSbix); case FontTech::ColorCbdt: - return false; + return Gfx::font_tech_is_supported(Gfx::FontTech::ColorCbdt); case FontTech::Palettes: - return false; + return Gfx::font_tech_is_supported(Gfx::FontTech::Palettes); case FontTech::Incremental: - return false; + return Gfx::font_tech_is_supported(Gfx::FontTech::Incremental); // https://drafts.csswg.org/css-fonts-5/#font-tech-definitions case FontTech::Avar2: - return false; + return Gfx::font_tech_is_supported(Gfx::FontTech::Avar2); } return false; } diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-fonts/parsing/font-face-src-format.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-fonts/parsing/font-face-src-format.txt index 3ac3c5e766d..1ceb38a39ca 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/css/css-fonts/parsing/font-face-src-format.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-fonts/parsing/font-face-src-format.txt @@ -2,21 +2,20 @@ Harness status: OK Found 35 tests -33 Pass -2 Fail +35 Pass Pass Check that src: url("foo.ttf") is valid Pass Check that src: url("foo.ttf"), url("bar.ttf") is valid Pass Check that src: url("foo.ttf") format() is invalid Pass Check that src: url("foo.ttf") dummy() is invalid Pass Check that src: url("foo.ttf") format("woff") dummy() is invalid Pass Check that src: url("foo.ttf") dummy() format("woff") is invalid -Fail Check that src: url("foo.ttf") format("collection") is valid +Pass Check that src: url("foo.ttf") format("collection") is valid Pass Check that src: url("foo.ttf") format("opentype") is valid Pass Check that src: url("foo.ttf") format("truetype") is valid Pass Check that src: url("foo.ttf") format("woff") is valid Pass Check that src: url("foo.ttf") format("woff2") is valid Pass Check that src: url("foo.ttf") format("opentype", "truetype") is invalid -Fail Check that src: url("foo.ttf") format(collection) is valid +Pass Check that src: url("foo.ttf") format(collection) is valid Pass Check that src: url("foo.ttf") format(opentype) is valid Pass Check that src: url("foo.ttf") format(truetype) is valid Pass Check that src: url("foo.ttf") format(woff) is valid diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-fonts/parsing/font-face-src-tech.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-fonts/parsing/font-face-src-tech.txt index ac27aa3efe5..815dd74754b 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/css/css-fonts/parsing/font-face-src-tech.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-fonts/parsing/font-face-src-tech.txt @@ -2,22 +2,21 @@ Harness status: OK Found 39 tests -34 Pass -5 Fail +39 Pass Pass Check that src: url("foo.ttf") is valid Pass Check that src: url("foo.ttf") tech() is invalid Pass Check that src: url("foo.ttf") tech(features-opentype) is valid -Fail Check that src: url("foo.ttf") tech(features-aat) is valid +Pass Check that src: url("foo.ttf") tech(features-aat) is valid Pass Check that src: url("foo.ttf") tech(color-COLRv0) is valid Pass Check that src: url("foo.ttf") tech(color-COLRv1) is valid -Fail Check that src: url("foo.ttf") tech(color-sbix) is valid -Fail Check that src: url("foo.ttf") tech(color-CBDT) is valid +Pass Check that src: url("foo.ttf") tech(color-sbix) is valid +Pass Check that src: url("foo.ttf") tech(color-CBDT) is valid Pass Check that src: url("foo.ttf") tech(variations) is valid -Fail Check that src: url("foo.ttf") tech(palettes) is valid +Pass Check that src: url("foo.ttf") tech(palettes) is valid Pass Check that src: url("foo.ttf") tech("features-opentype") is invalid Pass Check that src: url("foo.ttf") tech("color-COLRv0") is invalid Pass Check that src: url("foo.ttf") tech("variations") is invalid -Fail Check that src: url("foo.ttf") tech(features-opentype, color-COLRv0, variations, palettes) is valid +Pass Check that src: url("foo.ttf") tech(features-opentype, color-COLRv0, variations, palettes) is valid Pass Check that src: url("foo.ttf") tech(features-opentype color-COLRv0 variations palettes) is invalid Pass Check that src: url("foo.ttf") tech(feature-opentype) is invalid Pass Check that src: url("foo.ttf") tech(feature-aat) is invalid