diff --git a/.rive_head b/.rive_head index 9e946c4e..3a3da295 100644 --- a/.rive_head +++ b/.rive_head @@ -1 +1 @@ -fb8ecf3552aeece0b1d242804580a016b6297ad4 +7986d64d8371531716ea3f038dcbec5da187e6cd diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index c74f34f3..a48a793b 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -4,15 +4,18 @@ "name": "Mac", "includePath": [ "${workspaceFolder}/**", - "${workspaceFolder}/dev/test/include", "${workspaceFolder}/include" ], - "defines": [], + "defines": [ + "WITH_RIVE_TEXT", + "WITH_RIVE_AUDIO", + "WITH_RIVE_LAYOUT" + ], "macFrameworkPath": [], - "compilerPath": "/usr/local/bin/arm-none-eabi-gcc", - "cStandard": "gnu11", - "cppStandard": "gnu++14", - "intelliSenseMode": "clang-x64" + "compilerPath": "/usr/bin/clang", + "cStandard": "c11", + "cppStandard": "c++17", + "intelliSenseMode": "clang-arm64" } ], "version": 4 diff --git a/dependencies/premake5_harfbuzz.lua b/dependencies/premake5_harfbuzz.lua index e914b1e5..1a95bc8e 100644 --- a/dependencies/premake5_harfbuzz.lua +++ b/dependencies/premake5_harfbuzz.lua @@ -221,6 +221,8 @@ do harfbuzz .. '/src/hb-paint.cc', harfbuzz .. '/src/hb-paint-extents.cc', harfbuzz .. '/src/hb-outline.cc', + harfbuzz .. '/src/hb-style.h', + harfbuzz .. '/src/hb-style.cc', }) warnings('Off') @@ -235,7 +237,6 @@ do 'HB_NO_BITMAP', 'HB_NO_BUFFER_SERIALIZE', 'HB_NO_SETLOCALE', - 'HB_NO_STYLE', 'HB_NO_VERTICAL', 'HB_NO_LAYOUT_COLLECT_GLYPHS', 'HB_NO_LAYOUT_RARELY_USED', diff --git a/dependencies/premake5_harfbuzz_v2.lua b/dependencies/premake5_harfbuzz_v2.lua index 361302f3..f3880848 100644 --- a/dependencies/premake5_harfbuzz_v2.lua +++ b/dependencies/premake5_harfbuzz_v2.lua @@ -220,6 +220,8 @@ do harfbuzz .. '/src/hb-paint.cc', harfbuzz .. '/src/hb-paint-extents.cc', harfbuzz .. '/src/hb-outline.cc', + harfbuzz .. '/src/hb-style.h', + harfbuzz .. '/src/hb-style.cc', }) warnings('Off') @@ -237,7 +239,6 @@ do 'HB_NO_BUFFER_VERIFY', 'HB_NO_BUFFER_MESSAGE', 'HB_NO_SETLOCALE', - 'HB_NO_STYLE', 'HB_NO_VERTICAL', 'HB_NO_LAYOUT_COLLECT_GLYPHS', 'HB_NO_LAYOUT_RARELY_USED', diff --git a/include/rive/text/font_hb.hpp b/include/rive/text/font_hb.hpp index 12ef784e..a63d98b5 100644 --- a/include/rive/text/font_hb.hpp +++ b/include/rive/text/font_hb.hpp @@ -21,6 +21,8 @@ public: uint16_t getAxisCount() const override; float getAxisValue(uint32_t axisTag) const override; uint32_t getFeatureValue(uint32_t featureTag) const override; + uint16_t getWeight() const override; + bool isItalic() const override; rive::RawPath getPath(rive::GlyphID) const override; rive::SimpleArray onShapeText( @@ -39,7 +41,7 @@ public: bool useSystemShaper, uint16_t weight, uint8_t width); - + static float GetStyle(hb_font_t*, uint32_t); hb_font_t* font() const { return m_font; } private: diff --git a/include/rive/text_engine.hpp b/include/rive/text_engine.hpp index f4215d34..532327ca 100644 --- a/include/rive/text_engine.hpp +++ b/include/rive/text_engine.hpp @@ -157,6 +157,12 @@ public: // will be used. Otherwise the default value for the axis will be returned. virtual float getAxisValue(uint32_t axisTag) const = 0; + // Returns the current font value as a numeric value [1, 1000] + virtual uint16_t getWeight() const = 0; + + // Whether this font is italic or not. + virtual bool isItalic() const = 0; + // Font feature. struct Feature { @@ -201,11 +207,12 @@ public: // return a font that can draw (at least some of) them. If no font is // available just return nullptr. - using FallbackProc = - rive::rcp (*)(const rive::Unichar, - const uint32_t fallbackIndex); + using FallbackProc = rive::rcp (*)(const rive::Unichar missing, + const uint32_t fallbackIndex, + const rive::Font*); static FallbackProc gFallbackProc; static bool gFallbackProcEnabled; + static constexpr unsigned kRegularWeight = 400; protected: Font(const LineMetrics& lm) : m_lineMetrics(lm) {} diff --git a/skia/dependencies/get_skia.sh b/skia/dependencies/get_skia.sh index f479ef92..6d061c56 100755 --- a/skia/dependencies/get_skia.sh +++ b/skia/dependencies/get_skia.sh @@ -8,35 +8,35 @@ set -e # https://skia.org/user/build # GLFW requires CMake getSkia() { - SKIA_REPO=$1 - SKIA_STABLE_BRANCH=$2 - FOLDER_NAME=$3 - # ----------------------------- - # Get & Build Skia - # ----------------------------- - if [ ! -d $FOLDER_NAME ]; then - echo "Cloning Skia into $FOLDER_NAME." - git clone $SKIA_REPO $FOLDER_NAME - else - echo "Already have Skia in $FOLDER_NAME, update it." - cd $FOLDER_NAME && git fetch && git pull - cd .. - fi - - cd $FOLDER_NAME - - # switch to a stable branch - echo "Checking out stable branch $SKIA_STABLE_BRANCH" - git checkout $SKIA_STABLE_BRANCH - python tools/git-sync-deps + SKIA_REPO=$1 + SKIA_STABLE_BRANCH=$2 + FOLDER_NAME=$3 + # ----------------------------- + # Get & Build Skia + # ----------------------------- + if [ ! -d $FOLDER_NAME ]; then + echo "Cloning Skia into $FOLDER_NAME." + git clone $SKIA_REPO $FOLDER_NAME + else + echo "Already have Skia in $FOLDER_NAME, update it." + cd $FOLDER_NAME && git fetch && git pull cd .. + fi + + cd $FOLDER_NAME + + # switch to a stable branch + echo "Checking out stable branch $SKIA_STABLE_BRANCH" + git checkout $SKIA_STABLE_BRANCH + python3 tools/git-sync-deps + cd .. } if [ $# -eq 0 ]; then - # No arguments supplied; checkout the default skia repos. - getSkia https://github.com/rive-app/skia rive skia_rive_optimized - getSkia https://github.com/google/skia chrome/m99 skia + # No arguments supplied; checkout the default skia repos. + getSkia https://github.com/rive-app/skia rive skia_rive_optimized + getSkia https://github.com/google/skia chrome/m99 skia else - # The caller specified which skia repo to checkout. - getSkia $@ + # The caller specified which skia repo to checkout. + getSkia $@ fi diff --git a/src/text/font_hb.cpp b/src/text/font_hb.cpp index 766532c9..496cd37c 100644 --- a/src/text/font_hb.cpp +++ b/src/text/font_hb.cpp @@ -58,7 +58,11 @@ rive::rcp HBFont::FromSystem(void* systemFont, } #endif -/////////////// +float HBFont::GetStyle(hb_font_t* font, uint32_t styleTag) +{ + return hb_style_get_value(font, (hb_style_tag_t)styleTag); +} +////////////// constexpr int kStdScale = 2048; constexpr float gInvScale = 1.0f / kStdScale; @@ -321,6 +325,20 @@ uint32_t HBFont::getFeatureValue(uint32_t featureTag) const return (uint32_t)-1; } +uint16_t HBFont::getWeight() const +{ + uint32_t tag = HB_TAG('w', 'g', 'h', 't'); + float res = HBFont::GetStyle(m_font, tag); + return static_cast(res); +} + +bool HBFont::isItalic() const +{ + uint32_t tag = HB_TAG('i', 't', 'a', 'l'); + float res = HBFont::GetStyle(m_font, tag); + return res != 0.0; +} + rive::rcp HBFont::withOptions( rive::Span coords, rive::Span features) const @@ -514,7 +532,7 @@ void HBFont::shapeFallbackRun(rive::SimpleArrayBuilder& gruns, // font-fallback size_t index = iter - gr.glyphs.begin(); rive::Unichar missing = text[gr.textIndices[index]]; - auto fallback = HBFont::gFallbackProc(missing, fallbackIndex); + auto fallback = HBFont::gFallbackProc(missing, fallbackIndex, this); if (fallback && fallback.get() != this) { perform_fallback(fallback, @@ -694,9 +712,8 @@ rive::SimpleArray HBFont::onShapeText( // font-fallback size_t index = iter - gr.glyphs.begin(); rive::Unichar missing = text[gr.textIndices[index]]; - // todo: consider sending more chars if that helps choose a - // font - auto fallback = gFallbackProc(missing, 0); + // todo: consider sending more chars if that helps choose a font + auto fallback = gFallbackProc(missing, 0, this); if (fallback) { perform_fallback(fallback, gruns, text.data(), gr, tr, 1); diff --git a/tests/unit_tests/assets/fonts/AdventPro-VariableFont_wdth,wght.ttf b/tests/unit_tests/assets/fonts/AdventPro-VariableFont_wdth,wght.ttf new file mode 100644 index 00000000..cbc3a336 Binary files /dev/null and b/tests/unit_tests/assets/fonts/AdventPro-VariableFont_wdth,wght.ttf differ diff --git a/tests/unit_tests/assets/fonts/Inter_18pt-Regular.ttf b/tests/unit_tests/assets/fonts/Inter_18pt-Regular.ttf new file mode 100644 index 00000000..ce097c82 Binary files /dev/null and b/tests/unit_tests/assets/fonts/Inter_18pt-Regular.ttf differ diff --git a/tests/unit_tests/assets/fonts/Inter_28pt-Bold.ttf b/tests/unit_tests/assets/fonts/Inter_28pt-Bold.ttf new file mode 100644 index 00000000..d17828b2 Binary files /dev/null and b/tests/unit_tests/assets/fonts/Inter_28pt-Bold.ttf differ diff --git a/tests/unit_tests/assets/fonts/OpenSans-ExtraBoldItalic.ttf b/tests/unit_tests/assets/fonts/OpenSans-ExtraBoldItalic.ttf new file mode 100644 index 00000000..75789b42 Binary files /dev/null and b/tests/unit_tests/assets/fonts/OpenSans-ExtraBoldItalic.ttf differ diff --git a/tests/unit_tests/assets/fonts/OpenSans-Italic.ttf b/tests/unit_tests/assets/fonts/OpenSans-Italic.ttf new file mode 100644 index 00000000..29ff6938 Binary files /dev/null and b/tests/unit_tests/assets/fonts/OpenSans-Italic.ttf differ diff --git a/tests/unit_tests/premake5.lua b/tests/unit_tests/premake5.lua index c180fe27..69879541 100644 --- a/tests/unit_tests/premake5.lua +++ b/tests/unit_tests/premake5.lua @@ -30,6 +30,7 @@ do '../../decoders/include', '../../renderer/include', '../../renderer/src', + harfbuzz .. '/src', miniaudio, yoga, }) diff --git a/tests/unit_tests/runtime/font_test.cpp b/tests/unit_tests/runtime/font_test.cpp index ca697d75..1a55252a 100644 --- a/tests/unit_tests/runtime/font_test.cpp +++ b/tests/unit_tests/runtime/font_test.cpp @@ -3,6 +3,8 @@ #include "rive/text_engine.hpp" #include "rive/text/font_hb.hpp" #include "rive/text/utf.hpp" +#include "hb.h" +#include "hb-ot.h" #include using namespace rive; @@ -39,7 +41,8 @@ static rcp loadFont(const char* filename) static std::vector> fallbackFonts; static rive::rcp pickFallbackFont(const rive::Unichar missing, - const uint32_t fallbackIndex) + const uint32_t fallbackIndex, + const rive::Font*) { if (fallbackIndex > 0) { @@ -57,7 +60,37 @@ static rive::rcp pickFallbackFont(const rive::Unichar missing, return nullptr; } -TEST_CASE("fallback glyphs are found", "[text]") +TEST_CASE("Inspect Font Styles", "[text_styles]") +{ + struct TestCaseData + { + const char* fontPath; + uint16_t expectedWeight; + bool expectedItalic; + }; + + std::vector testCases = { + {"assets/fonts/AdventPro-VariableFont_wdth,wght.ttf", 400, false}, + {"assets/fonts/Inter_18pt-Regular.ttf", 400, false}, + {"assets/fonts/Inter_28pt-Bold.ttf", 700, false}, + {"assets/fonts/OpenSans-Italic.ttf", 400, true}, + {"assets/fonts/OpenSans-ExtraBoldItalic.ttf", 800, true}, + }; + + for (const auto& testCase : testCases) + { + SECTION(testCase.fontPath) + { + rive::rcp font = loadFont(testCase.fontPath); + HBFont* hbFont = static_cast(font.get()); + + REQUIRE(hbFont->getWeight() == testCase.expectedWeight); + REQUIRE(hbFont->isItalic() == testCase.expectedItalic); + } + } +} + +TEST_CASE("fallback glyphs are found", "[text_fallback]") { REQUIRE(fallbackFonts.empty()); auto font = loadFont("assets/RobotoFlex.ttf"); diff --git a/viewer/src/viewer_content/text_content.cpp b/viewer/src/viewer_content/text_content.cpp index 84514def..9375c057 100644 --- a/viewer/src/viewer_content/text_content.cpp +++ b/viewer/src/viewer_content/text_content.cpp @@ -100,10 +100,10 @@ static float drawpara(rive::Factory* factory, return origin.y + lines.back().bottom; } -//////////////////////////////////////////////////////////////////////////////////// std::vector> fallbackFonts; static rive::rcp pickFallbackFont(const rive::Unichar missing, - const uint32_t fallbackIndex) + const uint32_t fallbackIndex, + const rive::Font*) { if (fallbackIndex > 0) {