Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaFx Could not load @font-face font because of com.sun.javafx.css.StyleManager loadStylesheetUnPrivileged

I had already asked a similar question here but it seems It wasn't clear since I had a lot of code in the project and couldn't post it here So please don't mark as duplicate.

Because of that, I then decided to create a new project with just a Label in it to make the code small and clean and also to eliminate other potential suspects of the error I'm getting.

So here is my Java Source code

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        Group root = new Group();

        Label label = new Label("Sample Label");
        label.setId("sampleLabel");
        root.getChildren().add(label);

        Scene scene = new Scene(root, 300, 275);
        scene.getStylesheets().add(getClass().getResource("applicationStyles.css").toExternalForm());
        primaryStage.setTitle("Hello World");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

And this is my css file

/**/
@font-face {
    font-family:'Roboto';
    src:url("Roboto-Thin.ttf");
}
#sampleLabel{
    -fx-font-family: Roboto ;
}

This is the error I'm getting in Intellij Idea

Dec 02, 2015 9:16:34 AM com.sun.javafx.css.StyleManager loadStylesheetUnPrivileged
INFO: Could not load @font-face font [file:/C:/Users/UserName/Desktop/Java8%20projects/TeamViewer/out/production/TeamViewer/sample/Roboto-Thin.ttf]

All the project files are in one package and the font file is also present in the out>production>TeamViewer>sample>Roboto-Thin.ttf. I also upgraded from jdk-8u65 to jdk-8u66

Thanks, any help is greatly appreciated.

like image 478
Collins Abitekaniza Avatar asked Dec 02 '15 06:12

Collins Abitekaniza


3 Answers

So, almost 2 years later, and I came across my own response to the same problem I still have.

But now I have a cooler and more elegant solution, after studying the source code for com.sun.javafx.css.StyleManager : Simply parse the stylesheets myself and load the fonts.

See relevant source code here: lines 932-662

(Yes, this is all in Clojure, but I am sure you can figure it out.)

I start with this:

(defn add-stylesheet [^Scene scene path]
  (let [logger (Logging/getCSSLogger)
        level (.level logger)]
    (.setLevel logger PlatformLogger$Level/OFF)  ;; turn off logger
    (-> scene .getStylesheets (.add path))  ;; set stylesheet
    (.setLevel logger level) ;; turn logger back on
    (-> path stylesheet-parsed load-fonts))) ;; parse and load fonts

(Turning off logging doesn't work, for some reason).

The stylesheet is parsed with this:

(defn stylesheet-parsed [path]
  (.parse (CSSParser.) (cio/resource path)))

And finally the fonts are loaded with this:

(defn- load-fonts [^Stylesheet stylesheet]
  (doseq [^FontFace fontface (.getFontFaces stylesheet)]
    (doseq [^FontFace$FontFaceSrc ffsrc (.getSources fontface)]
      (let [src (-> ffsrc .getSrc (cs/replace "%20" " "))] ;; <- sanitizing path for Font/getFont
        (println "Loading font:" src)
        (let [f (Font/loadFont src 10.)]
          (println "Font loaded:" f))))))

This works just fine, and looks a lot like the original. An advantage is that here we don't check for type URL only, so we could theoretically extend it to handle @font-face more extensively.

Here is a more Clojure-y implementation of load-fonts which returns a list of all fonts loaded:

(defn- load-fontface-src [^FontFace$FontFaceSrc ffsrc]
  (-> ffsrc .getSrc (cs/replace "%20" " ") (Font/loadFont 10.)))

(defn- load-fontface [^FontFace ff]
  (map load-fontface-src (.getSources ff)))

(defn- load-fonts [^Stylesheet stylesheet]
  (vec (flatten (map load-fontface (.getFontFaces stylesheet)))))

And the imports needed:

(import
  '[com.sun.javafx.css.parser CSSParser]
  '[com.sun.javafx.css Stylesheet FontFace FontFace$FontFaceSrc]
  '[com.sun.javafx.util Logging]
  '[sun.util.logging PlatformLogger$Level])

TODO:
1. Turn of logging. (It is annoying, though only a problem in development.)
2. Test to see if any fonts were not loaded, and only then to the alternative parsing and loading. But probably the simply checking would require as much processing as actually loading the fonts an extra time.

FIX: added vec to the left of flatten, to ensure that lazy seqs are realized.

like image 55
Terje Dahl Avatar answered Oct 16 '22 15:10

Terje Dahl


I'm using the e(fx)clipse plugin for Eclipse, which does not recognize your CSS file as valid JavaFX CSS. I do not get the exception when I start the program however, it simply uses the default font.

With the following changes, the font is being loaded and displayed.

/**/
@font-face {
    font-family: Roboto; /* removed '' */
    src: url("Roboto-Thin.ttf");
}
#sampleLabel{
    -fx-font-family: Roboto ; /* added -fx- prefix */
}
like image 31
Prometheus Avatar answered Oct 16 '22 15:10

Prometheus


In my case this is produced by the '-' character in the font file name, replace this with a '_' and it works.

i identify that the font family must be the same file name but replacing all special characters ' ' (a blank space) and split the camel case words.

so:

before (no working):

@font-face {
    font-family: 'RifficFree Bold';
    src: url("../fonts/RifficFree-Bold.ttf");
}
.bingo-number, .label{
    -fx-font-family: 'RifficFree Bold';
}

after (working):

@font-face {
    font-family: 'Riffic Free Bold';
    src: url("../fonts/RifficFree_Bold.ttf");
}
.bingo-number, .label{
    -fx-font-family: 'Riffic Free Bold';
}
like image 1
Adrian Romero Avatar answered Oct 16 '22 14:10

Adrian Romero