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 } |