   (eval-str "function parseFont(payload) { return opentype.parse(b64.decode(payload)); }")
   (swap! parsefont (fn [old-parsefont] (.get @scope "parseFont"))))
 
-(defn bootstrap-rhino-if-needed []
+(defn- bootstrap-rhino-if-needed []
   (when-not @cx (run-js-thread bootstrap-rhino)))
 
-(defn load-font [filename]
-  (if-not (get @fonts filename)
-    (let [font-bytes (FileUtils/readFileToByteArray (File. filename))
+(defn- load-font [filename]
+  (if-not (get @fonts (.getName filename))
+    (let [font-bytes (FileUtils/readFileToByteArray filename)
           font-b64 (String. (base64/encode-bytes font-bytes))]
       (run-js-thread (fn []
                        (swap! fonts (fn [old-fonts]
-                                      (println "loading font" filename)
-                                      (assoc old-fonts filename (.call @parsefont @cx @scope @scope (object-array [font-b64])))))))
+                                      #_(println "loading font" (.getName filename))
+                                      (assoc old-fonts (.getName filename) (.call @parsefont @cx @scope @scope (object-array [font-b64])))))))
       :done)
     :already-loaded))
 
-(defn load-fonts []
+(defn- load-fonts []
   (bootstrap-rhino-if-needed)
-  (doall (map load-font ["./resources/fonts/Roboto-Black.ttf"
-                         "./resources/fonts/Roboto-Regular.ttf"])))
+  (doall (map load-font (->> (file-seq (File. "./resources/fonts"))
+                             (filter #(.endsWith (.getName %) ".ttf"))))))
 
-;
-;(defn js-to-clj [x]
-;  (zipmap (map keyword (keys x)) (vals x)))
-;
-;
+(defn- property-ids [obj]
+  (vec (run-js-thread #(NativeObject/getPropertyIds obj))))
+
+(defn- get-property [obj prop]
+  (run-js-thread #(NativeObject/getProperty obj prop)))
+
+(defn- font-fullname [font]
+  (let [names (get-property font "names")
+        fullnames (vals (get names "fullName"))]
+    (if (= 1 (count fullnames))
+      (first fullnames)
+      (throw (Exception. (str "No support for multiple fontnames:" fullnames))))))
+
+(defn- make-font-names-map []
+  (load-fonts)
+  (reduce (fn [o font]
+            (update o (font-fullname font)
+                    (fn [old-value]
+                      (if old-value
+                        (throw (Exception. (str "Duplicate font " old-value)))
+                        font)))) {} (vals @fonts)))
+
+(defonce font-name-to-font (make-font-names-map))
+
+(defn get-path-data [fontname text x y size]
+  {:pre [(some #{fontname} (keys font-name-to-font))]}
+  (run-js-thread (fn []
+                   (let [font (get font-name-to-font fontname)
+                         get-path (NativeObject/getProperty font "getPath")
+                         path (.call get-path @cx @scope font (object-array [text x y size]))
+                         to-path-data-fn (NativeObject/getProperty path "toPathData")
+                         path-data (.call to-path-data-fn @cx @scope path (object-array []))]
+                     path-data))))
 
 #_(defn get-path
     [text size]

                        (println "error in js-loop ..." (.getMessage e))
                        (async/>!! exception e)))))))

(defonce js-loop-thread (js-loop))

(defn run-js-thread [f]
  (async/>!! input f)
  (let [[result ch] (async/alts!! [output exception])]
    (if (= ch exception)
      (throw result)
      result)))

;;; ;;; ;;; STATE
(defonce cx (atom nil))

(defonce output (async/chan))
(defonce exception (async/chan))

(defn- js-handle [fn] (fn))

(defn- js-loop []
  (async/thread (while true
                  (let [fn (async/<!! input)]
                    (try
