Collins Abitekaniza
Collins Abitekaniza

Reputation: 4588

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.

Upvotes: 11

Views: 8785

Answers (6)

katanta
katanta

Reputation: 19

I found a solution on Reddit that worked for me. Here's the link: Reddit post

When defining the font family in the CSS stylesheet, make sure to use the exact name mentioned on the first line of the font file.

For example, if the first line says "Pixeloid Sans", the font family should be specified as follows:

-fx-font-family: "Pixeloid Sans";

I also removed the @font-face declaration, as it was unnecessary.

Lastly, I should mention that all of my .tff files are located in a folder within /resources.

Upvotes: 0

Adrian Romero
Adrian Romero

Reputation: 21

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';
}

Upvotes: 1

Fay Boisam
Fay Boisam

Reputation: 147

For those who - like me - still have this issue and do not want or know how to use Clojure, here is how to do it in Java only:
Bevore adding the stylesheet(s) to your scene, use Font.loadFont(getClass().getResourceAsStream([fontpath...]), [Some font-size, for example 12]);
The font will then be registered in JavaFX and you can use the -fx-font-family css-Property with the loaded font.

Upvotes: 0

Terje Dahl
Terje Dahl

Reputation: 982

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.

Upvotes: 1

Terje Dahl
Terje Dahl

Reputation: 982

I found the possible cause and a work-around: Under the hood the css-loader uses the function Font.loadFont to load the font-face in your CSS. Font.loadFont simply returns null if it fails, which give the "warning".

It seems that this function does not work with %20 it its path/url-string. So you need to resolve the path and then replace it with a space. That means you will have to load your fonts with code in stead of with CSS (for now).

In Clojure my work-around looks like this:

(require '[clojure.java.io :as cio])
(require '[clojure.string :as s])
(-> "fonts/SourceCodePro-Regular.ttf" 
  cio/resource 
  str 
  (s/replace "%20" " ") 
  (javafx.scene.text.Font/loadFont  10.))

;-)

Upvotes: 4

Prometheus
Prometheus

Reputation: 1015

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 */
}

Upvotes: 1

Related Questions