diff --git a/CHANGELOG.md b/CHANGELOG.md index ed1b43c00..e6f15d8f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ project adheres to [Semantic Versioning](http://semver.org/). ### Changed * Replaced `simple-get ` with ` Node.js builtin` `fetch` (#2309) * `ctx.font` has a new C++ parser and is 2x-400x faster. Please file an issue if you experience different results, as caching has been removed. +* The restriction of registering fonts before a canvas is created has been removed. You can now register a font as late as right before the `fillText` call ([#1921](https://github.com/Automattic/node-canvas/issues/1921)) ### Added * Support for accessibility and links in PDFs diff --git a/src/Canvas.cc b/src/Canvas.cc index 7b208bec2..b4fe25120 100644 --- a/src/Canvas.cc +++ b/src/Canvas.cc @@ -38,7 +38,10 @@ using namespace std; -std::vector font_face_list; +std::vector Canvas::font_face_list; + +// Increases each time a font is (de)registered +int Canvas::fontSerial = 1; /* * Initialize Canvas. @@ -734,6 +737,7 @@ Canvas::RegisterFont(const Napi::CallbackInfo& info) { free(family); free(weight); free(style); + fontSerial++; } void @@ -749,6 +753,7 @@ Canvas::DeregisterAllFonts(const Napi::CallbackInfo& info) { }); font_face_list.clear(); + fontSerial++; if (!success) Napi::Error::New(env, "Could not deregister one or more fonts").ThrowAsJavaScriptException(); } diff --git a/src/Canvas.h b/src/Canvas.h index 5b039539a..7539725d9 100644 --- a/src/Canvas.h +++ b/src/Canvas.h @@ -92,9 +92,11 @@ class Canvas : public Napi::ObjectWrap { void resurface(Napi::Object This); Napi::Env env; + static int fontSerial; private: Backend* _backend; Napi::ObjectReference _jsBackend; Napi::FunctionReference ctor; + static std::vector font_face_list; }; diff --git a/src/CanvasRenderingContext2d.cc b/src/CanvasRenderingContext2d.cc index dfbcc17a0..af32d949f 100644 --- a/src/CanvasRenderingContext2d.cc +++ b/src/CanvasRenderingContext2d.cc @@ -168,6 +168,18 @@ Context2d::Initialize(Napi::Env& env, Napi::Object& exports) { data->Context2dCtor = Napi::Persistent(ctor); } +void +Context2d::recreateLayout() { + if (_layout) g_object_unref(_layout); + _layout = pango_cairo_create_layout(_context); + // As of January 2023, Pango rounds glyph positions which renders text wider + // or narrower than the browser. See #2184 for more information +#if PANGO_VERSION_CHECK(1, 44, 0) + pango_context_set_round_glyph_positions(pango_layout_get_context(_layout), FALSE); +#endif + pango_layout_set_font_description(_layout, state->fontDescription); +} + /* * Create a cairo context. */ @@ -222,17 +234,10 @@ Context2d::Context2d(const Napi::CallbackInfo& info) : Napi::ObjectWrapcreateCairoContext(); - _layout = pango_cairo_create_layout(_context); - - // As of January 2023, Pango rounds glyph positions which renders text wider - // or narrower than the browser. See #2184 for more information -#if PANGO_VERSION_CHECK(1, 44, 0) - pango_context_set_round_glyph_positions(pango_layout_get_context(_layout), FALSE); -#endif states.emplace(); state = &states.top(); - pango_layout_set_font_description(_layout, state->fontDescription); + recreateLayout(); } /* @@ -2446,6 +2451,12 @@ Context2d::paintText(const Napi::CallbackInfo&info, bool stroke) { double y = args[1]; double scaled_by = 1; + // If fonts have been registered, the PangoLayout is using an outdated FontMap + if (canvas()->fontSerial != fontSerial) { + recreateLayout(); + fontSerial = canvas()->fontSerial; + } + PangoLayout *layout = this->layout(); pango_layout_set_text(layout, str.c_str(), -1); diff --git a/src/CanvasRenderingContext2d.h b/src/CanvasRenderingContext2d.h index a78788451..d19baedf2 100644 --- a/src/CanvasRenderingContext2d.h +++ b/src/CanvasRenderingContext2d.h @@ -205,6 +205,7 @@ class Context2d : public Napi::ObjectWrap { void setFontFromState(); void resetState(); inline PangoLayout *layout(){ return _layout; } + void recreateLayout(); ~Context2d(); Napi::Env env; @@ -224,4 +225,5 @@ class Context2d : public Napi::ObjectWrap { cairo_t *_context = nullptr; cairo_path_t *_path; PangoLayout *_layout = nullptr; + int fontSerial = 0; };