src/Pure/Tools/isabelle_fonts.scala
changeset 69336 14444ea196a0
parent 69332 85ccc983748c
child 69337 aa94b3b5aa0b
--- a/src/Pure/Tools/isabelle_fonts.scala	Fri Nov 23 21:47:35 2018 +0100
+++ b/src/Pure/Tools/isabelle_fonts.scala	Fri Nov 23 21:50:50 2018 +0100
@@ -13,11 +13,10 @@
 
   object Range
   {
-    def plain_text: Seq[Int] =
+    def base_font: Seq[Int] =
       (0x0020 to 0x007e) ++  // ASCII
       (0x00a0 to 0x024f) ++  // Latin Extended-A/B
       (0x0400 to 0x04ff) ++  // Cyrillic
-      (0x0590 to 0x05ff) ++  // Hebrew (non-mono)
       (0x0600 to 0x06ff) ++  // Arabic
       Seq(
         0x2018,  // single quote
@@ -35,7 +34,7 @@
         0xfffd,  // replacement character
       )
 
-    def symbols: Seq[Int] =
+    def isabelle_font: Seq[Int] =
       Seq(
         0x05,  // X
         0x06,  // Y
@@ -49,6 +48,7 @@
         0xf7,  // divide
       ) ++
       (0x0370 to 0x03ff) ++  // Greek (pseudo math)
+      (0x0590 to 0x05ff) ++  // Hebrew (non-mono)
       Seq(
         0x2010,  // hyphen
         0x2013,  // dash
@@ -115,18 +115,30 @@
     plain: String = "",
     bold: String = "",
     italic: String = "",
-    bold_italic: String = "",
-    fallback: Option[Family] = None)
+    bold_italic: String = "")
+  {
+    val fonts: List[String] =
+      proper_string(plain).toList :::
+      proper_string(bold).toList :::
+      proper_string(italic).toList :::
+      proper_string(bold_italic).toList
+
+    def get(index: Int): String = fonts(index % fonts.length)
+  }
 
   object Family
   {
+    def isabelle_text: Family =
+      Family(
+        plain = "IsabelleText.sfd",
+        bold = "IsabelleTextBold.sfd")
+
     def deja_vu_sans_mono: Family =
       Family(
         plain = "DejaVuSansMono.ttf",
         bold = "DejaVuSansMono-Bold.ttf",
         italic = "DejaVuSansMono-Oblique.ttf",
-        bold_italic = "DejaVuSansMono-BoldOblique.ttf",
-        fallback = Some(deja_vu_sans))
+        bold_italic = "DejaVuSansMono-BoldOblique.ttf")
 
     def deja_vu_sans: Family =
       Family(
@@ -142,4 +154,83 @@
         italic = "DejaVuSerif-Italic.ttf",
         bold_italic = "DejaVuSerif-BoldItalic.ttf")
   }
+
+
+  /* build fonts */
+
+  private def find_file(dirs: List[Path], name: String): Path =
+  {
+    val path = Path.explode(name)
+    dirs.collectFirst({ case dir if (dir + path).is_file => dir + path }) match {
+      case Some(file) => file
+      case None =>
+        error(cat_lines(
+          ("Failed to find font file " + path + " in directories:") ::
+            dirs.map(dir => "  " + dir.toString)))
+    }
+  }
+
+  val default_sources: List[Family] =
+    List(Family.deja_vu_sans_mono, Family.deja_vu_sans, Family.deja_vu_serif)
+
+  def build_fonts(
+    sources: List[Family] = default_sources,
+    source_dirs: List[Path] = Nil,
+    target_prefix: String = "Isabelle",
+    target_version: String = "",
+    target_dir: Path = Path.current,
+    progress: Progress = No_Progress)
+  {
+    Isabelle_System.mkdirs(target_dir)
+
+    val font_dirs = source_dirs ::: List(Path.explode("~~/lib/fonts"))
+
+    for (isabelle_font <- Family.isabelle_text.fonts) {
+      val isabelle_file = find_file(font_dirs, isabelle_font)
+      val isabelle_names = Fontforge.font_names(isabelle_file)
+
+      val target_names = isabelle_names.update(version = target_version)
+      val target_file = target_dir + target_names.ttf
+
+      progress.echo("Creating " + target_file.toString + " ...")
+      Fontforge.execute(
+        Fontforge.commands(
+          Fontforge.open(isabelle_file),
+          target_names.set,
+          Fontforge.generate(target_file),
+          Fontforge.close
+        )
+      ).check
+    }
+
+    for { source <- sources; (source_font, index) <- source.fonts.zipWithIndex } {
+      val isabelle_file = find_file(font_dirs, Family.isabelle_text.get(index))
+
+      val source_file = find_file(font_dirs, source_font)
+      val source_names = Fontforge.font_names(source_file)
+
+      val target_names = source_names.update(prefix = target_prefix, version = target_version)
+      val target_file = target_dir + target_names.ttf
+
+      progress.echo("Creating " + target_file.toString + " ...")
+      Fontforge.execute(
+        Fontforge.commands(
+          Fontforge.open(isabelle_file),
+          Fontforge.select(Range.isabelle_font),
+          Fontforge.copy,
+          Fontforge.close,
+
+          Fontforge.open(source_file),
+          Fontforge.select(Range.base_font),
+          Fontforge.select_invert,
+          Fontforge.clear,
+          Fontforge.select(Range.isabelle_font),
+          Fontforge.paste,
+
+          target_names.set,
+          Fontforge.generate(target_file),
+          Fontforge.close)
+      ).check
+    }
+  }
 }