src/Tools/jEdit/src/rich_text_area.scala
changeset 73884 0a12ca4f3e8d
parent 73883 994c9dacd2f9
child 75393 87ebf5a50283
equal deleted inserted replaced
73883:994c9dacd2f9 73884:0a12ca4f3e8d
     8 package isabelle.jedit
     8 package isabelle.jedit
     9 
     9 
    10 
    10 
    11 import isabelle._
    11 import isabelle._
    12 
    12 
    13 import java.awt.{Graphics2D, Shape, Color, Point, Cursor, MouseInfo}
    13 import java.awt.{Graphics2D, Shape, Color, Point, Cursor, MouseInfo, Font}
    14 import java.awt.event.{MouseMotionAdapter, MouseAdapter, MouseEvent,
    14 import java.awt.event.{MouseMotionAdapter, MouseAdapter, MouseEvent,
    15   FocusAdapter, FocusEvent, WindowEvent, WindowAdapter, KeyEvent}
    15   FocusAdapter, FocusEvent, WindowEvent, WindowAdapter, KeyEvent}
    16 import java.awt.font.TextAttribute
    16 import java.awt.font.TextAttribute
    17 import javax.swing.SwingUtilities
    17 import javax.swing.SwingUtilities
    18 import java.text.AttributedString
    18 import java.text.AttributedString
   402         rendering.caret_debugger_color
   402         rendering.caret_debugger_color
   403       else rendering.caret_invisible_color
   403       else rendering.caret_invisible_color
   404     }
   404     }
   405   }
   405   }
   406 
   406 
   407   private def reset_subst_font(): Unit =
   407   private class Font_Subst
   408   {
   408   {
   409     val field = classOf[Chunk].getDeclaredField("lastSubstFont")
   409     private var cache = Map.empty[Int, Option[Font]]
   410     field.setAccessible(true)
   410 
   411     field.set(null, null)
   411     def get(codepoint: Int): Option[Font] =
   412   }
   412       cache.getOrElse(codepoint,
   413 
   413         {
   414   private def paint_chunk_list(rendering: JEdit_Rendering,
   414           val field = classOf[Chunk].getDeclaredField("lastSubstFont")
       
   415           field.setAccessible(true)
       
   416           field.set(null, null)
       
   417           val res = Option(Chunk.getSubstFont(codepoint))
       
   418           cache += (codepoint -> res)
       
   419           res
       
   420         })
       
   421   }
       
   422 
       
   423   private def paint_chunk_list(rendering: JEdit_Rendering, font_subst: Font_Subst,
   415     gfx: Graphics2D, line_start: Text.Offset, head: Chunk, x: Float, y: Float): Float =
   424     gfx: Graphics2D, line_start: Text.Offset, head: Chunk, x: Float, y: Float): Float =
   416   {
   425   {
   417     val clip_rect = gfx.getClipBounds
   426     val clip_rect = gfx.getClipBounds
   418 
   427 
   419     val caret_range =
   428     val caret_range =
   420       if (caret_enabled) JEdit_Lib.caret_range(text_area)
   429       if (caret_enabled) JEdit_Lib.caret_range(text_area)
   421       else Text.Range.offside
   430       else Text.Range.offside
   422 
       
   423     reset_subst_font()
       
   424 
   431 
   425     var w = 0.0f
   432     var w = 0.0f
   426     var chunk = head
   433     var chunk = head
   427     while (chunk != null) {
   434     while (chunk != null) {
   428       val chunk_offset = line_start + chunk.offset
   435       val chunk_offset = line_start + chunk.offset
   448         chunk_text.addAttribute(TextAttribute.RUN_DIRECTION, TextAttribute.RUN_DIRECTION_LTR)
   455         chunk_text.addAttribute(TextAttribute.RUN_DIRECTION, TextAttribute.RUN_DIRECTION_LTR)
   449         chunk_text.addAttribute(TextAttribute.FONT, chunk_font)
   456         chunk_text.addAttribute(TextAttribute.FONT, chunk_font)
   450         if (chunk.usedFontSubstitution) {
   457         if (chunk.usedFontSubstitution) {
   451           for {
   458           for {
   452             (c, i) <- Codepoint.iterator_offset(chunk_str) if !chunk_font.canDisplay(c)
   459             (c, i) <- Codepoint.iterator_offset(chunk_str) if !chunk_font.canDisplay(c)
   453             _ = reset_subst_font()
   460             subst_font <- font_subst.get(c)
   454             subst_font = Chunk.getSubstFont(c) if subst_font != null
       
   455           } {
   461           } {
   456             val r = Text.Range(i, i + Character.charCount(c)) + chunk_offset
   462             val r = Text.Range(i, i + Character.charCount(c)) + chunk_offset
   457             val font = Chunk.deriveSubstFont(chunk_font, subst_font)
   463             val font = Chunk.deriveSubstFont(chunk_font, subst_font)
   458             chunk_attrib(TextAttribute.FONT, font, r)
   464             chunk_attrib(TextAttribute.FONT, font, r)
   459           }
   465           }
   500           val w = fm.charWidth(' ')
   506           val w = fm.charWidth(' ')
   501           val b = (w / 2) max 1
   507           val b = (w / 2) max 1
   502           val c = (lm.getAscent + lm.getStrikethroughOffset).round
   508           val c = (lm.getAscent + lm.getStrikethroughOffset).round
   503           ((w - b + 1) / 2, c - b / 2, w - b, line_height - b)
   509           ((w - b + 1) / 2, c - b / 2, w - b, line_height - b)
   504         }
   510         }
       
   511 
       
   512         val font_subst = new Font_Subst
   505 
   513 
   506         for (i <- physical_lines.indices) {
   514         for (i <- physical_lines.indices) {
   507           val line = physical_lines(i)
   515           val line = physical_lines(i)
   508           if (line != -1) {
   516           if (line != -1) {
   509             val line_range = Text.Range(start(i), end(i) min buffer.getLength)
   517             val line_range = Text.Range(start(i), end(i) min buffer.getLength)
   513             val chunks = text_area.getChunksOfScreenLine(screen_line)
   521             val chunks = text_area.getChunksOfScreenLine(screen_line)
   514             if (chunks != null) {
   522             if (chunks != null) {
   515               try {
   523               try {
   516                 val line_start = buffer.getLineStartOffset(line)
   524                 val line_start = buffer.getLineStartOffset(line)
   517                 gfx.clipRect(x0, y + line_height * i, Integer.MAX_VALUE, line_height)
   525                 gfx.clipRect(x0, y + line_height * i, Integer.MAX_VALUE, line_height)
   518                 val w = paint_chunk_list(rendering, gfx, line_start, chunks, x0.toFloat, y0.toFloat)
   526                 val w =
       
   527                   paint_chunk_list(rendering, font_subst, gfx,
       
   528                     line_start, chunks, x0.toFloat, y0.toFloat)
   519                 gfx.clipRect(x0 + w.toInt, 0, Integer.MAX_VALUE, Integer.MAX_VALUE)
   529                 gfx.clipRect(x0 + w.toInt, 0, Integer.MAX_VALUE, Integer.MAX_VALUE)
   520                 orig_text_painter.paintValidLine(gfx,
   530                 orig_text_painter.paintValidLine(gfx,
   521                   screen_line, line, start(i), end(i), y + line_height * i)
   531                   screen_line, line, start(i), end(i), y + line_height * i)
   522               } finally { gfx.setClip(clip) }
   532               } finally { gfx.setClip(clip) }
   523             }
   533             }