src/Pure/Tools/fontforge.scala
author paulson <lp15@cam.ac.uk>
Wed, 24 Apr 2024 20:56:26 +0100
changeset 80149 40a3fc07a587
parent 75394 42267c650205
permissions -rw-r--r--
More tidying of proofs
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
69328
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
     1
/*  Title:      Pure/Tools/fontforge.scala
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
     2
    Author:     Makarius
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
     3
69333
c889afca73a5 proper documentation;
wenzelm
parents: 69329
diff changeset
     4
Support for fontforge and its scripting language: see
c889afca73a5 proper documentation;
wenzelm
parents: 69329
diff changeset
     5
/usr/share/doc/fontforge/scripting.html e.g. on Ubuntu Linux installation.
69328
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
     6
*/
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
     7
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
     8
package isabelle
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
     9
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
    10
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
    11
import java.io.{File => JFile}
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
    12
import java.util.Locale
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
    13
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
    14
75393
87ebf5a50283 clarified formatting, for the sake of scala3;
wenzelm
parents: 71601
diff changeset
    15
object Fontforge {
69328
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
    16
  /** scripting language **/
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
    17
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
    18
  type Script = String
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
    19
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
    20
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
    21
  /* concrete syntax */
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
    22
75393
87ebf5a50283 clarified formatting, for the sake of scala3;
wenzelm
parents: 71601
diff changeset
    23
  def string(s: String): Script = {
69329
8bbde4dba926 tuned error;
wenzelm
parents: 69328
diff changeset
    24
    def err(c: Char): Nothing =
71163
b5822f4c3fde tuned -- avoid deprecated constructors;
wenzelm
parents: 69370
diff changeset
    25
      error("Bad character \\u" + String.format(Locale.ROOT, "%04x", Integer.valueOf(c)) +
69329
8bbde4dba926 tuned error;
wenzelm
parents: 69328
diff changeset
    26
        " in fontforge string " + quote(s))
69328
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
    27
69329
8bbde4dba926 tuned error;
wenzelm
parents: 69328
diff changeset
    28
    val q = if (s.contains('"')) '\'' else '"'
69328
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
    29
75393
87ebf5a50283 clarified formatting, for the sake of scala3;
wenzelm
parents: 71601
diff changeset
    30
    def escape(c: Char): String = {
69329
8bbde4dba926 tuned error;
wenzelm
parents: 69328
diff changeset
    31
      if (c == '\u0000' || c == '\r' || c == q) err(c)
69328
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
    32
      else if (c == '\n') "\\n"
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
    33
      else if (c == '\\') "\\\\"
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
    34
      else c.toString
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
    35
    }
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
    36
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
    37
    if (s.nonEmpty && s(0) == '\\') err('\\')
71601
97ccf48c2f0c misc tuning based on hints by IntelliJ IDEA;
wenzelm
parents: 71163
diff changeset
    38
    s.iterator.map(escape).mkString(q.toString, "", q.toString)
69328
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
    39
  }
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
    40
69333
c889afca73a5 proper documentation;
wenzelm
parents: 69329
diff changeset
    41
  def file_name(path: Path): Script = string(File.standard_path(path))
69328
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
    42
69333
c889afca73a5 proper documentation;
wenzelm
parents: 69329
diff changeset
    43
c889afca73a5 proper documentation;
wenzelm
parents: 69329
diff changeset
    44
  /* commands */
c889afca73a5 proper documentation;
wenzelm
parents: 69329
diff changeset
    45
69335
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
    46
  def command_list(cmds: List[String]): Script = cat_lines(cmds)
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
    47
  def commands(cmds: String*): Script = command_list(cmds.toList)
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
    48
69333
c889afca73a5 proper documentation;
wenzelm
parents: 69329
diff changeset
    49
  // fonts
c889afca73a5 proper documentation;
wenzelm
parents: 69329
diff changeset
    50
  def open(path: Path): Script = "Open(" + file_name(path) +")"
69335
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
    51
  def close: Script = "Close()"
69333
c889afca73a5 proper documentation;
wenzelm
parents: 69329
diff changeset
    52
  def generate(path: Path): Script = "Generate(" + file_name(path) +")"
c889afca73a5 proper documentation;
wenzelm
parents: 69329
diff changeset
    53
c889afca73a5 proper documentation;
wenzelm
parents: 69329
diff changeset
    54
  // selection
c889afca73a5 proper documentation;
wenzelm
parents: 69329
diff changeset
    55
  def select_all: Script = "SelectAll()"
c889afca73a5 proper documentation;
wenzelm
parents: 69329
diff changeset
    56
  def select_none: Script = "SelectNone()"
c889afca73a5 proper documentation;
wenzelm
parents: 69329
diff changeset
    57
  def select_invert: Script = "SelectInvert()"
69335
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
    58
  def select(args: Seq[Int]): Script =
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
    59
    command_list(select_none :: args.toList.map(code => "SelectMoreSingletons(" + code + ")"))
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
    60
69333
c889afca73a5 proper documentation;
wenzelm
parents: 69329
diff changeset
    61
  def clear: Script = "Clear()"
c889afca73a5 proper documentation;
wenzelm
parents: 69329
diff changeset
    62
  def copy: Script = "Copy()"
c889afca73a5 proper documentation;
wenzelm
parents: 69329
diff changeset
    63
  def paste: Script = "Paste()"
c889afca73a5 proper documentation;
wenzelm
parents: 69329
diff changeset
    64
c889afca73a5 proper documentation;
wenzelm
parents: 69329
diff changeset
    65
c889afca73a5 proper documentation;
wenzelm
parents: 69329
diff changeset
    66
c889afca73a5 proper documentation;
wenzelm
parents: 69329
diff changeset
    67
  /** execute fontforge program **/
69328
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
    68
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
    69
  def execute(script: Script, args: String = "", cwd: JFile = null): Process_Result =
75394
42267c650205 tuned formatting;
wenzelm
parents: 75393
diff changeset
    70
    Isabelle_System.with_tmp_file("fontforge") { script_file =>
69328
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
    71
      File.write(script_file, script)
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
    72
      Isabelle_System.bash(File.bash_path(Path.explode("$ISABELLE_FONTFORGE")) +
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
    73
        " -lang=ff -script " + File.bash_path(script_file) + " " + args)
75394
42267c650205 tuned formatting;
wenzelm
parents: 75393
diff changeset
    74
    }
69333
c889afca73a5 proper documentation;
wenzelm
parents: 69329
diff changeset
    75
75393
87ebf5a50283 clarified formatting, for the sake of scala3;
wenzelm
parents: 71601
diff changeset
    76
  def font_domain(path: Path, strict: Boolean = false): List[Int] = {
69335
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
    77
    val script =
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
    78
      commands(
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
    79
        open(path),
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
    80
        "i = 0",
69370
589896fe1df2 more robust: enforce Unicode range;
wenzelm
parents: 69335
diff changeset
    81
        "while (i < CharCnt() && i < 0x110000)",
69335
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
    82
        "  if (" + (if (strict) "DrawsSomething" else "WorthOutputting") + "(i)); Print(i); endif",
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
    83
        "  i = i + 1",
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
    84
        "endloop",
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
    85
        close)
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
    86
    Library.trim_split_lines(execute(script).check.out).map(Value.Int.parse)
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
    87
  }
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
    88
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
    89
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
    90
  /* font names */
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
    91
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
    92
  sealed case class Font_Names(
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
    93
    fontname: String = "",
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
    94
    familyname: String = "",
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
    95
    fullname: String = "",
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
    96
    weight: String = "",
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
    97
    copyright: String = "",
75393
87ebf5a50283 clarified formatting, for the sake of scala3;
wenzelm
parents: 71601
diff changeset
    98
    fontversion: String = ""
87ebf5a50283 clarified formatting, for the sake of scala3;
wenzelm
parents: 71601
diff changeset
    99
  ) {
69335
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   100
    override def toString: String = fontname
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   101
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   102
    def ttf: Path = Path.explode(fontname).ext("ttf")
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   103
75393
87ebf5a50283 clarified formatting, for the sake of scala3;
wenzelm
parents: 71601
diff changeset
   104
    def update(prefix: String = "", version: String = ""): Font_Names = {
69335
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   105
      val fontversion1 = proper_string(version) getOrElse fontversion
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   106
      if (prefix == "") copy(fontversion = fontversion1)
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   107
      else {
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   108
        copy(fontname = prefix + fontname,
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   109
          familyname = prefix + " " + familyname,
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   110
          fullname = prefix + " " + fullname,
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   111
          weight = weight,
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   112
          copyright = copyright,
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   113
          fontversion = fontversion1)
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   114
      }
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   115
    }
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   116
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   117
    def set: Script =
71601
97ccf48c2f0c misc tuning based on hints by IntelliJ IDEA;
wenzelm
parents: 71163
diff changeset
   118
      List(fontname, familyname, fullname, weight, copyright, fontversion).map(string).
69335
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   119
        mkString("SetFontNames(", ",", ")")
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   120
  }
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   121
75393
87ebf5a50283 clarified formatting, for the sake of scala3;
wenzelm
parents: 71601
diff changeset
   122
  def font_names(path: Path): Font_Names = {
69335
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   123
    val script =
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   124
      commands(
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   125
        open(path),
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   126
        "Print($fontname)",
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   127
        "Print($familyname)",
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   128
        "Print($fullname)",
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   129
        "Print($weight)",
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   130
        "Print($fontversion)",
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   131
        "Print($copyright)",
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   132
        close)
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   133
    Library.trim_split_lines(execute(script).check.out) match {
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   134
      case fontname :: familyname :: fullname :: weight :: fontversion :: copyright =>
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   135
        Font_Names(fontname, familyname, fullname, weight, cat_lines(copyright), fontversion)
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   136
      case res => error(cat_lines("Bad font names: " :: res))
76c8beaf3bab more operations;
wenzelm
parents: 69334
diff changeset
   137
    }
69333
c889afca73a5 proper documentation;
wenzelm
parents: 69329
diff changeset
   138
  }
69328
4646fcb59121 support for fontforge and its scripting language;
wenzelm
parents:
diff changeset
   139
}