Skip to content

Commit

Permalink
refactor(font-control): uses native font enumeration (#804)
Browse files Browse the repository at this point in the history
* refactor(font-control): uses native font enumeration

slightly reduces jank when enumerating the font list.adds fuzzy searching to font list. updates electron.

* refactor(font-control): moves font initialisation to modV setup

Fixes bad SCSS rewrite from #583

* fix: scroll font-list to top when typing

* fix: use font-family only
  • Loading branch information
2xAA authored Jun 11, 2023
1 parent 2cad1e0 commit e294498
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 33 deletions.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
"dotenv": "^8.2.0",
"electron-updater": "^4.3.1",
"fluent-ffmpeg": "^2.1.2",
"font-list": "^1.3.1",
"fuse.js": "^6.2.1",
"golden-layout": "^1.5.9",
"grandiose": "github:vcync/grandiose#feat/workerCompatibility",
Expand Down
32 changes: 25 additions & 7 deletions src/application/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
import PromiseWorker from "promise-worker-transferable";
import Vue from "vue";
import { ipcRenderer } from "electron";
import { app } from "@electron/remote";
import { createWebcodecVideo } from "./createWebcodecVideo";

import Worker from "worker-loader!./worker/index.worker.js";
import {
setupMedia,
Expand All @@ -7,16 +13,9 @@ import {
} from "./setup-media";
import setupBeatDetektor from "./setup-beat-detektor";
import setupMidi from "./setup-midi";

import store from "./worker/store";
import windowHandler from "./window-handler";
import use from "./use";

import PromiseWorker from "promise-worker-transferable";
import Vue from "vue";
import { ipcRenderer } from "electron";
import { app } from "@electron/remote";
import { createWebcodecVideo } from "./createWebcodecVideo";
import { GROUP_ENABLED } from "./constants";

let imageBitmap;
Expand Down Expand Up @@ -158,6 +157,8 @@ export default class ModV {
async setup(canvas = document.createElement("canvas")) {
this.windowHandler();

this.enumerateFonts();

try {
await this.setupMedia({ useDefaultDevices: true });
} catch (e) {
Expand Down Expand Up @@ -310,4 +311,21 @@ export default class ModV {
loadPreset(filePathToPreset) {
this.$worker.postMessage({ type: "loadPreset", payload: filePathToPreset });
}

async enumerateFonts() {
const localFonts = await window.queryLocalFonts();
const fonts = [];

for (let i = 0; i < localFonts.length; i += 1) {
const { family, fullName, postscriptName, style } = localFonts[i];

fonts.push({ family, fullName, postscriptName, style });

// No need to await here, async loading is fine.
// The user can't use fonts fonts immediately at this stage, so no need to block the thread
document.fonts.load(`14px ${postscriptName}`, fullName);
}

this.store.commit("fonts/SET_LOCAL_FONTS", fonts);
}
}
30 changes: 30 additions & 0 deletions src/application/worker/store/modules/fonts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const state = {
defaultFonts: ["serif", "sans-serif", "cursive", "monospace"],
localFonts: []
};

const getters = {
fonts: state => [
...state.defaultFonts,
...state.localFonts
.filter(
(value, index, self) =>
index === self.findIndex(t => t.family === value.family)
)
.map(font => font.family)
.sort((a, b) => a.localeCompare(b))
]
};

const mutations = {
SET_LOCAL_FONTS(state, fonts = []) {
state.localFonts = fonts;
}
};

export default {
namespaced: true,
state,
getters,
mutations
};
57 changes: 37 additions & 20 deletions src/components/Controls/FontControl.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
:style="{ fontFamily: value }"
/>

<ul class="searchable-select" v-show="showFontList">
<ul class="searchable-select" v-show="showFontList" ref="fontList">
<li
v-for="(font, index) in fontsToShow"
:value="font"
Expand All @@ -29,7 +29,7 @@
</template>

<script>
import fontList from "font-list";
import Fuse from "fuse.js";
export default {
props: {
Expand All @@ -41,26 +41,16 @@ export default {
data() {
return {
defaultFonts: ["serif", "sans-serif", "cursive", "monospace"],
fonts: [],
showFontList: false,
searchTerm: "",
keyboardSelectedIndex: -1
keyboardSelectedIndex: -1,
fuse: null
};
},
async created() {
try {
const fonts = await fontList.getFonts();
this.fonts = [
...this.defaultFonts,
...fonts.map(font => font.replace(/"/g, ""))
];
} catch (e) {
console.error(e);
}
this.searchTerm = this.value;
this.setupFuse();
},
mounted() {
Expand All @@ -72,12 +62,20 @@ export default {
},
computed: {
fonts() {
return this.$modV._store.getters["fonts/fonts"];
},
fontsToShow() {
if (this.value === this.searchTerm) {
return this.fonts;
const { fonts, fuse, searchTerm, value } = this;
if (value === searchTerm || !searchTerm) {
return fonts;
}
return this.fonts.filter(font => this.search(font, this.searchTerm));
return fuse
.search(searchTerm)
.sort((a, b) => a.score - b.score)
.map(result => result.item);
}
},
Expand All @@ -88,6 +86,9 @@ export default {
} = e;
this.searchTerm = value;
this.$nextTick(() => {
this.$refs.fontList.scrollTo(0, 0);
});
},
setFont(font) {
Expand Down Expand Up @@ -166,6 +167,22 @@ export default {
selected.scrollIntoView({ block: "nearest" });
}
});
},
setupFuse(fontsIn) {
const fonts = fontsIn ?? this.fonts;
const fuse = new Fuse([], { includeScore: true });
// eslint-disable-next-line no-for-each/no-for-each
fonts.forEach(fontName => fuse.add(fontName));
this.fuse = fuse;
}
},
watch: {
fonts(fonts) {
this.setupFuse(fonts);
}
}
};
Expand All @@ -183,8 +200,8 @@ export default {
margin: 0;
}
.searchable-select.selected,
.searchable-select:hover {
.searchable-select li.selected,
.searchable-select li:hover {
background-color: var(--foreground-color-3);
}
</style>
6 changes: 1 addition & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3573,6 +3573,7 @@ call-bind@^1.0.0:
function-bind "^1.1.1"
get-intrinsic "^1.0.2"


call-limit@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/call-limit/-/call-limit-1.1.1.tgz#ef15f2670db3f1992557e2d965abc459e6e358d4"
Expand Down Expand Up @@ -6338,11 +6339,6 @@ follow-redirects@^1.0.0:
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc"
integrity sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==

font-list@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/font-list/-/font-list-1.3.1.tgz#b6527e94045601b92971572220ce691714452aed"
integrity sha512-/TvQbGLIdyfH4SBZkDwWlX0JNDVH98Q29SkgMJlIdmc4ObKu+RnB/B493lskB2Z8XZ2FZ532QOem4/PDgtoXUQ==

for-in@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
Expand Down

0 comments on commit e294498

Please sign in to comment.