このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。
昨日に引き続き、ヘルパメソッドの実装をしていこう。
========== RFBCanvas#recreateDisplayBuffer ==========
// クライアントの画素形式に合った画面バッファを用意
private void recreateDisplayBuffer() throws IOException {
PixelFormat format = context.getPixelFormat();
if (!format.isTrueColor())
throw new IOException("Can't handle indexed pixel format.");
int redMask = format.getRedMax() << format.getRedShift();
int greenMask = format.getGreenMax() << format.getGreenShift();
int blueMask = format.getBlueMax() << format.getBlueShift();
ColorModel model = new DirectColorModel(
format.getBitPerPixel(), redMask, greenMask, blueMask);
WritableRaster raster = model.createCompatibleWritableRaster(
getWidth(), getHeight());
synchronized (paintingSystem) {
// 以前の画面バッファがあればデータを引き継ぐ
if (displayBuffer != null) {
raster.setRect(displayBuffer.getRaster());
}
displayBuffer = new BufferedImage(model, raster, false, null);
unsentRegion = null;
requestedRegion = null;
}
}
========== end of RFBCanvas#recreateDisplayBuffer ==========
recreateDisplayBuffer メソッドでメンバを初期化する。
この実装については、以前に考察した時のものを利用した。
グラフィックス系のクラスは奥が深い。
http://mixi.jp/view_diary.pl?id=318269104&owner_id=2300658
========== RFBCanvas#firePaint ==========
// 指定範囲に対して paint を発行
private void firePaint(Rectangle region) {
synchronized (paintingSystem) {
// 描画範囲を計算
Rectangle r = region.intersection(clientRegion);
if (r.isEmpty()) return;
// 描画
Graphics2D g = displayBuffer.createGraphics();
try {
g.setClip(r);
paint(g);
} finally {
g.dispose();
}
// 描画された範囲を未送信領域に追加
unsentRegion = addShapes(unsentRegion, r);
}
}
========== end of RFBCanvas#firePaint ==========
========== RFBCanvas#fireUpdate ==========
// 指定範囲に対して update を発行
void fireUpdate(Rectangle region) {
synchronized (paintingSystem) {
// 描画範囲を計算
Rectangle r = region.intersection(clientRegion);
if (r.isEmpty()) return;
// 描画
Graphics2D g = displayBuffer.createGraphics();
try {
g.setClip(r);
update(g);
} finally {
g.dispose();
}
// 更新された範囲を未送信領域に追加
unsentRegion = addShapes(unsentRegion, r);
}
}
========== end of RFBCanvas#fireUpdate ==========
firePaint/fireUpdate の実装はほぼ同じだ。
displayBuffer の createGraphics で Graphics を作成し、
実装者が描画できる範囲にクリッピングを施した上で、
paint/update コールバックを呼び出す。
もし更新領域がなければイベントは発行しない。
このメソッドで更新された領域は、
後にクライアントに送信するため、
unsentRegion に追加しておく。
addShapes は、Shape 同士を合成するためのメソッドだ。
========== RFBCanvas#addShapes ==========
// Shape 2 つを合成する
static private Shape addShapes(Shape augend, Shape addend) {
if (augend == null) return addend;
if (addend == null) return augend;
Area a = new Area(augend);
a.add(new Area(addend));
return a;
}
========== end of RFBCanvas#addShapes ==========
unsentRegion を Shape にしたのには理由がある。
更新される領域は基本的に矩形(Rectangle)なのだが、
クライアントが要求する領域が一致しているとは限らない。
そのため、未送信の領域は矩形に収まらない、
不定形の領域になる可能性が高いのだ。
Area は、Shape の 1 種であり、
任意の形状の領域を保持することができる。
しかし、Area は処理コストが高くつくため、
矩形領域の場合は Rectangle を使うことで高速化を図る。
さて、最後に sendFramebuffer を実装しなければならない。
このメソッドではクライアントにデータを送るのだが、
実はサーバメッセージをまだ解説していないため、
現時点では処理する方法が分からないのだ。