Skip to content

Commit

Permalink
Merge pull request #1542 from k-kagari/feature/more-tests-for-cnativew
Browse files Browse the repository at this point in the history
CNativeW の static 関数に対するテストを追加する
  • Loading branch information
kengoide authored Feb 17, 2021
2 parents 503d619 + 8390ff8 commit 5407fd8
Show file tree
Hide file tree
Showing 11 changed files with 168 additions and 26 deletions.
2 changes: 2 additions & 0 deletions sakura_core/CRegexKeyword.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ typedef struct RegexInfo_t {
int nFlag; //色指定のチェックが入っているか? YES=RK_EMPTY, NO=RK_NOMATCH
} REGEX_INFO;

class CStringRef;

//! 正規表現キーワードクラス
/*!
正規表現キーワードを扱う。
Expand Down
4 changes: 1 addition & 3 deletions sakura_core/EditInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@

#include "basis/SakuraBasis.h"
#include "config/maxdata.h"
#include "charset/charcode.h"
#include "mem/CNativeW.h"
#include "types/CType.h"
#include "charset/charset.h"

/*!
* ファイル情報
Expand Down
4 changes: 2 additions & 2 deletions sakura_core/charset/charcode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ namespace WCODE
bool CalcHankakuByFont(wchar_t);

//2007.08.30 kobake 追加
bool IsHankaku(wchar_t wc)
bool IsHankaku(wchar_t wc, const CCharWidthCache& cache)
{
//※ほぼ未検証。ロジックが確定したらインライン化すると良い。

Expand Down Expand Up @@ -83,7 +83,7 @@ namespace WCODE
}

//$$ 仮。もう動的に計算しちゃえ。(初回のみ)
return CalcHankakuByFont(wc);
return cache.CalcHankakuByFont(wc);
}

//!制御文字であるかどうか
Expand Down
22 changes: 10 additions & 12 deletions sakura_core/charset/charcode.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,6 @@ namespace WCODE
return c>=front && c<=back;
}

//!半角文字(縦長長方形)かどうか判定
bool IsHankaku(wchar_t wc);

//!全角文字(正方形)かどうか判定
inline bool IsZenkaku(wchar_t wc)
{
return !IsHankaku(wc);
}

//!使用フォント番号を返す
// (0:半角/1:全角)
int GetFontNo(wchar_t c);
Expand Down Expand Up @@ -262,9 +253,9 @@ class CCharWidthCache {
void Clear();
[[nodiscard]] bool GetMultiFont() const { return m_bMultiFont; }

bool CalcHankakuByFont(wchar_t c) const;
int CalcPxWidthByFont(wchar_t c);
int CalcPxWidthByFont2(const wchar_t* pc2) const;
virtual bool CalcHankakuByFont(wchar_t c) const;
virtual int CalcPxWidthByFont(wchar_t c);
virtual int CalcPxWidthByFont2(const wchar_t* pc2) const;

private:
void DeleteLocalData();
Expand All @@ -290,4 +281,11 @@ void InitCharWidthCache( const LOGFONT &lf, ECharWidthFontMode fMode=CWM_FONT_ED
void InitCharWidthCacheFromDC(const LOGFONT* lfs, ECharWidthFontMode fMode, HDC hdcOrg );
[[nodiscard]] CCharWidthCache& GetCharWidthCache();

namespace WCODE {
//!半角文字(縦長長方形)かどうか判定
bool IsHankaku(wchar_t wc, const CCharWidthCache& cache = GetCharWidthCache());
//!全角文字(正方形)かどうか判定
inline bool IsZenkaku(wchar_t wc) { return !IsHankaku(wc); }
}

#endif /* SAKURA_CHARCODE_4C34C669_0BAB_441A_9B1D_2B9AC1895380_H_ */
2 changes: 2 additions & 0 deletions sakura_core/doc/CBlockComment.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ enum ECommentType{
#define BLOCKCOMMENT_NUM 2
#define BLOCKCOMMENT_BUFFERSIZE 16

class CStringRef;

// 2005.11.10 Moca アクセス関数追加
class CBlockComment{
public:
Expand Down
2 changes: 2 additions & 0 deletions sakura_core/doc/CLineComment.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
#define COMMENT_DELIMITER_NUM 3
#define COMMENT_DELIMITER_BUFFERSIZE 16

class CStringRef;

/*! 行コメントデリミタを管理する
@note CLineCommentは、共有メモリSTypeConfigに含まれるので、メンバ変数は常に実体を持っていなければならない。
Expand Down
3 changes: 2 additions & 1 deletion sakura_core/env/CAppNodeManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@
#define SAKURA_CAPPNODEMANAGER_CAE7A323_DEA3_47E4_91DE_C99A88C32683_H_
#pragma once

#include "util/design_template.h"
#include "basis/CMyString.h"
#include "config/maxdata.h"
#include "util/design_template.h"

class CAppNodeGroupHandle;

Expand Down
13 changes: 7 additions & 6 deletions sakura_core/mem/CNativeW.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ CLogicInt CNativeW::GetSizeOfChar( const wchar_t* pData, int nDataLen, int nIdx
}

//! 指定した位置の文字が半角何個分かを返す
CKetaXInt CNativeW::GetKetaOfChar( const wchar_t* pData, int nDataLen, int nIdx )
CKetaXInt CNativeW::GetKetaOfChar( const wchar_t* pData, int nDataLen, int nIdx, const CCharWidthCache& cache)
{
//文字列範囲外なら 0
if( nIdx >= nDataLen )
Expand All @@ -372,7 +372,7 @@ CKetaXInt CNativeW::GetKetaOfChar( const wchar_t* pData, int nDataLen, int nIdx
}

//半角文字なら 1
if(WCODE::IsHankaku(pData[nIdx]) )
if(WCODE::IsHankaku(pData[nIdx], cache))
return CKetaXInt(1);

//全角文字なら 2
Expand All @@ -381,25 +381,26 @@ CKetaXInt CNativeW::GetKetaOfChar( const wchar_t* pData, int nDataLen, int nIdx
}

//! 指定した位置の文字の文字幅を返す
CHabaXInt CNativeW::GetHabaOfChar( const wchar_t* pData, int nDataLen, int nIdx )
CHabaXInt CNativeW::GetHabaOfChar( const wchar_t* pData, int nDataLen, int nIdx,
CCharWidthCache& cache, bool bEnableExtEol )
{
//文字列範囲外なら 0
if( nIdx >= nDataLen ){
return CHabaXInt(0);
}
// HACK:改行コードに対して1を返す
if( WCODE::IsLineDelimiter(pData[nIdx], GetDllShareData().m_Common.m_sEdit.m_bEnableExtEol) ){
if( WCODE::IsLineDelimiter(pData[nIdx], bEnableExtEol) ){
return CHabaXInt(1);
}

// サロゲートチェック
if(IsUTF16High(pData[nIdx]) && nIdx + 1 < nDataLen && IsUTF16Low(pData[nIdx + 1])){
return CHabaXInt(WCODE::CalcPxWidthByFont2(pData + nIdx));
return CHabaXInt(cache.CalcPxWidthByFont2(pData + nIdx));
}else if(IsUTF16Low(pData[nIdx]) && 0 < nIdx && IsUTF16High(pData[nIdx - 1])) {
// サロゲートペア(下位)
return CHabaXInt(0); // 不正位置
}
return CHabaXInt(WCODE::CalcPxWidthByFont(pData[nIdx]));
return CHabaXInt(cache.CalcPxWidthByFont(pData[nIdx]));
}

/* ポインタで示した文字の次にある文字の位置を返します */
Expand Down
10 changes: 8 additions & 2 deletions sakura_core/mem/CNativeW.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@

#include "CNative.h"
#include "basis/SakuraBasis.h"
#include "charset/charcode.h"
#include "debug/Debug2.h" //assert
#include "env/DLLSHAREDATA.h"

//! 文字列への参照を取得するインターフェース
class IStringRef{
Expand Down Expand Up @@ -163,8 +165,12 @@ class CNativeW final : public CNative{
public:
// -- -- staticインターフェース -- -- //
static CLogicInt GetSizeOfChar( const wchar_t* pData, int nDataLen, int nIdx ); //!< 指定した位置の文字がwchar_t何個分かを返す
static CHabaXInt GetHabaOfChar( const wchar_t* pData, int nDataLen, int nIdx );
static CKetaXInt GetKetaOfChar( const wchar_t* pData, int nDataLen, int nIdx ); //!< 指定した位置の文字が半角何個分かを返す
static CHabaXInt GetHabaOfChar( const wchar_t* pData, int nDataLen, int nIdx,
CCharWidthCache& cache = GetCharWidthCache(),
bool bEnableExtEol = GetDllShareData().m_Common.m_sEdit.m_bEnableExtEol );
//! 指定した位置の文字が半角何個分かを返す
static CKetaXInt GetKetaOfChar( const wchar_t* pData, int nDataLen, int nIdx,
const CCharWidthCache& cache = GetCharWidthCache() );
static const wchar_t* GetCharNext( const wchar_t* pData, int nDataLen, const wchar_t* pDataCurrent ); //!< ポインタで示した文字の次にある文字の位置を返します
static const wchar_t* GetCharPrev( const wchar_t* pData, int nDataLen, const wchar_t* pDataCurrent ); //!< ポインタで示した文字の直前にある文字の位置を返します

Expand Down
1 change: 1 addition & 0 deletions sakura_core/recent/SShare_History.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#ifndef SAKURA_SSHARE_HISTORY_9F7E6200_FEE2_4CAC_A5D3_32EEC4130CFC_H_
#define SAKURA_SSHARE_HISTORY_9F7E6200_FEE2_4CAC_A5D3_32EEC4130CFC_H_

#include "EditInfo.h"
#include "config/maxdata.h"

//共有メモリ内構造体
Expand Down
131 changes: 131 additions & 0 deletions tests/unittests/test-cnative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
*/
#include <stdexcept>
#include <gtest/gtest.h>
#include "charset/charcode.h"
#include "mem/CNativeW.h"
#include "mem/CNativeA.h"

Expand Down Expand Up @@ -741,3 +742,133 @@ TEST(CNativeW, globalOperatorAdd)
CNativeW v4(L"後半");
EXPECT_STREQ(L"前半後半", (v3 + v4).GetStringPtr());
}

/*!
* @brief GetSizeOfCharの仕様
* @remark 指定した文字の符号単位数を返す。
*/
TEST(CNativeW, GetSizeOfChar)
{
// 基本多言語面の文字ならば1を返す。
EXPECT_EQ(CNativeW::GetSizeOfChar(L"a", 1, 0), 1);
// 範囲外なら0を返す。
EXPECT_EQ(CNativeW::GetSizeOfChar(L"", 0, 0), 0);
// 上位・下位サロゲートの組み合わせであれば2を返す。
EXPECT_EQ(CNativeW::GetSizeOfChar(L"\xd83c\xdf38", 2, 0), 2);
// 指定位置が下位サロゲートならその他の文字と同様に1を返す。
EXPECT_EQ(CNativeW::GetSizeOfChar(L"\xd83c\xdf38", 2, 1), 1);
}

/*!
* @brief GetKetaOfCharの仕様
* @remark 指定した文字の桁数を返す。
*/
TEST(CNativeW, GetKetaOfChar)
{
// 範囲外なら0を返す。
EXPECT_EQ(CNativeW::GetKetaOfChar(L"", 0, 0), 0);
// 上位サロゲートなら2を返す。
EXPECT_EQ(CNativeW::GetKetaOfChar(L"\xd83c\xdf38", 2, 0), 2);
// 上位サロゲートに続く下位サロゲートであれば0を返す。
EXPECT_EQ(CNativeW::GetKetaOfChar(L"\xd83c\xdf38", 2, 1), 0);
// 下位サロゲートだけなら2を返す。
EXPECT_EQ(CNativeW::GetKetaOfChar(L"\xdf38", 1, 0), 2);

// サクラエディタでは Unicode で表現できない文字コードの破壊を防ぐため、
// 不明バイトを下位サロゲートにマップして保持している。
// この1バイト文字は半角として扱わなければ不自然なので、
// 上位対を持たない下位サロゲート 0xdc00 ~ 0xdcff の範囲に限り、1を返すことになっている。
//
// https://sourceforge.net/p/sakura-editor/patchunicode/57/
// http://sakura-editor.sourceforge.net/cgi-bin/cyclamen/cyclamen.cgi?log=unicode&v=833
EXPECT_EQ(CNativeW::GetKetaOfChar(L"\xdbff", 1, 0), 2);
for (wchar_t ch = 0xdc00; ch <= 0xdcff; ++ch)
EXPECT_EQ(CNativeW::GetKetaOfChar(&ch, 1, 0), 1);
EXPECT_EQ(CNativeW::GetKetaOfChar(L"\xdd00", 1, 0), 2);

// 文字が半角なら1を返す。
EXPECT_EQ(CNativeW::GetKetaOfChar(L"a", 1, 0), 1);

// 文字が全角なら2を返す。
class FakeCache : public CCharWidthCache {
public:
bool CalcHankakuByFont(wchar_t c) const override { return false; }
} cache;
EXPECT_EQ(CNativeW::GetKetaOfChar(L"", 1, 0, cache), 2);
}

/*!
* @brief GetKetaOfCharの仕様
* @remark 指定した文字のピクセル単位幅を返す。
*/
TEST(CNativeW, GetHabaOfChar)
{
// 範囲外なら0を返す。
EXPECT_EQ((Int)CNativeW::GetHabaOfChar(L"", 0, 1, GetCharWidthCache(), false), 0);

// 改行コードなら1を返す。
EXPECT_EQ((Int)CNativeW::GetHabaOfChar(L"\r\n", 2, 0, GetCharWidthCache(), false), 1);
EXPECT_EQ((Int)CNativeW::GetHabaOfChar(L"\r\n", 2, 1, GetCharWidthCache(), false), 1);

// CalcPxWidthByFont で計算した結果を返す。
class FakeCache1 : public CCharWidthCache {
public:
int CalcPxWidthByFont(wchar_t ch) override {
if (ch == L'a') return 10000;
else if (ch == L'b') return 20000;
else return 0;
}
} cache1;
EXPECT_EQ((Int)CNativeW::GetHabaOfChar(L"ab", 2, 0, cache1, false), 10000);
EXPECT_EQ((Int)CNativeW::GetHabaOfChar(L"ab", 2, 1, cache1, false), 20000);

// サロゲートペアの幅は CalcPxWidthByFont2 で計算する。
// 指定された位置が下位サロゲートなら0を返す。
class FakeCache2 : public CCharWidthCache {
public:
int CalcPxWidthByFont2(const wchar_t* pc2) const override {
return 20000;
}
} cache2;
EXPECT_EQ((Int)CNativeW::GetHabaOfChar(L"\xd83c\xdf38", 2, 0, cache2, false), 20000);
EXPECT_EQ((Int)CNativeW::GetHabaOfChar(L"\xd83c\xdf38", 2, 1, cache2, false), 0);

// サロゲートペアが片方しかないときは CalcPxWidthByFont で計算している。
class FakeCache3 : public CCharWidthCache {
public:
int CalcPxWidthByFont(wchar_t c) override {
return 10000;
}
} cache3;
EXPECT_EQ((Int)CNativeW::GetHabaOfChar(L"\xd83c", 2, 0, cache3, false), 10000);
EXPECT_EQ((Int)CNativeW::GetHabaOfChar(L"\xdf38", 2, 0, cache3, false), 10000);
EXPECT_EQ((Int)CNativeW::GetHabaOfChar(L"\xdf38", 2, 1, cache3, false), 10000);
}

/*!
* @brief GetCharNextの仕様
*/
TEST(CNativeW, GetCharNext)
{
constexpr wchar_t* text = L"a\xd83c\xdf38";
// 次の文字のアドレスを返す。
EXPECT_EQ(CNativeW::GetCharNext(text, 3, text), text + 1);
// 上位サロゲートが渡された場合は下位サロゲートを飛ばす。
EXPECT_EQ(CNativeW::GetCharNext(text, 3, text + 1), text + 3);
// ポインタを進めた結果が範囲外なら &pData[nDataLen] を返す。
EXPECT_EQ(CNativeW::GetCharNext(text, 3, text + 3), text + 3);
}

/*!
* @brief GetCharPrevの仕様
*/
TEST(CNativeW, GetCharPrev)
{
constexpr wchar_t* text = L"a\xd83c\xdf38" L"d";
// 前の文字のアドレスを返す。
EXPECT_EQ(CNativeW::GetCharPrev(text, 4, text + 1), text);
// 前の文字が下位サロゲートだった場合は下位サロゲートを飛ばす。
EXPECT_EQ(CNativeW::GetCharPrev(text, 4, text + 3), text + 1);
// ポインタを戻した結果が範囲外なら pData を返す。
EXPECT_EQ(CNativeW::GetCharPrev(text, 4, text), text);
}

0 comments on commit 5407fd8

Please sign in to comment.