mirror of
https://github.com/penpot/penpot.git
synced 2026-02-12 22:53:02 +00:00
✨ Make deleted fonts fixer to run with more granular stragegy
Instead of running it on all the file, only run it to local library and the current page, reducing considerably the overhead of analyzing the whole file on each file load. It stills executes for page each time the page is loaded, and add some kind of local cache for not doing repeated work each time page loads is pending to be implemented in other commit.
This commit is contained in:
@@ -42,7 +42,6 @@
|
||||
[app.main.data.workspace.common :as dwc]
|
||||
[app.main.data.workspace.drawing :as dwd]
|
||||
[app.main.data.workspace.edition :as dwe]
|
||||
[app.main.data.workspace.fix-broken-shapes :as fbs]
|
||||
[app.main.data.workspace.fix-deleted-fonts :as fdf]
|
||||
[app.main.data.workspace.groups :as dwg]
|
||||
[app.main.data.workspace.guides :as dwgu]
|
||||
@@ -232,8 +231,7 @@
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(rx/of (dp/check-open-plugin)
|
||||
(fdf/fix-deleted-fonts)
|
||||
(fbs/fix-broken-shapes)))))
|
||||
(fdf/fix-deleted-fonts-for-local-library file-id)))))
|
||||
|
||||
(defn- bundle-fetched
|
||||
[{:keys [file file-id thumbnails] :as bundle}]
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
;;
|
||||
;; Copyright (c) KALEIDOS INC
|
||||
|
||||
(ns app.main.data.workspace.fix-broken-shapes
|
||||
(:require
|
||||
[app.main.data.changes :as dch]
|
||||
[app.main.data.helpers :as dsh]
|
||||
[beicon.v2.core :as rx]
|
||||
[potok.v2.core :as ptk]))
|
||||
|
||||
(defn- generate-broken-link-changes
|
||||
[attr {:keys [objects id] :as container}]
|
||||
(let [base {:type :fix-obj :fix :broken-children attr id}
|
||||
contains? (partial contains? objects)
|
||||
xform (comp
|
||||
;; FIXME: Ensure all obj have id field (this is needed
|
||||
;; because some bug adds an ephimeral shape with id ZERO,
|
||||
;; with a single attr `:shapes` having a vector of ids
|
||||
;; pointing to not existing shapes). That happens on
|
||||
;; components. THIS IS A WORKAOURD
|
||||
(map (fn [[id obj]]
|
||||
(if (some? (:id obj))
|
||||
obj
|
||||
(assoc obj :id id))))
|
||||
|
||||
;; Remove all valid shapes
|
||||
(remove (fn [obj]
|
||||
(every? contains? (:shapes obj))))
|
||||
|
||||
(map (fn [obj]
|
||||
(assoc base :id (:id obj)))))]
|
||||
|
||||
(sequence xform objects)))
|
||||
|
||||
(defn fix-broken-shapes
|
||||
[]
|
||||
(ptk/reify ::fix-broken-shapes
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
(let [fdata (dsh/lookup-file-data state)
|
||||
changes (concat
|
||||
(mapcat (partial generate-broken-link-changes :page-id)
|
||||
(vals (:pages-index fdata)))
|
||||
(mapcat (partial generate-broken-link-changes :component-id)
|
||||
(vals (:components fdata))))]
|
||||
|
||||
(if (seq changes)
|
||||
(rx/of (dch/commit-changes
|
||||
{:origin it
|
||||
:redo-changes (vec changes)
|
||||
:undo-changes []
|
||||
:save-undo? false}))
|
||||
(rx/empty))))))
|
||||
@@ -14,8 +14,9 @@
|
||||
[beicon.v2.core :as rx]
|
||||
[potok.v2.core :as ptk]))
|
||||
|
||||
;; This event will update the file so the texts with non existing custom fonts try to be fixed.
|
||||
;; This can happen when:
|
||||
;; This event will update the file so the texts with non existing
|
||||
;; custom fonts try to be fixed. This can happen when:
|
||||
;;
|
||||
;; - Exporting/importing files to different teams or penpot instances
|
||||
;; - Moving files from one team to another in the same instance
|
||||
;; - Custom fonts are explicitly deleted in the team area
|
||||
@@ -23,112 +24,99 @@
|
||||
(defn- calculate-alternative-font-id
|
||||
[value]
|
||||
(let [fonts (deref fonts/fontsdb)]
|
||||
(->> (vals fonts)
|
||||
(filter #(= (:family %) value))
|
||||
(first)
|
||||
:id)))
|
||||
(reduce-kv (fn [_ _ font]
|
||||
(if (= (:family font) value)
|
||||
(reduced (:id font))
|
||||
nil))
|
||||
nil
|
||||
fonts)))
|
||||
|
||||
(defn- has-invalid-font-family?
|
||||
[node]
|
||||
(let [fonts (deref fonts/fontsdb)
|
||||
font-family (:font-family node)
|
||||
alternative-font-id (calculate-alternative-font-id font-family)]
|
||||
(let [fonts (deref fonts/fontsdb)
|
||||
font-family (:font-family node)]
|
||||
(and (some? font-family)
|
||||
(nil? (get fonts (:font-id node)))
|
||||
(some? alternative-font-id))))
|
||||
(nil? (get fonts (:font-id node))))))
|
||||
|
||||
(defn- should-fix-deleted-font-shape?
|
||||
(defn- shape-has-invalid-font-family??
|
||||
[shape]
|
||||
(let [text-nodes (txt/node-seq txt/is-text-node? (:content shape))]
|
||||
(and (cfh/text-shape? shape)
|
||||
(some has-invalid-font-family? text-nodes))))
|
||||
|
||||
(defn- should-fix-deleted-font-component?
|
||||
[component]
|
||||
(let [xf (comp (map val)
|
||||
(filter should-fix-deleted-font-shape?))]
|
||||
(first (sequence xf (:objects component)))))
|
||||
(and (cfh/text-shape? shape)
|
||||
(some has-invalid-font-family?
|
||||
(txt/node-seq txt/is-text-node? (:content shape)))))
|
||||
|
||||
(defn- fix-deleted-font
|
||||
[node]
|
||||
(let [alternative-font-id (calculate-alternative-font-id (:font-family node))]
|
||||
(cond-> node
|
||||
(some? alternative-font-id) (assoc :font-id alternative-font-id))))
|
||||
(if-let [alternative-font-id (calculate-alternative-font-id (:font-family node))]
|
||||
(assoc node :font-id alternative-font-id)
|
||||
node))
|
||||
|
||||
(defn- fix-deleted-font-shape
|
||||
(defn- fix-shape-content
|
||||
[shape]
|
||||
(let [transform (partial txt/transform-nodes has-invalid-font-family? fix-deleted-font)]
|
||||
(update shape :content transform)))
|
||||
(txt/transform-nodes has-invalid-font-family? fix-deleted-font
|
||||
(:content shape)))
|
||||
|
||||
(defn- fix-deleted-font-component
|
||||
[component]
|
||||
(update component
|
||||
:objects
|
||||
(fn [objects]
|
||||
(update-vals objects fix-deleted-font-shape))))
|
||||
|
||||
(defn fix-deleted-font-typography
|
||||
(defn- fix-typography
|
||||
[typography]
|
||||
(let [alternative-font-id (calculate-alternative-font-id (:font-family typography))]
|
||||
(cond-> typography
|
||||
(some? alternative-font-id) (assoc :font-id alternative-font-id))))
|
||||
(if-let [alternative-font-id (calculate-alternative-font-id (:font-family typography))]
|
||||
(assoc typography :font-id alternative-font-id)
|
||||
typography))
|
||||
|
||||
(defn- generate-deleted-font-shape-changes
|
||||
(defn- generate-page-changes
|
||||
[{:keys [objects id]}]
|
||||
(sequence
|
||||
(comp (map val)
|
||||
(filter should-fix-deleted-font-shape?)
|
||||
(map (fn [shape]
|
||||
{:type :mod-obj
|
||||
:id (:id shape)
|
||||
:page-id id
|
||||
:operations [{:type :set
|
||||
:attr :content
|
||||
:val (:content (fix-deleted-font-shape shape))}
|
||||
{:type :set
|
||||
:attr :position-data
|
||||
:val nil}]})))
|
||||
objects))
|
||||
(reduce-kv (fn [changes shape-id shape]
|
||||
(if (shape-has-invalid-font-family?? shape)
|
||||
(conj changes {:type :mod-obj
|
||||
:id shape-id
|
||||
:page-id id
|
||||
:operations [{:type :set
|
||||
:attr :content
|
||||
:val (fix-shape-content shape)}
|
||||
{:type :set
|
||||
:attr :position-data
|
||||
:val nil}]})
|
||||
changes))
|
||||
[]
|
||||
objects))
|
||||
|
||||
(defn- generate-deleted-font-components-changes
|
||||
(defn- generate-library-changes
|
||||
[fdata]
|
||||
(sequence
|
||||
(comp (map val)
|
||||
(filter should-fix-deleted-font-component?)
|
||||
(map (fn [component]
|
||||
{:type :mod-component
|
||||
:id (:id component)
|
||||
:objects (-> (fix-deleted-font-component component) :objects)})))
|
||||
(:components fdata)))
|
||||
(reduce-kv (fn [changes _ typography]
|
||||
(if (has-invalid-font-family? typography)
|
||||
(conj changes {:type :mod-typography
|
||||
:typography (fix-typography typography)})
|
||||
changes))
|
||||
[]
|
||||
(:typographies fdata)))
|
||||
|
||||
(defn- generate-deleted-font-typography-changes
|
||||
[fdata]
|
||||
(sequence
|
||||
(comp (map val)
|
||||
(filter has-invalid-font-family?)
|
||||
(map (fn [typography]
|
||||
{:type :mod-typography
|
||||
:typography (fix-deleted-font-typography typography)})))
|
||||
(:typographies fdata)))
|
||||
|
||||
(defn fix-deleted-fonts
|
||||
[]
|
||||
(ptk/reify ::fix-deleted-fonts
|
||||
(defn fix-deleted-fonts-for-local-library
|
||||
"Looks the file local library for deleted fonts and emit changes if
|
||||
invalid but fixable typographyes found."
|
||||
[file-id]
|
||||
(ptk/reify ::fix-deleted-fonts-for-local-library
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
(let [fdata (dsh/lookup-file-data state)
|
||||
pages (:pages-index fdata)
|
||||
|
||||
shape-changes (mapcat generate-deleted-font-shape-changes (vals pages))
|
||||
components-changes (generate-deleted-font-components-changes fdata)
|
||||
typography-changes (generate-deleted-font-typography-changes fdata)
|
||||
changes (concat shape-changes
|
||||
components-changes
|
||||
typography-changes)]
|
||||
(if (seq changes)
|
||||
(let [fdata (dsh/lookup-file-data state file-id)]
|
||||
(when-let [changes (-> (generate-library-changes fdata)
|
||||
(not-empty))]
|
||||
(rx/of (dwc/commit-changes
|
||||
{:origin it
|
||||
:redo-changes (vec changes)
|
||||
:redo-changes changes
|
||||
:undo-changes []
|
||||
:save-undo? false}))
|
||||
(rx/empty))))))
|
||||
:save-undo? false})))))))
|
||||
|
||||
;; FIXME: would be nice to not execute this code twice per page in the
|
||||
;; same working session, maybe some local memoization can improve that
|
||||
|
||||
(defn fix-deleted-fonts-for-page
|
||||
[file-id page-id]
|
||||
(ptk/reify ::fix-deleted-fonts-for-page
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
(let [page (dsh/lookup-page state file-id page-id)]
|
||||
(when-let [changes (-> (generate-page-changes page)
|
||||
(not-empty))]
|
||||
(rx/of (dwc/commit-changes
|
||||
{:origin it
|
||||
:redo-changes changes
|
||||
:undo-changes []
|
||||
:save-undo? false})))))))
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
[app.main.data.helpers :as dsh]
|
||||
[app.main.data.persistence :as-alias dps]
|
||||
[app.main.data.workspace.drawing :as dwd]
|
||||
[app.main.data.workspace.fix-deleted-fonts :as fdf]
|
||||
[app.main.data.workspace.layout :as layout]
|
||||
[app.main.data.workspace.libraries :as dwl]
|
||||
[app.main.data.workspace.thumbnails :as dwth]
|
||||
@@ -104,6 +105,7 @@
|
||||
(if (dsh/lookup-page state file-id page-id)
|
||||
(rx/concat
|
||||
(rx/of (initialize-page* file-id page-id)
|
||||
(fdf/fix-deleted-fonts-for-page file-id page-id)
|
||||
(dwth/watch-state-changes file-id page-id)
|
||||
(dwl/watch-component-changes))
|
||||
(let [profile (:profile state)
|
||||
|
||||
Reference in New Issue
Block a user