LLTigerで発表しました -Language Update編-

資料あげときます。

Xlib.php
http://github.com/moriyoshi/php-Xlib/
よりとってきてください。

<?php
require 'Xlib.php';
$fonts = array(
    'hiragino-mincho' => "/System/Library/Fonts/ヒラギノ明朝 ProN W6.otf",
    'courier'         => "/Library/Fonts/Courier New Bold.ttf",
);

$texts = array(
    array("はい"),
    array("始まって"),
    array("しまいました"),
    array("Heavyweight"),
    array("Heavyweight\nTemplate"),
    array("Heavyweight\nTemplate\nLanguage"),
    array("PHPの"),
    array("Language\nUpdate"),
    array("今回は"),
    array(""),
    array("moriyoshiが"),
    array("お送りさせて"),
    array("いただきます"),
    array("自己紹介"),
    array("<?php phpcredits(); ?>"),
    array(""),
    array("さて"),
    array("PHPは実用本意"),
    array("進歩"),
    array("とくにありません"),
    array("バグフィックス"),
    array("もり"),
    array("もり・"),
    array("もり・もり"),
    array("もり・もり・"),
    array("もり・もり・もりだくさん&#9832;"),
    array("…なわけですが"),
    array("昨年からの\n振り返り"),
    array("2009/6/30"),
    array("5.3.0リリース"),
    array("クロージャ導入\nネームスペース導入\netc."),
    array("\"),
    array("民主主義の悲劇"),
    array("…"),
    array("2009/7/16"),
    array("CVSから\nSubversionへの\n移行完了"),
    array("いまさらという感じ"),
    array("以降\nしばらく\n目立った動きなし"),
    array("…"),
    array("2010/3/12"),
    array("PHP6ブランチ放棄事件"),
    array("事の発端"),
    array("output-bufferingのバグ"),
    array("直すには大規模な\n改修が必要"),
    array("パッチはtrunkにある"),
    array("5.3にバックポートしたい"),
    array("5.3は安定ブランチ"),
    array("なので許されない"),
    array("trunkはUnicode対応作業中"),
    array("リリースは当分先"),
    array("他にも同様の事例あり"),
    array("しびれを切らしたJaniさん"),
    array("無断で"),
    array("trunkをリネームし\n5.3からtrunkを再ブランチ"),
    array("糾弾される"),
    array("そこにRasmusさん登場"),
    array("「まあまあ落ち着いて」"),
    array("一定の理解を示すよう提案"),
    array("結局"),
    array("Unicode化は見送られ"),
    array("新生trunk\n(5.4ブランチ)"),
    array("誕生"),
    array("というわけでした"),
    array("…"),
    array("2010/4/22"),
    array("Traits patchマージ"),
    array("Traitsとは?"),
    array("いわゆるMixin的なもの"),
    array("実装の再利用性を促進"),
    array("trait Hey {\n    public function hey() {\n        echo \"hey\\n\";\n    }\n}", array('font' => 'courier')),
    array("trait Howdy {\n    public function howdy() {\n        echo \"howdy\\n\";\n    }\n}", array('font' => 'courier')),
    array("class Hello {\n    use Hey, Howdy;\n}", array('font' => 'courier')),
    array("class Hello {\n    use Hey, Howdy;\n}\n\$hello = new Hello;\n\$hello->hey();\n\$hello->howdy();", array('font' => 'courier')),
    array("class TexasHello {\n    use Hey;\n    use Howdy { hello => howdy }\n}", array('font' => 'courier')),
    array("\$hello = new TexasHello;\n\$hello->howdy();\n\$hello->hello();", array('font' => 'courier')),
    array(""),
    array("2010/7/22"),
    array("5.3.3リリース"),
    array("重要な変更"),
    array("メソッド名=クラス名\n&#9758;コンストラクタ"),
    array("    ○\n(従来までの常識)"),
    array("but"),
    array("名前空間中のクラス"),
    array("×"),
    array("namespace Foo;\nclass Bar {\n    public function Bar() {\n        // 5.3.2まではコンストラクタ\n        // 5.3.3からは普通のメソッド\n    }\n}"),
    array("理由?"),
    array("嫌だから"),
    array(""),
    array("以上で"),
    array("Language Update"),
    array("駆け足でしたが"),
    array("ご清聴ありがとうございました"),
    array("ところで"),
    array("この"),
    array("プレゼンツールは"),
    array("もちろん"),
    array("100% Pure PHPで"),
    array("実装しております"),
    array("- おわり -"),
);

ini_set('memory_limit', -1);

$x = XDisplay::create();
$bc = $x->allocColor($x->screens[0]->colormap, 0xffff, 0xffff, 0xffff);
$wnd = $x->createWindow($x->screens[0]->rootWindow,
        0, 0, $x->screens[0]->width, $x->screens[0]->height, 0, XClient::InputOutput, null,
        array('backgroundPixel' => $bc['pixel'],
              'eventMask' => XClient::ExposureMask
                             | XClient::ButtonPressMask
                             | XClient::KeyPressMask
                             | XClient::StructureNotifyMask,
              'overrideRedirect' => true));
$_motif_wm_hints = $x->internAtom("_MOTIF_WM_HINTS");
$wnd->changeProperty(XClient::PropModeReplace, $_motif_wm_hints, $_motif_wm_hints, 32, "\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00");

$gc = $wnd->createGC(
        array('function' => 3, 'lineWidth' => 8, 'lineStyle' => 0));
$x->mapWindow($wnd);

class Canvas {
    protected $im;
    public $width;
    public $height;
    protected $backgroundColor;
    protected $foregroundColor;

    public function __construct($width, $height) {
        $this->im = imagecreatetruecolor($width, $height);
        $this->width = $width;
        $this->height = $height;
        $this->backgroundColor = imagecolorallocate($this->im, 255, 255, 255);
        $this->foregroundColor = imagecolorallocate($this->im, 0, 0, 0);
    }

    public function toPixels() {
        ob_start();
        imagegd2($this->im, NULL, 64);
        $data = substr(ob_get_clean(), 23);
        $data |= substr($data & str_repeat("\x00\x00\x00\xff", strlen($data) / 4), 3);
        return $data;
    }

    public function clear() {
        imagefilledrectangle($this->im, 0, 0, $this->width, $this->height, $this->backgroundColor);
    }

    public function setFont($font) {
        $this->font = $font;
    }

    public function drawText($text, $sz) {
        for (;;) {
            $bbox = imagettfbbox($sz, 0, $this->font, $text);
            if ($bbox[2] < $this->width * 0.8)
                break;
            $sz -= 8;
        }
        imagettftext($this->im, $sz, 0, ($this->width - $bbox[2]) / 2, ($this->height - $bbox[3]) / 2 + $sz * 0.6, $this->foregroundColor, $this->font, $text);
    }
}
     
$cv = new Canvas($x->screens[0]->width, $x->screens[0]->height);

function drawImage($wnd, $gc, $x, $y, $width, $height, $data) {
    $ncx = (int)($width / 64);
    $ncy = (int)($height / 64);
    for ($j = 0; $j < $ncy; $j++) {
        $ch = min(64, $height - $j * 64);
        for ($i = 0; $i < $ncx; $i++) {
            $cw = min(64, $width - $i * 64);
            $wnd->putImage(2, $gc, $cw, $ch, $x + $i * 64, $y + $j * 64, 0, 24, substr($data, $i * 16384 + $j * $width * 256, 16384));
        }
    }
}

$data = null;
$counter = 0;
for (;;) {
    switch ($x->nextEvent($ev)) {
    case XClient::Expose:
        if ($data !== null)
            drawImage($wnd, $gc, 0, 0, $cv->width, $cv->height, $data);
        break;
    case XClient::ButtonPress:
    case XClient::KeyPress:
    case XClient::KeyRelease:
        $cv->clear();
        $line = array_shift($texts);
        if ($line) {
            $text = $line[0];
            $fontname = 'hiragino-mincho';
            if (isset($line[1])) {
                if (isset($line[1]['font']))
                    $fontname = $line[1]['font'];
            }
            $cv->setFont($fonts[$fontname]);
            $cv->drawText($text, 84);
        }
        $data = $cv->toPixels();
        drawImage($wnd, $gc, 0, 0, $cv->width, $cv->height, $data);
        break;
    case XClient::MotionNotify:
        break;
    }
}