diff --git a/src/main/java/fr/clementgre/pdf4teachers/utils/fonts/SystemFontsMapper.java b/src/main/java/fr/clementgre/pdf4teachers/utils/fonts/SystemFontsMapper.java
index dc719b71..25136afa 100644
--- a/src/main/java/fr/clementgre/pdf4teachers/utils/fonts/SystemFontsMapper.java
+++ b/src/main/java/fr/clementgre/pdf4teachers/utils/fonts/SystemFontsMapper.java
@@ -26,16 +26,21 @@
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
/**
* Originally created by azakhary on 4/24/2015
- * see https://github.com/UnderwaterApps/overlap2d/blob/master/overlap2d/src/com/uwsoft/editor/proxy/FontManager.java
+ * see ...
* (Apache 2.0 license)
* Edited by Clement Grennerat
*/
public class SystemFontsMapper {
-
- // Family, Paths
+
+ private static final String[] FONT_EXTENSIONS = {"ttf", "otf", "ttc"};
+ private static final double MILLIS_PER_SECOND = 1000d;
+ private static final int NOTIFICATION_TIMEOUT_SECONDS = 30;
+
+ // Family, Paths
private final HashMap systemFontMap = new HashMap<>();
public static String[] getSystemFontNames(){
@@ -46,71 +51,41 @@ public static String[] getSystemFontNames(){
return new String[0];
}
}
-
- private String[] getSystemFontsDirs(){
- String[] result;
+
+ public List getAllSystemFontFiles(){
if(PlatformUtils.isWindows()){
- result = new String[2];
- result[0] = System.getenv("WINDIR") + File.separator + "Fonts";
- result[1] = System.getenv("LOCALAPPDATA") + File.separator + "Microsoft\\Windows\\Fonts";
- return result;
-
- }else if(PlatformUtils.isMac()){
- result = new String[3];
- result[0] = System.getProperty("user.home") + File.separator + "Library/Fonts";
- result[1] = "/Library/Fonts";
- result[2] = "/System/Library/Fonts";
- return result;
-
- }else if(PlatformUtils.isLinux()){
- String[] pathsToCheck = {
- System.getProperty("user.home") + File.separator + ".fonts",
- "/usr/share/fonts/truetype",
- "/usr/share/fonts/TTF",
- "/usr/local/share/fonts/"
- };
- ArrayList resultList = new ArrayList<>();
-
- for(int i = pathsToCheck.length - 1; i >= 0; i--){
- String path = pathsToCheck[i];
- File tmp = new File(path);
- if(tmp.exists() && tmp.isDirectory() && tmp.canRead()){
- resultList.add(path);
- }
- }
-
- if(resultList.isEmpty()){
- MainWindow.showNotification(AlertIconType.WARNING, "Error: unable to load system fonts, no directory is readable", 30);
- result = new String[0];
- }else{
- result = new String[resultList.size()];
- result = resultList.toArray(result);
- }
- return result;
+ return scanDirectoriesForFonts(List.of(
+ System.getenv("WINDIR") + File.separator + "Fonts",
+ System.getenv("LOCALAPPDATA") + File.separator + "Microsoft\\Windows\\Fonts"
+ ));
}
- return null;
- }
- public List getAllSystemFontFiles(){
- // only retrieving ttf files
- String[] extensions = {"ttf", "otf", "ttc"};
- String[] paths = getSystemFontsDirs();
- return Arrays.stream(paths)
- .map(File::new)
- .filter(File::exists)
- .flatMap(fontDirectory -> FilesUtils.listFiles(fontDirectory, extensions, true)
- .stream())
- .collect(Collectors.toCollection(ArrayList::new));
+ if(PlatformUtils.isMac()){
+ return scanDirectoriesForFonts(List.of(
+ System.getProperty("user.home") + File.separator + "Library/Fonts",
+ "/Library/Fonts",
+ "/System/Library/Fonts"
+ ));
+ }
+ if(PlatformUtils.isLinux()){
+ // Use fc-list to get font files directly (works on NixOS and other non-standard setups)
+ List fcListFiles = getLinuxFontFilesViaFcList();
+ if(!fcListFiles.isEmpty()) return fcListFiles;
+
+ // Fallback to directory scanning if fc-list fails
+ return scanDirectoriesForFonts(getLinuxFontDirs());
+ }
+ return List.of();
}
-
+
public void loadFontsFromSystemFiles(){
String[] systemFonts = getSystemFontNames();
Log.i("Indexing system fonts... (" + systemFonts.length + " fonts)");
-
+
new Thread(() -> {
long time = System.currentTimeMillis();
- int pdfBoxErrors = 0;
-
+
systemFontMap.clear();
+ int pdfBoxErrors = 0;
for(File file : getAllSystemFontFiles()){
try{
Font[] fonts = Font.loadFonts(new FileInputStream(file.getAbsolutePath()), -1);
@@ -122,22 +97,93 @@ public void loadFontsFromSystemFiles(){
}
}catch(IOException e){Log.eNotified(e);}
}
-
- double ping = (System.currentTimeMillis() - time) / 1000d;
- Log.i("Loaded " + systemFontMap.size() + "/" + systemFonts.length + " fonts in " + ping + "s (" + pdfBoxErrors + " unable to load due to PDFBox restrictions, usually missing tables)");
-
+
+ double ping = (System.currentTimeMillis() - time) / MILLIS_PER_SECOND;
+ Log.i("Loaded " + systemFontMap.size() + '/' + systemFonts.length + " fonts in " + ping + "s (" + pdfBoxErrors + " unable to load due to PDFBox restrictions, usually missing tables)");
+
Platform.runLater(FontUtils::fontsUpdated);
}, "System fonts loader").start();
}
+
public void loadFontsFromCache(List fontPathss){
for(FontPaths fontPaths : fontPathss){
systemFontMap.put(fontPaths.getName(), fontPaths);
}
Platform.runLater(FontUtils::fontsUpdated);
}
+
+ public FontPaths getFontPathsFromName(String fontFamily){
+ return systemFontMap.get(fontFamily);
+ }
+
+ public HashMap getFonts(){
+ return systemFontMap;
+ }
+
+ public boolean hasFont(String fontFamily){
+ return systemFontMap.containsKey(fontFamily);
+ }
+ private List scanDirectoriesForFonts(List directories){
+ return directories.stream()
+ .map(File::new)
+ .filter(File::exists)
+ .flatMap(fontDirectory -> FilesUtils.listFiles(fontDirectory, FONT_EXTENSIONS, true).stream())
+ .collect(Collectors.toCollection(ArrayList::new));
+ }
+
+ private List getLinuxFontFilesViaFcList(){
+ try{
+ ProcessBuilder pb = new ProcessBuilder("fc-list", "--format=%{file}\n");
+ pb.redirectErrorStream(true);
+ Process process = pb.start();
+ String output = new String(process.getInputStream().readAllBytes(), java.nio.charset.StandardCharsets.UTF_8);
+ process.waitFor();
+
+ return Arrays.stream(output.split("\n"))
+ .filter(line -> !line.isEmpty())
+ .map(File::new)
+ .filter(file -> file.exists() && file.canRead())
+ .toList();
+ }catch(IOException | InterruptedException e){
+ Log.eNotified(e);
+ return List.of();
+ }
+ }
+
+ private List getLinuxFontDirs(){
+ String userHome = System.getProperty("user.home");
+ Stream standardPaths = Stream.of(
+ userHome + "/.local/share/fonts",
+ userHome + "/.fonts",
+ "/usr/share/fonts/truetype",
+ "/usr/share/fonts/TTF",
+ "/usr/local/share/fonts/"
+ );
+
+ // Add font directories from XDG_DATA_DIRS (for NixOS and other non-standard setups)
+ String xdgDataDirs = System.getenv("XDG_DATA_DIRS");
+ Stream xdgPaths = (xdgDataDirs != null && !xdgDataDirs.isEmpty())
+ ? Arrays.stream(xdgDataDirs.split(":"))
+ .filter(dir -> !dir.isEmpty())
+ .map(dir -> dir + "/fonts")
+ : Stream.empty();
+
+ List result = Stream.concat(xdgPaths, standardPaths)
+ .map(File::new)
+ .filter(file -> file.exists() && file.isDirectory() && file.canRead())
+ .map(File::getAbsolutePath)
+ .toList();
+
+ if(result.isEmpty()){
+ Platform.runLater(() ->
+ MainWindow.showNotification(AlertIconType.WARNING,
+ "Error: unable to load system fonts, no directory is readable", NOTIFICATION_TIMEOUT_SECONDS));
+ }
+ return result;
+ }
+
private boolean addFontToMap(Font font, String path){
-
// Check if PDFBox is able to load the font, otherwise, cancel the add.
try(PDDocument doc = new PDDocument();
FileInputStream fis = new FileInputStream(path)){
@@ -145,7 +191,7 @@ private boolean addFontToMap(Font font, String path){
}catch(IOException e){
return false;
}
-
+
FontPaths paths;
if(systemFontMap.containsKey(font.getFamily())){
paths = systemFontMap.get(font.getFamily());
@@ -157,14 +203,4 @@ private boolean addFontToMap(Font font, String path){
return true;
}
-
- public FontPaths getFontPathsFromName(String fontFamily){
- return systemFontMap.get(fontFamily);
- }
- public HashMap getFonts(){
- return systemFontMap;
- }
- public boolean hasFont(String fontFamily){
- return systemFontMap.containsKey(fontFamily);
- }
-}
+}
\ No newline at end of file