diff --git a/frontend/src/app/main/fonts.cljs b/frontend/src/app/main/fonts.cljs index 0ef0f2061e..3d4101e1f7 100644 --- a/frontend/src/app/main/fonts.cljs +++ b/frontend/src/app/main/fonts.cljs @@ -342,8 +342,8 @@ (fn [result {:keys [font-id] :as node}] (let [current-font (if (some? font-id) - (select-keys node [:font-id :font-variant-id]) - (select-keys txt/default-typography [:font-id :font-variant-id]))] + (select-keys node [:font-id :font-variant-id :font-weight :font-style]) + (select-keys txt/default-typography [:font-id :font-variant-id :font-weight :font-style]))] (conj result current-font))) #{}))) diff --git a/frontend/src/app/render_wasm/api.cljs b/frontend/src/app/render_wasm/api.cljs index 4b6d389217..d0cec24ae1 100644 --- a/frontend/src/app/render_wasm/api.cljs +++ b/frontend/src/app/render_wasm/api.cljs @@ -20,7 +20,6 @@ [app.common.types.shape.layout :as ctl] [app.common.uuid :as uuid] [app.config :as cf] - [app.main.fonts :as fonts] [app.main.refs :as refs] [app.main.render :as render] [app.main.store :as st] @@ -828,7 +827,7 @@ (set-shape-vertical-align (get content :vertical-align)) - (let [fonts (fonts/get-content-fonts content) + (let [fonts (f/get-content-fonts content) fallback-fonts (fonts-from-text-content content true) all-fonts (concat fonts fallback-fonts) result (f/store-fonts shape-id all-fonts)] diff --git a/frontend/src/app/render_wasm/api/fonts.cljs b/frontend/src/app/render_wasm/api/fonts.cljs index ea47a06b2b..7acb5c88ff 100644 --- a/frontend/src/app/render_wasm/api/fonts.cljs +++ b/frontend/src/app/render_wasm/api/fonts.cljs @@ -9,6 +9,7 @@ [app.common.data :as d] [app.common.data.macros :as dm] [app.common.logging :as log] + [app.common.types.text :as txt] [app.common.uuid :as uuid] [app.config :as cf] [app.main.fonts :as fonts] @@ -49,10 +50,13 @@ :builtin)) (defn- font-db-data - [font-id font-variant-id] + [font-id font-variant-id font-weight-fallback font-style-fallback] (let [font (fonts/get-font-data font-id) + closest-variant (fonts/find-closest-variant font font-weight-fallback font-style-fallback) variant (fonts/get-variant font font-variant-id)] - variant)) + (if (or (nil? closest-variant) (= closest-variant variant)) + variant + closest-variant))) (defn- font-id->uuid [font-id] (case (font-backend font-id) @@ -63,22 +67,22 @@ :builtin uuid/zero)) -(defn ^:private font-id->asset-id [font-id font-variant-id] + +(defn ^:private font-id->asset-id [font-id font-variant-id font-weight font-style] (case (font-backend font-id) :google font-id :custom (let [font-uuid (custom-font-id->uuid font-id) - matching-font (d/seek (fn [[_ font]] - (let [variant-id (or (:font-variant-id font) (dm/str (:font-style font) "-" (:font-weight font)))] - (and (= (:font-id font) font-uuid) - (or (nil? font-variant-id) - (= variant-id font-variant-id))))) - (seq @fonts))] + matching-font (some (fn [[_ font]] + (and (= (:font-id font) font-uuid) + (= (str (:font-weight font)) (str font-weight)) + font)) + (seq @fonts))] (when matching-font - (:ttf-file-id (second matching-font)))) + (:ttf-file-id matching-font))) :builtin - (let [variant (font-db-data font-id font-variant-id)] + (let [variant (font-db-data font-id font-variant-id font-weight font-style)] (:ttf-url variant)))) (defn update-text-layout @@ -100,6 +104,7 @@ ptr (h/call wasm/internal-module "_alloc_bytes" size) heap (gobj/get ^js wasm/internal-module "HEAPU8") mem (js/Uint8Array. (.-buffer heap) ptr size)] + (.set mem (js/Uint8Array. font-array-buffer)) (h/call wasm/internal-module "_store_font" (aget shape-id-buffer 0) @@ -134,17 +139,17 @@ (rx/empty))))}) (defn- google-font-ttf-url - [font-id font-variant-id] - (let [variant (font-db-data font-id font-variant-id)] + [font-id font-variant-id font-weight font-style] + (let [variant (font-db-data font-id font-variant-id font-weight font-style)] (if-let [ttf-url (:ttf-url variant)] (str/replace ttf-url "https://fonts.gstatic.com/s/" (u/join cf/public-uri "/internal/gfonts/font/")) nil))) (defn- font-id->ttf-url - [font-id asset-id font-variant-id] + [font-id asset-id font-variant-id font-weight font-style] (case (font-backend font-id) :google - (google-font-ttf-url font-id font-variant-id) + (google-font-ttf-url font-id font-variant-id font-weight font-style) :custom (dm/str (u/join cf/public-uri "assets/by-id/" asset-id)) :builtin @@ -153,7 +158,7 @@ (defn- store-font-id [shape-id font-data asset-id emoji? fallback?] (when asset-id - (let [uri (font-id->ttf-url (:font-id font-data) asset-id (:font-variant-id font-data)) + (let [uri (font-id->ttf-url (:font-id font-data) asset-id (:font-variant-id font-data) (:weight font-data) (:style 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" @@ -187,6 +192,30 @@ (catch :default _e uuid/zero))) +(defn normalize-span-font + [span paragraph] + (let [font-id (:font-id span) + font-variant-id (:font-variant-id span) + font-weight-fallback (or (:font-weight span) (:font-weight paragraph)) + font-style-fallback (or (:font-style span) (:font-style paragraph)) + font-data (font-db-data font-id font-variant-id font-weight-fallback font-style-fallback)] + (-> span + (assoc :font-variant-id (or (:name font-data) (:id font-data) font-variant-id) + :font-weight (or (:weight font-data) font-weight-fallback) + :font-style (or (:style font-data) font-style-fallback))))) + +(defn normalize-paragraph-font + [paragraph] + (let [font-id (:font-id paragraph) + font-variant-id (:font-variant-id paragraph) + font-weight-fallback (:font-weight paragraph) + font-style-fallback (:font-style paragraph) + font-data (font-db-data font-id font-variant-id font-weight-fallback font-style-fallback)] + (-> paragraph + (assoc :font-variant-id (or (:name font-data) (:id font-data) font-variant-id) + :font-weight (or (:weight font-data) font-weight-fallback) + :font-style (or (:style font-data) font-style-fallback))))) + (defn serialize-font-size [font-size] (cond @@ -244,26 +273,36 @@ (string? letter-spacing) (or (d/parse-double letter-spacing) default-letter-spacing))) + +(defn normalize-font-variant + [font-variant-id] + (if (or (nil? font-variant-id) (str/blank? font-variant-id)) + "regular" + font-variant-id)) + (defn store-font [shape-id font] (let [font-id (get font :font-id) font-variant-id (get font :font-variant-id) + font-weight-fallback (or (get font :font-weight) 400) + font-style-fallback (or (get font :font-style) "normal") emoji? (get font :is-emoji false) fallback? (get font :is-fallback false) + font-data (font-db-data font-id font-variant-id font-weight-fallback font-style-fallback) wasm-id (font-id->uuid font-id) - raw-weight (or (:weight (font-db-data font-id font-variant-id)) 400) + raw-weight (or (:weight font-data) font-weight-fallback) weight (serialize-font-weight raw-weight) style (serialize-font-style (cond (str/includes? font-variant-id "italic") "italic" (str/includes? raw-weight "italic") "italic" - :else "normal")) - asset-id (font-id->asset-id font-id font-variant-id) + :else font-style-fallback)) + variant-id (or (:name font-data) font-variant-id) + asset-id (font-id->asset-id font-id variant-id raw-weight style) font-data {:wasm-id wasm-id :font-id font-id - :font-variant-id font-variant-id + :font-variant-id variant-id :style style :weight weight}] - (store-font-id shape-id font-data asset-id emoji? fallback?))) ;; FIXME: This is a temporary function to load the fallback fonts for the editor. @@ -273,6 +312,29 @@ (doseq [font fonts] (fonts/ensure-loaded! (:font-id font) (:font-variant-id font)))) + +(defn get-content-fonts + "Extends from app.main.fonts/get-content-fonts. Extracts the fonts used by the content of a text shape, resolving the correct font variant info." + [content] + (let [paragraph-set (first (get content :children)) + paragraphs (get paragraph-set :children)] + (->> paragraphs + (mapcat #(get % :children)) + (filter txt/is-text-node?) + (reduce + (fn [result {:keys [font-id font-variant-id font-weight font-style] :as node}] + (let [resolved-font-id (or font-id (:font-id txt/default-typography)) + resolved-variant-id (or font-variant-id (:font-variant-id txt/default-typography)) + font-weight-fallback (or font-weight (:font-weight txt/default-typography) 400) + font-style-fallback (or font-style (:font-style txt/default-typography) "normal") + font-data (font-db-data resolved-font-id resolved-variant-id font-weight-fallback font-style-fallback) + font-ref {:font-id resolved-font-id + :font-variant-id (or (:name font-data) (:id font-data) resolved-variant-id) + :font-weight (or (:weight font-data) font-weight-fallback) + :font-style (or (:style font-data) font-style-fallback)}] + (conj result font-ref))) + #{})))) + (defn store-fonts [shape-id fonts] (keep (fn [font] (store-font shape-id font)) fonts)) diff --git a/frontend/src/app/render_wasm/api/texts.cljs b/frontend/src/app/render_wasm/api/texts.cljs index 15827186de..3ded360e2c 100644 --- a/frontend/src/app/render_wasm/api/texts.cljs +++ b/frontend/src/app/render_wasm/api/texts.cljs @@ -142,7 +142,9 @@ ;; buffer has the following format: ;; [ ] [spans paragraph text] - (let [num-spans (count spans) + (let [normalized-paragraph (f/normalize-paragraph-font paragraph) + normalized-spans (map #(f/normalize-span-font % normalized-paragraph) spans) + num-spans (count normalized-spans) fills-size (* types.fills.impl/FILL-U8-SIZE MAX-TEXT-FILLS) metadata-size (+ PARAGRAPH-ATTR-U8-SIZE (* num-spans (+ SPAN-ATTR-U8-SIZE fills-size))) @@ -157,8 +159,8 @@ (-> offset (mem/write-u32 dview num-spans) - (write-paragraph dview paragraph) - (write-spans dview spans paragraph) + (write-paragraph dview normalized-paragraph) + (write-spans dview normalized-spans normalized-paragraph) (mem/write-buffer heapu8 text-buffer)) (h/call wasm/internal-module "_set_shape_text_content")))