1010import  java .nio .file .Files ;
1111import  java .nio .file .InvalidPathException ;
1212import  java .nio .file .Path ;
13+ import  java .nio .file .Paths ;
1314import  java .util .Base64 ;
1415import  java .util .Optional ;
1516import  java .util .concurrent .atomic .AtomicReference ;
@@ -84,8 +85,6 @@ In general, use additionalCssToLoad(), to also ensure file existence checks are
8485     */ 
8586    private  final  String  cssPathString ;
8687    @ SuppressWarnings ("OptionalUsedAsFieldOrParameterType" )
87-     private  final  Optional <Path > cssPath ;
88-     @ SuppressWarnings ("OptionalUsedAsFieldOrParameterType" )
8988    private  final  Optional <URL > cssUrl ;
9089
9190    private  final  AtomicReference <Optional <String >> cssDataUrlString  = new  AtomicReference <>(Optional .empty ());
@@ -100,60 +99,33 @@ public Theme(String path, PreferencesService preferencesService) {
10099            // Light theme 
101100            this .type  = Type .LIGHT ;
102101            this .cssUrl  = Optional .empty ();
103-             this .cssPath  = Optional .empty ();
104102        } else  {
105103            URL  url  = JabRefFrame .class .getResource (path );
106104            if  (url  != null ) {
107105                // Embedded dark theme 
108106                this .type  = Type .DARK ;
109-                 this .cssPath  = Optional .empty ();
110-                 this .cssUrl  = Optional .of (url );
111107            } else  {
112108                // Custom theme 
113109                this .type  = Type .CUSTOM ;
114-                 this .cssPath  = cssStringToPath (path );
115-                 // note that for an invalid path, the url will also be empty here: 
116-                 this .cssUrl  = cssPath .map (Theme ::cssPathToUrl );
110+ 
111+                 try  {
112+                     url  = Path .of (path ).toUri ().toURL ();
113+                 } catch  (InvalidPathException  e ) {
114+                     LOGGER .warn ("Cannot load additional css {} because it is an invalid path: {}" , path , e .getLocalizedMessage ());
115+                     url  = null ;
116+                 } catch  (MalformedURLException  e ) {
117+                     LOGGER .warn ("Cannot load additional css url {} because it is a malformed url: {}" , path , e .getLocalizedMessage ());
118+                     url  = null ;
119+                 }
117120            }
118121
119-             LOGGER . debug ( "Theme is {}, additional css path is {},  url is {}" , 
120-                      this .type ,  cssPath . orElse ( null ) , cssUrl .orElse (null ));
122+             this . cssUrl  =  Optional . ofNullable ( url ); 
123+             LOGGER . debug ( "Theme is {}, additional css url is {}" ,  this .type , cssUrl .orElse (null ));
121124        }
122125
123126        additionalCssToLoad ().ifPresent (this ::loadCssToMemory );
124127    }
125128
126-     /** 
127-      * Creates a Path from a path String 
128-      * 
129-      * @param pathString the path string 
130-      * @return the path on the default file system, or empty if not valid for that file system (e.g. bad characters) 
131-      */ 
132-     private  static  Optional <Path > cssStringToPath (String  pathString ) {
133-         try  {
134-             return  Optional .of (Path .of (pathString ));
135-         } catch  (InvalidPathException  e ) {
136-             LOGGER .warn ("Cannot load additional css {} because it is an invalid path: {}" , pathString , e .getLocalizedMessage ());
137-             return  Optional .empty ();
138-         }
139-     }
140- 
141-     /** 
142-      * Creates a URL from a file system path. The scheme of the URL depends on the file system provider, but it will 
143-      * generally be 
144-      * 
145-      * @param path the file system path 
146-      * @return the URL for that file system path 
147-      */ 
148-     private  static  URL  cssPathToUrl (Path  path ) {
149-         try  {
150-             return  path .toUri ().toURL ();
151-         } catch  (MalformedURLException  e ) {
152-             LOGGER .warn ("Cannot load additional css url {} because it is a malformed url: {}" , path , e .getLocalizedMessage ());
153-             return  null ;
154-         }
155-     }
156- 
157129    /** 
158130     * Returns the additional CSS file or resource, after checking that it is accessible. 
159131     * 
@@ -163,34 +135,43 @@ private static URL cssPathToUrl(Path path) {
163135     * @return an optional providing the URL of the CSS file/resource, or empty 
164136     */ 
165137    private  Optional <URL > additionalCssToLoad () {
166-         // When we have a valid file system path, check that the CSS file is readable 
167-         if  (cssPath .isPresent ()) {
168-             Path  path  = cssPath .get ();
169- 
170-             if  (!Files .exists (path )) {
171-                 LOGGER .warn ("Not loading additional css file {} because it could not be found" , cssPath .get ());
172-                 return  Optional .empty ();
173-             }
138+         // Check external sources of CSS to make sure they are available: 
139+         if  (isAdditionalCssExternal ()) {
140+             Optional <Path > cssPath  = cssUrl .map (url  -> Paths .get (URI .create (url .toExternalForm ())));
141+             // No need to return explicitly return Optional.empty() if Path is invalid; the URL will be empty anyway 
142+             if  (cssPath .isPresent ()) {
143+                 // When we have a valid file system path, check that the CSS file is readable 
144+                 Path  path  = cssPath .get ();
145+ 
146+                 if  (!Files .exists (path )) {
147+                     LOGGER .warn ("Not loading additional css file {} because it could not be found" , cssPath .get ());
148+                     return  Optional .empty ();
149+                 }
174150
175-             if  (Files .isDirectory (path )) {
176-                 LOGGER .warn ("Not loading additional css file {} because it is a directory" , cssPath .get ());
177-                 return  Optional .empty ();
151+                 if  (Files .isDirectory (path )) {
152+                     LOGGER .warn ("Not loading additional css file {} because it is a directory" , cssPath .get ());
153+                     return  Optional .empty ();
154+                 }
178155            }
179156        }
180157
181158        return  cssUrl ;
182159    }
183160
161+     private  boolean  isAdditionalCssExternal () {
162+         return  cssUrl .isPresent () && "file" .equals (cssUrl .get ().getProtocol ());
163+     }
164+ 
184165    /** 
185166     * Creates a data-embedded URL from a file (or resource) URL. 
186167     * 
187168     * TODO: this is only desirable for file URLs, as protection against the file being removed (see 
188169     *       {@link #MAX_IN_MEMORY_CSS_LENGTH} for details). However, there is a bug in OpenJFX, in that it does not 
189170     *       recognise jrt URLs (modular java runtime URLs). This is detailed in 
190171     *       <a href="https://bugs.openjdk.java.net/browse/JDK-8240969">JDK-8240969</a>. 
191-      *       When we upgrade to OpenJFX 16, we should limit loadCssToMemory to only  URLs where the protocol is equal  
192-      *       to file, using  {@link URL#getProtocol ()}. Also rename to loadFileCssToMemory () and reword the 
193-      *      javadoc, for clarity. 
172+      *       When we upgrade to OpenJFX 16, we should limit loadCssToMemory to external  URLs i.e. check  
173+      *       {@link #isAdditionalCssExternal ()}. Also rename to loadExternalCssToMemory () and reword the 
174+      *        javadoc, for clarity. 
194175     * 
195176     * @param url the URL of the resource to convert into a data: url 
196177     */ 
0 commit comments