-
Notifications
You must be signed in to change notification settings - Fork 168
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ルーラー描画の高速化 #1067
ルーラー描画の高速化 #1067
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,13 +9,18 @@ | |
CRuler::CRuler(const CEditView* pEditView, const CEditDoc* pEditDoc) | ||
: m_pEditView(pEditView) | ||
, m_pEditDoc(pEditDoc) | ||
, m_hFont(NULL) | ||
, m_nRulerHeight(0) | ||
{ | ||
m_nOldRulerDrawX = 0; // 前回描画したルーラーのキャレット位置 2002.02.25 Add By KK | ||
m_nOldRulerWidth = 0; // 前回描画したルーラーのキャレット幅 2002.02.25 Add By KK | ||
} | ||
|
||
CRuler::~CRuler() | ||
{ | ||
if (m_hFont) { | ||
::DeleteObject( m_hFont ); | ||
} | ||
} | ||
|
||
//2007.08.26 kobake UNICODE用にX位置を変更 | ||
|
@@ -88,26 +93,31 @@ void CRuler::DrawRulerBg(CGraphics& gr) | |
CTypeSupport cRulerType(m_pEditView,COLORIDX_RULER); | ||
|
||
// フォント設定 (ルーラー上の数字用) | ||
LOGFONT lf; | ||
HFONT hFont; | ||
HFONT hFontOld; | ||
memset_raw( &lf, 0, sizeof(lf) ); | ||
lf.lfHeight = 1 - pCommon->m_sWindow.m_nRulerHeight; // 2002/05/13 ai | ||
lf.lfWidth = 0; | ||
lf.lfEscapement = 0; | ||
lf.lfOrientation = 0; | ||
lf.lfWeight = 400; | ||
lf.lfItalic = 0; | ||
lf.lfUnderline = 0; | ||
lf.lfStrikeOut = 0; | ||
lf.lfCharSet = 0; | ||
lf.lfOutPrecision = 3; | ||
lf.lfClipPrecision = 2; | ||
lf.lfQuality = 1; | ||
lf.lfPitchAndFamily = 34; | ||
wcscpy( lf.lfFaceName, L"Arial" ); | ||
hFont = ::CreateFontIndirect( &lf ); | ||
hFontOld = (HFONT)::SelectObject( gr, hFont ); | ||
if (m_hFont && m_nRulerHeight != pCommon->m_sWindow.m_nRulerHeight) { | ||
::DeleteObject( m_hFont ); | ||
m_hFont = NULL; | ||
} | ||
if (m_hFont == NULL) { | ||
LOGFONT lf = {0}; | ||
lf.lfHeight = 1 - pCommon->m_sWindow.m_nRulerHeight; // 2002/05/13 ai | ||
lf.lfWidth = 0; | ||
lf.lfEscapement = 0; | ||
lf.lfOrientation = 0; | ||
lf.lfWeight = 400; | ||
lf.lfItalic = 0; | ||
lf.lfUnderline = 0; | ||
lf.lfStrikeOut = 0; | ||
lf.lfCharSet = 0; | ||
lf.lfOutPrecision = 3; | ||
lf.lfClipPrecision = 2; | ||
lf.lfQuality = 1; | ||
lf.lfPitchAndFamily = 34; | ||
wcscpy_s( lf.lfFaceName, L"Arial" ); | ||
m_hFont = ::CreateFontIndirect( &lf ); | ||
m_nRulerHeight = pCommon->m_sWindow.m_nRulerHeight; | ||
} | ||
assert(m_hFont != NULL); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. このassertがfailするときの挙動を、いつか真面目に考えないといかんと思っとります。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 基本的には起こりえないエラーについては Debug ビルドで軽くみておくぐらいで良いんじゃないかなと思います。フリーソフトのテキストエディタにミッションクリティカルを求めるのも変な話なので。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ガチスルーの意図 if (!m_hFont) return; //後続の処理を実行しない です。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ガチスルーとはそういう事でしたか。話題自体をスルーする事かと思ってました。 フォント作成が失敗するような状況だと return 後の処理が正常に動く保証も無いような気がしますが、エラーチェックを入れないより大分良い気がしてきました。 |
||
HFONT hFontOld = (HFONT)::SelectObject( gr, m_hFont ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 感想です。
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. メソッド名に |
||
::SetBkMode( gr, TRANSPARENT ); | ||
|
||
//背景塗りつぶし | ||
|
@@ -126,7 +136,6 @@ void CRuler::DrawRulerBg(CGraphics& gr) | |
int nX = m_pEditView->GetTextArea().GetAreaLeft(); | ||
int nY = m_pEditView->GetTextArea().GetRulerHeight() - 2; | ||
|
||
// 下線 (ルーラーと本文の境界) | ||
berryzplus marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// Aug. 14, 2005 genta 折り返し幅をLayoutMgrから取得するように | ||
// 2005.11.10 Moca 1dot足りない | ||
CLayoutXInt nMaxLineColum = m_pEditDoc->m_cLayoutMgr.GetMaxLineLayout(); | ||
|
@@ -135,8 +144,6 @@ void CRuler::DrawRulerBg(CGraphics& gr) | |
if( nToX > m_pEditView->GetTextArea().GetAreaRight() ){ | ||
nToX = m_pEditView->GetTextArea().GetAreaRight(); | ||
} | ||
::MoveToEx( gr, m_pEditView->GetTextArea().GetAreaLeft(), nY + 1, NULL ); | ||
::LineTo( gr, nToX, nY + 1 ); | ||
|
||
//目盛を描画 | ||
const int oneColumn = (Int)m_pEditView->GetTextMetrics().GetLayoutXDefault(); | ||
|
@@ -150,44 +157,55 @@ void CRuler::DrawRulerBg(CGraphics& gr) | |
i += CLayoutXInt(oneColumn - pxOffset); // CLayoutXInt == pixel | ||
++keta; | ||
} | ||
|
||
// 目盛り線を1本ずつ描画するのではなく後述する PolyPolyline でまとめて描画を行う | ||
const int nWidth = (Int)(m_pEditView->GetTextArea().GetRightCol() - i); | ||
const size_t nLinesToDraw = 1 + std::min<int>((nWidth + 1 + 1 + oneColumn - 1) / oneColumn, nMaxLineKetas - keta + 1); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. この式の確からしさを検証できるドキュメントが欲しいです。 左辺の変数名は「ドキュメントが要らないコード」の要件を満たしている気がします。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. while 文が回る回数を計算してます。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ええと、左辺の変数名から利用方法は理解していて、わからんのはその数式が正しいといえる根拠です。 const size_t nLinesToDraw = 1 + std::min<int>(
(nWidth + 1 + 1 + oneColumn - 1) / oneColumn,
nMaxLineKetas - keta + 1);
日本語にして見ると なんでやねん! の嵐です。 とりあえず、「既存と同じです」なら「ま、いっか」となるんですけど、なんで?のもっともらしい理由づけが欲しいです。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 元の実装の記述の意味合いや厳密性については考えていませんが、while 文での扱いと同じ結果になるように合わせた式にしています。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. もちょっと細かく解説した方が良いでしょうか? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
冗談でなく、本当に理解できてないです。 改めてコードを眺めた感じの見解が以下です。
この見解で合ってるとすると、スジが通ってると思います。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
このコメント取消。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. const size_t nLinesToDraw = 1 + std::min<int>((nWidth + 1 + 1 + oneColumn - 1) / oneColumn, nMaxLineKetas - keta + 1); は
で、A と B から小さい値を選ぶ理由は while 文の条件式で A
なので、
ですが、 さて、while 文の条件式は下記のようになっていて、
ループ内では
となっています。なので変数 この場合に除算が使えます。余りが出た場合に
元々の条件式に B
|
||
auto& apt = m_apt; | ||
auto& asz = m_asz; | ||
apt.resize(nLinesToDraw * 2); | ||
asz.resize(nLinesToDraw, 2); | ||
// 下線 (ルーラーと本文の境界) | ||
apt[0] = POINT{m_pEditView->GetTextArea().GetAreaLeft(), nY + 1}; | ||
apt[1] = POINT{nToX, nY + 1}; | ||
size_t idx = 1; | ||
while(i <= m_pEditView->GetTextArea().GetRightCol() + 1 && keta <= nMaxLineKetas) | ||
{ | ||
apt[idx * 2 + 0] = POINT{nX, nY}; | ||
//ルーラー終端の区切り(大) | ||
if( keta == nMaxLineKetas ){ | ||
::MoveToEx( gr, nX, nY, NULL ); | ||
::LineTo( gr, nX, 0 ); | ||
apt[idx * 2 + 1] = POINT{nX, 0}; | ||
} | ||
//10目盛おきの区切り(大)と数字 | ||
else if( 0 == keta % 10 ){ | ||
wchar_t szColumn[32]; | ||
::MoveToEx( gr, nX, nY, NULL ); | ||
::LineTo( gr, nX, 0 ); | ||
apt[idx * 2 + 1] = POINT{nX, 0}; | ||
_itow( ((Int)keta) / 10, szColumn, 10 ); | ||
::TextOut( gr, nX + 2 + 0, -1 + 0, szColumn, wcslen( szColumn ) ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ここって There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. そればっかりはやって見ないと分からん感じです。 |
||
} | ||
//5目盛おきの区切り(中) | ||
else if( 0 == keta % 5 ){ | ||
::MoveToEx( gr, nX, nY, NULL ); | ||
::LineTo( gr, nX, nY - 6 ); | ||
apt[idx * 2 + 1] = POINT{nX, nY - 6}; | ||
} | ||
//毎目盛の区切り(小) | ||
else{ | ||
::MoveToEx( gr, nX, nY, NULL ); | ||
::LineTo( gr, nX, nY - 3 ); | ||
apt[idx * 2 + 1] = POINT{nX, nY - 3}; | ||
} | ||
++idx; | ||
assert(idx <= nLinesToDraw); | ||
|
||
nX += dx; | ||
i += oneColumn; | ||
keta++; | ||
} | ||
::PolyPolyline(gr, &apt[0], &asz[0], (DWORD)nLinesToDraw); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 感想です。 趣味ですが、最後の引数で渡す値は reserveで確保サイズを決定し、 たぶん、PolyPolyLineの呼出直前に線分の数を計算するのが有効なはず。 asz.assign(nLinesToDraw, 2); で、 asz.assign(apt.size() / 2, 2);
::PolyPolyline(gr, apt.data(), asz.data(), static_cast<DWORD>(asz.size())); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. その方法は安全で間違いが起きないかもしれませんが、途中でメモリの再確保が行われるかもしれません。事前計算出来る場合にはメモリを一括で確保していくやり方が良いと思います。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 出たとこ勝負で ルーラーで表示できる桁目盛りの数なんて高が知れてるので、全部動的に追加確保しても問題ないような気もします。まぁ、このコメントは感想なので、具体的になにか対応してほしいわけでもなく、指摘として言ってみてるだけなんで気にしないでください 😄 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 人によっては1行80桁の制限を頑なに守り続けるかもしれませんが、将来的にモニタの解像度が異常に上がって頭髪の平均密度を越す勢いで |
||
|
||
//色戻す | ||
gr.PopTextForeColor(); | ||
gr.PopPen(); | ||
|
||
//フォント戻す | ||
::SelectObject( gr, hFontOld ); | ||
berryzplus marked this conversation as resolved.
Show resolved
Hide resolved
|
||
::DeleteObject( hFont ); | ||
} | ||
|
||
/*! ルーラー描画 | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lfHeight
メンバに負数を渡すと、ピクセル単位のフォントサイズを指定したことになる、というようなLOGFONT構造体の仕様があった気がします。
「1 - ルーラー高さ」はおそらく負数になるので、たぶんこれはDPI対応の対象になるような気がします。
もちろん、別件で構わないと思っとりますが、そのうちやりたい。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
共通設定のウィンドウに「ルーラーの高さ」の設定がありますが単位がドットですね。指定されたドット数の高さにするのか、それとも表示倍率に応じて調整するのか、どちらが正しい仕様なのかは謎です(そもそも明文化された仕様は無いですけど)。
#505 でもここらへんに関わる会話がありました。
ルーラーのフォントの単位をエディタのフォントと同じポイントにして、エディタのフォントサイズ変更に追従するのが挙動としては良いと思いますが、そうするとルーラーの高さを設定で持つ事との互換性が無くなると思います。ルーラーのフォントサイズが大きくなると、ルーラーの高さを超えてしまう為です。