more systematic treatment of internal state, which belongs strictly to the main actor, not the Swing thread;
authorwenzelm
Fri, 21 May 2010 11:16:01 +0200
changeset 370419640f6546179
parent 37040 0e4073f19825
child 37042 4834c3112788
more systematic treatment of internal state, which belongs strictly to the main actor, not the Swing thread;
do not re-use mutable DOM -- avoid races wrt. the rendering engine;
more thorough resize -- always recalculate metrics/margin synchronously;
asynchronous setDocument;
tuned;
src/Tools/jEdit/src/jedit/html_panel.scala
     1.1 --- a/src/Tools/jEdit/src/jedit/html_panel.scala	Fri May 21 11:12:54 2010 +0200
     1.2 +++ b/src/Tools/jEdit/src/jedit/html_panel.scala	Fri May 21 11:16:01 2010 +0200
     1.3 @@ -42,13 +42,15 @@
     1.4    initial_font_size: Int,
     1.5    handler: PartialFunction[HTML_Panel.Event, Unit]) extends HtmlPanel
     1.6  {
     1.7 -  // global logging
     1.8 +  /** Lobo setup **/
     1.9 +
    1.10 +  /* global logging */
    1.11 +
    1.12    Logger.getLogger("org.lobobrowser").setLevel(Level.WARNING)
    1.13  
    1.14  
    1.15 -  /* Lobo setup */
    1.16 +  /* pixel size -- cf. org.lobobrowser.html.style.HtmlValues.getFontSize */
    1.17  
    1.18 -  // pixel size -- cf. org.lobobrowser.html.style.HtmlValues.getFontSize
    1.19    val screen_resolution =
    1.20      if (GraphicsEnvironment.isHeadless()) 72
    1.21      else Toolkit.getDefaultToolkit().getScreenResolution()
    1.22 @@ -106,26 +108,37 @@
    1.23      template_tail
    1.24  
    1.25  
    1.26 -  /* physical document */
    1.27 +  /** main actor **/
    1.28  
    1.29 -  private class Doc
    1.30 -  {
    1.31 -    private var current_font_size: Int = 0
    1.32 -    private var current_font_metrics: FontMetrics = null
    1.33 -    private var current_body: List[XML.Tree] = Nil
    1.34 -    private var current_DOM: org.w3c.dom.Document = null
    1.35 +  /* internal messages */
    1.36 +
    1.37 +  private case class Resize(font_size: Int)
    1.38 +  private case class Render(body: List[XML.Tree])
    1.39 +  private case object Refresh
    1.40 +
    1.41 +  private val main_actor = actor {
    1.42 +
    1.43 +    /* internal state */
    1.44 +
    1.45 +    var current_font_metrics: FontMetrics = null
    1.46 +    var current_font_size: Int = 0
    1.47 +    var current_margin: Int = 0
    1.48 +    var current_body: List[XML.Tree] = Nil
    1.49  
    1.50      def resize(font_size: Int)
    1.51      {
    1.52 -      if (font_size != current_font_size || current_font_metrics == null) {
    1.53 +      val (font_metrics, margin) =
    1.54          Swing_Thread.now {
    1.55 -          current_font_size = font_size
    1.56 -          current_font_metrics =
    1.57 -            getFontMetrics(system.get_font(lobo_px(raw_px(font_size))))
    1.58 +          val metrics = getFontMetrics(system.get_font(lobo_px(raw_px(font_size))))
    1.59 +          (metrics, (getWidth() / (metrics.charWidth(Symbol.spc) max 1) - 4) max 20)
    1.60          }
    1.61 -        current_DOM =
    1.62 -          builder.parse(
    1.63 -            new InputSourceImpl(new StringReader(template(font_size)), "http://localhost"))
    1.64 +      if (current_font_metrics == null ||
    1.65 +          current_font_size != font_size ||
    1.66 +          current_margin != margin)
    1.67 +      {
    1.68 +        current_font_metrics = font_metrics
    1.69 +        current_font_size = font_size
    1.70 +        current_margin = margin
    1.71          refresh()
    1.72        }
    1.73      }
    1.74 @@ -135,43 +148,36 @@
    1.75      def render(body: List[XML.Tree])
    1.76      {
    1.77        current_body = body
    1.78 -      val margin = (getWidth() / (current_font_metrics.charWidth(Symbol.spc) max 1) - 4) max 20
    1.79        val html_body =
    1.80          current_body.flatMap(div =>
    1.81 -          Pretty.formatted(List(div), margin,
    1.82 -              Pretty.font_metric(current_font_metrics))
    1.83 +          Pretty.formatted(List(div), current_margin, Pretty.font_metric(current_font_metrics))
    1.84              .map(t => XML.elem(HTML.PRE, HTML.spans(t))))
    1.85 -
    1.86 -      val node = XML.document_node(current_DOM, XML.elem(HTML.BODY, html_body))
    1.87 -      Swing_Thread.now {
    1.88 -        current_DOM.removeChild(current_DOM.getLastChild())
    1.89 -        current_DOM.appendChild(node)
    1.90 -        setDocument(current_DOM, rcontext)
    1.91 -      }
    1.92 +      val doc =
    1.93 +        builder.parse(
    1.94 +          new InputSourceImpl(new StringReader(template(current_font_size)), "http://localhost"))
    1.95 +      doc.removeChild(doc.getLastChild())
    1.96 +      doc.appendChild(XML.document_node(doc, XML.elem(HTML.BODY, html_body)))
    1.97 +      Swing_Thread.later { setDocument(doc, rcontext) }
    1.98      }
    1.99  
   1.100 +
   1.101 +    /* main loop */
   1.102 +
   1.103      resize(initial_font_size)
   1.104 -  }
   1.105  
   1.106 -
   1.107 -  /* main actor and method wrappers */
   1.108 -
   1.109 -  private case class Resize(font_size: Int)
   1.110 -  private case class Render(body: List[XML.Tree])
   1.111 -  private case object Refresh
   1.112 -
   1.113 -  private val main_actor = actor {
   1.114 -    var doc = new Doc
   1.115      loop {
   1.116        react {
   1.117 -        case Resize(font_size) => doc.resize(font_size)
   1.118 -        case Refresh => doc.refresh()
   1.119 -        case Render(body) => doc.render(body)
   1.120 +        case Resize(font_size) => resize(font_size)
   1.121 +        case Refresh => refresh()
   1.122 +        case Render(body) => render(body)
   1.123          case bad => System.err.println("main_actor: ignoring bad message " + bad)
   1.124        }
   1.125      }
   1.126    }
   1.127  
   1.128 +
   1.129 +  /* external methods */
   1.130 +
   1.131    def resize(font_size: Int) { main_actor ! Resize(font_size) }
   1.132    def refresh() { main_actor ! Refresh }
   1.133    def render(body: List[XML.Tree]) { main_actor ! Render(body) }