HTML 対応
前のドキュメントで折り返し処理を実装したので、次はHTMLファイルを見やすく表示できるようにしてみよう。
■ HTML タグの指定色表示
ここ にHTMLファイルを表示した画面を示したが、HTMLタグと本文が同じ色で表示されていて、視認性が低い。そこで、まずHTMLタグを色表示するようにしてみる。そのためには、"<" の直後に英字がある場合はフラグ(HTMLtag)をONにし、">" を表示した時にフラグをOFFにするとよい。タグの途中で改行を入れることはまずあり得ないと考えられるので、タグ中かどうかの状態は論理行単位で有効とする。プログラムは以下のようになる。
## column
static bool isHTMLtag(cchar *ptr, int length)
{
return length >= 2 && ptr[0] == '<' && isalpha(ptr[1]) ||
length >= 3 && ptr[0] == '<' && ptr[1] == '/' && isalpha(ptr[2]);
}
void CViewView::OnDraw(CDC* pDC)
{
.....
bool HTMLtag = false; // HTML(SGML) タグ中かどうか
for(; line < m_vwLineMgr->getLineCountEx() && py < bottom; ++line, py += VW_LINE_HEIGHT) {
.....
while( ptr < eolptr ) {
int px = column * VW_FONT_WIDTH;
if( kwlen > 0 ) { // キーワード発見済みの場合
.....
} else if( *ptr == '\t' ) { // TAB の場合
.....
} else { // 通常文字
cchar *ptr0 = ptr;
if( lineComment ) { // コメント状態
.....
} else if( HTMLtag ) {
textColor = RGB(0x80, 0, 0); // 文字色は黒赤
while( ptr < eolptr && *ptr != '\t' ) {
ptr += 1;
if( ptr[-1] == '>' ) {
HTMLtag = false;
break;
}
}
} else { // 非コメント状態
textColor = RGB(0, 0, 0); // 文字色は黒
while( ptr < eolptr && *ptr != '\t' ) {
if( __iscsym((uchar)*ptr) ) {
.....
} else {
.....
if( isHTMLtag(ptr, endptr-ptr) ) {
HTMLtag = true;
break;
}
csym = false;
}
.....
}
}
}
}
}
}
## endcolumn
■ HTML タグ内キーワード
HTML タグ内のキーワードも色表示した方が視認性が高まる。
## column
void CViewView::OnDraw(CDC* pDC)
{
.....
} else if( HTMLtag ) {
textColor = RGB(0x80, 0, 0); // 文字色は黒赤
while( ptr < eolptr && *ptr != '\t' ) {
if( __iscsym((uchar)*ptr) ) {
if( !csym && isHTMLKeyWord(ptr, endptr-ptr, kwlen, kwcol) ) // 単語区切り&キーワード発見
break;
csym = true;
} else
csym = false;
ptr += 1;
if( ptr[-1] == '>' ) {
HTMLtag = false;
break;
}
}
.....
}
## endcolumn
ここ に実行結果画面を示す。
■ if が外か while が外か
上記に示したプログラムは、HTMLtag が真か偽かでまず処理を分け、その中で while ループを形成しているが、その処理内容は酷似している。したがって、while ループを外側にし、その中で if 文により処理を切り分けるようにすることもできる。
## column
void CViewView::OnDraw(CDC* pDC)
{
.....
while( ptr < eolptr ) {
int px = column * VW_FONT_WIDTH;
if( kwlen > 0 ) { // キーワード発見済みの場合
.....
} else if( *ptr == '\t' ) { // TAB の場合
.....
} else { // 通常文字
cchar *ptr0 = ptr;
if( lineComment ) { // コメント状態
.....
} else { // 非コメント状態
textColor = HTMLtag ? RGB(0x80, 0, 0) : // 文字色は黒赤
RGB(0, 0, 0); // 文字色は黒
while( ptr < eolptr && *ptr != '\t' ) {
if( __iscsym((uchar)*ptr) ) {
if( !csym ) {
if( !HTMLtag && isKeyWord(ptr, endptr-ptr, kwlen, kwcol) ) // 単語区切り&キーワード発見
break;
if( HTMLtag && isHTMLKeyWord(ptr, endptr-ptr, kwlen, kwcol) ) // 単語区切り&キーワード発見
break;
}
csym = true;
} else {
.....
if( !HTMLtag && isHTMLtag(ptr, endptr-ptr) ) {
HTMLtag = true;
break;
}
csym = false;
}
.....
ptr += 1;
if( HTMLtag && ptr[-1] == '>' ) {
HTMLtag = false;
break;
}
}
}
}
}
.....
}
## endcolumn
どちらの形式が優れているかは微妙である。while を外側にした方が全体のコード量が少なくなる傾向にある。現代的なCPUはループ全体がキャッシュに治まると処理がとても高速になるのでループ内のコード量を減らすことは重要である。しかし、現在は HTML タグだけの条件判断だが、<? ... ?> や <script> ... </script> の処理も入ってくると条件判断が複雑になり、コードを追うのが大変になると思われる。また、現代的なCPUはパイプラインが深く、条件判断の分岐予測に失敗するとせっかく処理したパイプライン内の情報が無駄になってしまうので、条件分岐は少ない方が望ましいと考えられる。そういうわけなので、どちらがよいかの判断は全ての機能を実装し終わった後に判断することにしよう。