言語ゲーム

とあるエンジニアが嘘ばかり書く日記

Twitter: @propella

Squeak の ParagraphEditor 再び

テキストをに画面表示するために、長く伸びた行を画面に収まるよう途中で回り込ませる処理が必要だ。そこん所を調べてみた。表示関連をデバッガで追いかけるには下手にブレークポイントを仕込めないので、注意深く実験。

  • 描画のデバッグ
    • Workspace を開ける
    • 同じ所で何度かハロを出し TextMorphForEditView をインスペクト
    • インスペクタで self drawOn: Display getCanvas をデバッグ
  • 編集のデバッグ
    • ParagraphEditor>>printIt (Crtl+Shift+I) などの致命的でない機能に halt を仕込む。

行の横幅を決めるには、一文字一文字の横幅を順に足して行って、幅が一杯になるまで埋めなくてはいけない。解析の単位はスペースやタブ、改行などの空白文字 scanCharactersFrom:to:in:rightX:stopConditions:kern: CompositionScanner が解析結果に応じて適切な処理をする。例えば物理改行の前にスペースがあった場合、 CompositionScanner はそこですぐ改行せずに、以前のスペース位置で改行を行う。

print it から横幅を決めるまでのスタックフレーム

  • CompositionScanner(CharacterScanner)>>basicScanCharactersFrom:to:in:rightX:stopConditions:kern:
  • CompositionScanner(CharacterScanner)>>scanCharactersFrom:to:in:rightX:stopConditions:kern:
  • CompositionScanner>>composeFrom:inRectangle:firstLine:leftSide:rightSide:
  • TextComposer>>composeEachRectangleIn:
  • TextComposer>>composeAllRectangles:
  • TextComposer>>composeLinesFrom:to:delta:into:priorLines:atY:textStyle:text:container:wantsColumnBreaks:
  • TextComposer>>composeAllLines
  • TextComposer>>composeLinesFrom:to:delta:into:priorLines:atY:textStyle:text:container:wantsColumnBreaks:
  • MultiNewParagraph(NewParagraph)>>composeLinesFrom:to:delta:into:priorLines:atY:
  • MultiNewParagraph(NewParagraph)>>recomposeFrom:to:delta:
  • MultiNewParagraph(NewParagraph)>>replaceFrom:to:with:displaying:
  • TextMorphEditor>>zapSelectionWith:
  • TextMorphEditor(ParagraphEditor)>>replace:with:and:
  • TextMorphEditor(ParagraphEditor)>>insertAndSelect:at:
  • TextMorphEditor(ParagraphEditor)>>afterSelectionInsertAndSelect:
  • TextMorphEditor(ParagraphEditor)>>printIt

実際の描画は displayLine:offset:leftInRun: で行われるが、レイアウトと同様 basicScanCharactersFrom:to:in:rightX:stopConditions:kern: で空白文字の処理が行われる。

drawOn: から表示までのスタックフレーム。

  • MultiDisplayScanner(MultiCharacterScanner)>>basicScanCharactersFrom:to:in:rightX:stopConditions:kern:
  • MultiDisplayScanner(MultiCharacterScanner)>>scanCharactersFrom:to:in:rightX:stopConditions:kern:
  • MultiDisplayScanner>>displayLine:offset:leftInRun:
  • MultiNewParagraph>>displayOn:using:at:
  • FormCanvas>>paragraph:bounds:color:
  • TextMorphForEditView(TextMorph)>>drawOn:

まとめ。表示処理を、Squeak では次の二つに分けて行っている。

  • 更新時整形 MultiNewParagraph(NewParagraph)>>recomposeFrom:to:delta: など
    • 文字列の編集の度に呼ばれる。
    • TextLine (一行の文字数と座標情報)オブジェクトが生成される。
  • 表示 MultiDisplayScanner>>displayLine:offset:leftInRun:
    • 整形した文字列を表示する。

段落、単語、文字というような階層構造のあるテキストの表示を状態マシンを使って文字単位で行っているために多少ややこしい。