diff --git a/frontend/src/app/main/fonts.cljs b/frontend/src/app/main/fonts.cljs index 50b3b0035..4ee3c80b3 100644 --- a/frontend/src/app/main/fonts.cljs +++ b/frontend/src/app/main/fonts.cljs @@ -33,16 +33,16 @@ :name "Source Sans Pro" :family "sourcesanspro" :variants - [{:id "200" :name "200" :weight "200" :style "normal" :suffix "extralight"} - {:id "200italic" :name "200 (italic)" :weight "200" :style "italic" :suffix "extralightitalic"} - {:id "300" :name "300" :weight "300" :style "normal" :suffix "light"} - {:id "300italic" :name "300 (italic)" :weight "300" :style "italic" :suffix "lightitalic"} - {:id "regular" :name "regular" :weight "400" :style "normal"} - {:id "italic" :name "italic" :weight "400" :style "italic"} - {:id "bold" :name "bold" :weight "bold" :style "normal"} - {:id "bolditalic" :name "bold (italic)" :weight "bold" :style "italic"} - {:id "black" :name "black" :weight "900" :style "normal"} - {:id "blackitalic" :name "black (italic)" :weight "900" :style "italic"}]}]) + [{:id "200" :name "200" :weight "200" :style "normal" :suffix "extralight" :ttf-url "sourcesanspro-extralight.ttf"} + {:id "200italic" :name "200 (italic)" :weight "200" :style "italic" :suffix "extralightitalic" :ttf-url "sourcesanspro-extralightitalic.ttf"} + {:id "300" :name "300" :weight "300" :style "normal" :suffix "light" :ttf-url "sourcesanspro-light.ttf"} + {:id "300italic" :name "300 (italic)" :weight "300" :style "italic" :suffix "lightitalic" :ttf-url "sourcesanspro-lightitalic.ttf"} + {:id "regular" :name "regular" :weight "400" :style "normal" :ttf-url "sourcesanspro-regular.ttf"} + {:id "italic" :name "italic" :weight "400" :style "italic" :ttf-url "sourcesanspro-italic.ttf"} + {:id "bold" :name "bold" :weight "bold" :style "normal" :ttf-url "sourcesanspro-bold.ttf"} + {:id "bolditalic" :name "bold (italic)" :weight "bold" :style "italic" :ttf-url "sourcesanspro-bolditalic.ttf"} + {:id "black" :name "black" :weight "900" :style "normal" :ttf-url "sourcesanspro-black.ttf"} + {:id "blackitalic" :name "black (italic)" :weight "900" :style "italic" :ttf-url "sourcesanspro-blackitalic.ttf"}]}]) (defonce fontsdb (l/atom {})) (defonce fonts (l/atom [])) @@ -253,7 +253,6 @@ (defn get-variant [{:keys [variants] :as font} font-variant-id] - (prn "get-variant" font-variant-id fonts) (or (d/seek #(= (:id %) font-variant-id) variants) (get-default-variant font))) diff --git a/frontend/src/app/render_wasm/api/fonts.cljs b/frontend/src/app/render_wasm/api/fonts.cljs index 3797a0bce..4c13618bf 100644 --- a/frontend/src/app/render_wasm/api/fonts.cljs +++ b/frontend/src/app/render_wasm/api/fonts.cljs @@ -34,20 +34,46 @@ [font-id] (uuid/uuid (subs font-id (inc (str/index-of font-id "-"))))) -(defn- font-id->uuid [font-id] - (if (str/starts-with? font-id "gfont-") - (google-font-id->uuid font-id) - (custom-font-id->uuid font-id))) +(defn- font-backend + [font-id] + (cond + (str/starts-with? font-id "gfont-") + :google + (str/starts-with? font-id "custom-") + :custom + :else + :builtin)) -(defn ^:private font-id->ttf-id [font-id font-variant-id] - (if (str/starts-with? font-id "gfont-") font-id - (let [font-uuid (custom-font-id->uuid font-id) - matching-font (d/seek (fn [[_ font]] - (and (= (:font-id font) font-uuid) - (= (:font-variant-id font) font-variant-id))) - (seq @fonts))] - (when matching-font - (:ttf-file-id (second matching-font)))))) +(defn- font-db-data + [font-id font-variant-id] + (let [font (fonts/get-font-data font-id) + variant (fonts/get-variant font font-variant-id)] + variant)) + +(defn- font-id->uuid [font-id] + (case (font-backend font-id) + :google + (google-font-id->uuid font-id) + :custom + (custom-font-id->uuid font-id) + :builtin + uuid/zero)) + +(defn ^:private font-id->asset-id [font-id font-variant-id] + (case (font-backend font-id) + :google + font-id + :custom + (let [font-uuid (custom-font-id->uuid font-id) + matching-font (d/seek (fn [[_ font]] + (and (= (:font-id font) font-uuid) + (= (:font-variant-id font) font-variant-id))) + (seq @fonts))] + (when matching-font + (:ttf-file-id (second matching-font)))) + :builtin + (let [variant (font-db-data font-id font-variant-id)] + (:ttf-url variant)))) ;; IMPORTANT: It should be noted that only TTF fonts can be stored. (defn- store-font-buffer @@ -78,26 +104,25 @@ (defn- google-font-ttf-url [font-id font-variant-id] - (let [font (fonts/get-font-data font-id) - variant (fonts/get-variant font font-variant-id)] + (let [variant (font-db-data font-id font-variant-id)] (if-let [ttf-url (:ttf-url variant)] (str/replace ttf-url "http://fonts.gstatic.com/s/" (u/join cf/public-uri "/internal/gfonts/font/")) - (do - (println "Variant TTF URL not found for" font-id font-variant-id) - nil)))) + nil))) (defn- font-id->ttf-url - [font-id font-variant-id] - (if (str/starts-with? font-id "gfont-") - ;; if font-id is a google font (starts with gfont-), we need to get the ttf url from Google Fonts API. + [font-id asset-id font-variant-id] + (case (font-backend font-id) + :google (google-font-ttf-url font-id font-variant-id) - ;; otherwise, we return the font from our public-uri - (str (u/join cf/public-uri "assets/by-id/" font-id)))) + :custom + (dm/str (u/join cf/public-uri "assets/by-id/" font-id)) + :builtin + (dm/str (u/join cf/public-uri "fonts/" asset-id)))) (defn- store-font-id [font-data asset-id] (when asset-id - (let [uri (font-id->ttf-url asset-id (:font-variant-id font-data)) + (let [uri (font-id->ttf-url (:font-id font-data) asset-id (:font-variant-id font-data)) id-buffer (uuid/get-u32 (:wasm-id font-data)) font-data (assoc font-data :family-id-buffer id-buffer) font-stored? (not= 0 (h/call wasm/internal-module "_is_font_uploaded" @@ -136,17 +161,16 @@ (let [font-id (dm/get-prop font :font-id) font-variant-id (dm/get-prop font :font-variant-id) wasm-id (font-id->uuid font-id) + raw-weight (or (:weight (font-db-data font-id font-variant-id)) 400) - weight (serialize-font-weight - (if-let [weight-match (re-find #"\d+" font-variant-id)] - (js/parseInt weight-match) - 400)) + weight (serialize-font-weight raw-weight) style (serialize-font-style (cond (str/includes? font-variant-id "italic") "italic" :else "normal")) - asset-id (font-id->ttf-id font-id font-variant-id) + asset-id (font-id->asset-id font-id font-variant-id) font-data {:wasm-id wasm-id + :font-id font-id :font-variant-id font-variant-id :style style :weight weight}] diff --git a/render-wasm/src/fonts/RobotoMono-Regular.ttf b/render-wasm/src/fonts/RobotoMono-Regular.ttf deleted file mode 100644 index 6df2b2536..000000000 Binary files a/render-wasm/src/fonts/RobotoMono-Regular.ttf and /dev/null differ diff --git a/render-wasm/src/fonts/sourcesanspro-regular.ttf b/render-wasm/src/fonts/sourcesanspro-regular.ttf new file mode 100644 index 000000000..cb2f33597 Binary files /dev/null and b/render-wasm/src/fonts/sourcesanspro-regular.ttf differ diff --git a/render-wasm/src/render/fonts.rs b/render-wasm/src/render/fonts.rs index 2460fa27d..dd8d24f2b 100644 --- a/render-wasm/src/render/fonts.rs +++ b/render-wasm/src/render/fonts.rs @@ -1,12 +1,22 @@ use skia_safe::{self as skia, textlayout, Font, FontMgr}; -use crate::shapes::FontFamily; +use crate::shapes::{FontFamily, FontStyle}; +use crate::uuid::Uuid; -const DEFAULT_FONT_BYTES: &[u8] = include_bytes!("../fonts/RobotoMono-Regular.ttf"); const EMOJI_FONT_BYTES: &[u8] = include_bytes!("../fonts/NotoColorEmoji-Regular.ttf"); -pub static DEFAULT_FONT: &'static str = "robotomono-regular"; pub static DEFAULT_EMOJI_FONT: &'static str = "noto-color-emoji"; +const DEFAULT_FONT_BYTES: &[u8] = include_bytes!("../fonts/sourcesanspro-regular.ttf"); + +pub fn default_font() -> String { + let family = FontFamily::new(default_font_uuid(), 400, FontStyle::Normal); + format!("{}", family) +} + +fn default_font_uuid() -> Uuid { + Uuid::nil() +} + pub struct FontStore { font_mgr: FontMgr, font_provider: textlayout::TypefaceFontProvider, @@ -18,25 +28,19 @@ impl FontStore { pub fn new() -> Self { let font_mgr = FontMgr::new(); - let mut font_provider = skia::textlayout::TypefaceFontProvider::new(); - - let default_font = font_mgr - .new_from_data(DEFAULT_FONT_BYTES, None) - .expect("Failed to load font"); - - font_provider.register_typeface(default_font, DEFAULT_FONT); + let mut font_provider = load_default_provider(&font_mgr); + // TODO: Load emoji font lazily let emoji_font = font_mgr .new_from_data(EMOJI_FONT_BYTES, None) .expect("Failed to load font"); - font_provider.register_typeface(emoji_font, DEFAULT_EMOJI_FONT); let mut font_collection = skia::textlayout::FontCollection::new(); font_collection.set_default_font_manager(FontMgr::from(font_provider.clone()), None); let debug_typeface = font_provider - .match_family_style("robotomono-regular", skia::FontStyle::default()) + .match_family_style(default_font().as_str(), skia::FontStyle::default()) .unwrap(); let debug_font = skia::Font::new(debug_typeface, 10.0); @@ -85,3 +89,15 @@ impl FontStore { self.font_provider.family_names().any(|x| x == serialized) } } + +fn load_default_provider(font_mgr: &FontMgr) -> skia::textlayout::TypefaceFontProvider { + let mut font_provider = skia::textlayout::TypefaceFontProvider::new(); + + let family = FontFamily::new(default_font_uuid(), 400, FontStyle::Normal); + let font = font_mgr + .new_from_data(DEFAULT_FONT_BYTES, None) + .expect("Failed to load font"); + font_provider.register_typeface(font, family.alias().as_str()); + + font_provider +} diff --git a/render-wasm/src/shapes/fonts.rs b/render-wasm/src/shapes/fonts.rs index a0e624bfc..7a4524cad 100644 --- a/render-wasm/src/shapes/fonts.rs +++ b/render-wasm/src/shapes/fonts.rs @@ -39,6 +39,10 @@ impl FontFamily { pub fn new(id: Uuid, weight: u32, style: FontStyle) -> Self { Self { id, style, weight } } + + pub fn alias(&self) -> String { + format!("{}", self) + } } impl fmt::Display for FontFamily { diff --git a/render-wasm/src/shapes/text.rs b/render-wasm/src/shapes/text.rs index d343a2944..4a5d37af1 100644 --- a/render-wasm/src/shapes/text.rs +++ b/render-wasm/src/shapes/text.rs @@ -1,6 +1,6 @@ use crate::{ math::Rect, - render::{DEFAULT_EMOJI_FONT, DEFAULT_FONT}, + render::{default_font, DEFAULT_EMOJI_FONT}, }; use skia_safe::{ self as skia, @@ -133,7 +133,7 @@ impl TextLeaf { style.set_font_size(self.font_size); style.set_font_families(&[ self.serialized_font_family(), - DEFAULT_FONT.to_string(), + default_font(), DEFAULT_EMOJI_FONT.to_string(), ]); style