Skip to content

Commit

Permalink
Add thread view text drawing method choice to about:config (#1259)
Browse files Browse the repository at this point in the history
about:config に「スレビューのテキストを描画する方法
( 0: PangoGlyphString 1: PangoLayout )」を追加します。
ビルドオプション(`-Dpangolayout=enabled`)は削除せず残し
デフォルト設定の方法を指定します。

修正前は描画方法をビルドオプションで指定していました。
2つの方法(PangoLayoutとPangoGlyphString)はpangoライブラリで
実装できるため設定で変更できる仕組みを導入して利便性を向上させます。
  • Loading branch information
ma8ma committed Sep 30, 2023
1 parent a06d8c2 commit 350e30a
Show file tree
Hide file tree
Showing 10 changed files with 162 additions and 77 deletions.
3 changes: 3 additions & 0 deletions INSTALL
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@
描画にPangoLayoutを使う。デフォルトでは PangoGlyphString を使用する。
スレビューのテキスト表示に問題があるときはこのオプションを試してみてください。

about:config 「スレビューのテキストを描画する方法 ( 0: PangoGlyphString 1: PangoLayout )」で変更が可能。
変更後に開いたスレから適用される。 (v0.10.1-20230930から追加)

-Dmigemo=enabled

migemoによる検索が有効になる。migemoがUTF-8の辞書でインストールされている必要がある。
Expand Down
4 changes: 3 additions & 1 deletion docs/manual/make.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ OSやディストリビューション別の解説は [#592][dis592] を参照
<dt>-Dpangolayout=enabled</dt>
<dd>
描画に PangoLayout を使う。デフォルトでは PangoGlyphString を使用する。
スレビューのテキスト表示に問題があるときはこのオプションを試してみてください。
スレビューのテキスト表示に問題があるときはこのオプションを試してみてください。<br>
about:config 「スレビューのテキストを描画する方法 ( 0: PangoGlyphString 1: PangoLayout )」で変更が可能。
変更後に開いたスレから適用される。 <small>(v0.10.1-20230930から追加)</small>
</dd>
<dt>-Dmigemo=enabled</dt>
<dd>
Expand Down
193 changes: 117 additions & 76 deletions src/article/drawareabase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,15 @@
#include "cssmanager.h"
#include "session.h"

#include <pangomm/glyphstring.h>

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <limits>
#include <sstream>

#ifndef USE_PANGOLAYOUT
#include <pangomm/glyphstring.h>
#endif

using namespace ARTICLE;

Expand Down Expand Up @@ -126,6 +125,8 @@ DrawAreaBase::DrawAreaBase( const std::string& url )
, m_pre_pos_y{ -1 }
, m_back_marker( nullptr, cairo_surface_destroy )
, m_cursor_type( cursor_names::kDefault )
, m_render_text{ CONFIG::get_text_rendering_method() == 0 ? &DrawAreaBase::render_text_glyphstring
: &DrawAreaBase::render_text_pangolayout }
{
#ifdef _DEBUG
std::cout << "DrawAreaBase::DrawAreaBase " << m_url << std::endl;;
Expand Down Expand Up @@ -2530,7 +2531,9 @@ void DrawAreaBase::draw_one_text_node( LAYOUT* layout, const CLIPINFO& ci )
if( byte_from ) draw_string( layout, ci, color_text, color_back, 0, byte_from );

//
if( byte_to != strlen( layout->text ) ) draw_string( layout, ci, color_text, color_back, byte_to, strlen( layout->text ) );
if( const auto len = std::strlen( layout->text ); byte_to != len ) {
draw_string( layout, ci, color_text, color_back, byte_to, len );
}
}

// 検索結果のハイライト
Expand Down Expand Up @@ -2696,14 +2699,20 @@ bool DrawAreaBase::draw_one_img_node( LAYOUT* layout, const CLIPINFO& ci )



//
// 文字を描画する関数
//
// ノードの byte_from バイト目の文字から byte_to バイト目の「ひとつ前」の文字まで描画
// byte_to が 0 なら最後まで描画
//
// たとえば node->text = "abcdefg" で byte_from = 1, byte_to = 3 なら "bc" を描画
//
/** @brief 文字を描画する関数
*
* @details ノードの byte_from バイト目の文字から byte_to バイト目の「ひとつ前」の文字まで描画<br>
* byte_to が 0 なら最後まで描画<br>
* <br>
* たとえば node->text = "abcdefg" で byte_from = 1, byte_to = 3 なら "bc" を描画
*
* @param[in] node 文字列を含むレイアウトのデータ
* @param[in] ci 描画領域のデータ
* @param[in] color 文字色のID
* @param[in] color_back 背景色のID
* @param[in] byte_from 描画をする文字列の始点(バイト目)
* @param[in] byte_to 描画をする文字列の終点(上記参照)
*/
void DrawAreaBase::draw_string( LAYOUT* node, const CLIPINFO& ci,
const int color, const int color_back, const int byte_from, const int byte_to )
{
Expand Down Expand Up @@ -2773,72 +2782,23 @@ void DrawAreaBase::draw_string( LAYOUT* node, const CLIPINFO& ci,

const int xx = x;

#ifdef USE_PANGOLAYOUT // Pango::Layout を使って文字を描画

const Gdk::RGBA& fg = m_color[ color ];
const Gdk::RGBA& bg = m_color[ color_back ];
using PA = Pango::Attribute;
auto foreground = PA::create_attr_foreground( fg.get_red_u(), fg.get_green_u(), fg.get_blue_u() );
auto background = PA::create_attr_background( bg.get_red_u(), bg.get_green_u(), bg.get_blue_u() );

m_pango_layout->set_text( Glib::ustring( node->text + pos_start, n_ustr ) );

cairo_t* const text_cr = cairo_create( m_backscreen.get() );

Pango::AttrList attr;
attr.insert( foreground );
attr.insert( background );
m_pango_layout->set_attributes( attr );
cairo_move_to( text_cr, x, y );
pango_cairo_show_layout( text_cr, m_pango_layout->gobj() );

// Pango::Weight属性を使うと文字幅が変わりレイアウトが乱れる
// そこで文字を重ねて描画することで太字を表示する
if( node->bold ) {
Pango::AttrList overlapping;
overlapping.insert( foreground );
m_pango_layout->set_attributes( overlapping );
cairo_move_to( text_cr, x + 1.0, y );
pango_cairo_show_layout( text_cr, m_pango_layout->gobj() );
}

#else // Pango::GlyphString を使って文字を描画

assert( m_context );

fill_backscreen( color_back, x, y, width_line, m_font->height );

cairo_t* const text_cr = cairo_create( m_backscreen.get() );

gdk_cairo_set_source_rgba( text_cr, m_color[ color ].gobj() );

Pango::AttrList attr;
const auto text = Glib::ustring( node->text + pos_start, n_ustr );
const std::vector<Pango::Item> list_item = m_context->itemize( text, attr );

Glib::RefPtr< Pango::Font > font;
Pango::GlyphString grl;
cairo_t* text_cr = cairo_create( m_backscreen.get() );

for( const Pango::Item& item : list_item ) {
RenderTextArguments args = {
text_cr,
rect, // NOTE: rect->width の値は更新されることがある
node->text + pos_start,
n_ustr,
x,
y,
color,
color_back,
width_line,
byte_to,
node->bold,
};

font = item.get_analysis().get_font();
grl = item.shape( item.get_segment( text ) );
const int width = PANGO_PIXELS( grl.get_width() );

cairo_move_to( text_cr, x, y + m_font->ascent );
pango_cairo_show_glyph_string( text_cr, font->gobj(), grl.gobj() );
if( node->bold ) {
cairo_move_to( text_cr, x + 1.0, y + m_font->ascent );
pango_cairo_show_glyph_string( text_cr, font->gobj(), grl.gobj() );
}

x += width;
}

// 実際のラインの長さ(x - rect->x)とlayout_one_text_node()で計算した
// 近似値(rect->width)を一致させる ( 応急処置 )
if( ! byte_to && abs( ( x - rect->x ) - rect->width ) > 2 ) rect->width = x - rect->x;
#endif // USE_PANGOLAYOUT
(this->*m_render_text)( args );

// リンクの時は下線を引く
if( node->link && CONFIG::get_draw_underline() ){
Expand All @@ -2858,6 +2818,87 @@ void DrawAreaBase::draw_string( LAYOUT* node, const CLIPINFO& ci,
}


/** @brief 文字を描画する関数 (Pango::GlyphString を使うバージョン)
*
* @param[in] args 文字の描写に使うデータ
*/
void DrawAreaBase::render_text_glyphstring( RenderTextArguments& args )
{
assert( m_context );

// forループで繰り返し使われるものはローカル変数にコピーする
cairo_t* text_cr = args.text_cr;
int x = args.x;
const int y = args.y;
const bool bold = args.bold;

fill_backscreen( args.color_back, x, y, args.width_line, m_font->height );

gdk_cairo_set_source_rgba( text_cr, m_color[ args.color ].gobj() );

Pango::AttrList attr;
const auto text = Glib::ustring( args.text, args.n_ustr );
const std::vector<Pango::Item> list_item = m_context->itemize( text, attr );

Glib::RefPtr<Pango::Font> font;
Pango::GlyphString grl;

for( const Pango::Item& item : list_item ) {

font = item.get_analysis().get_font();
grl = item.shape( item.get_segment( text ) );
const int width = PANGO_PIXELS( grl.get_width() );

cairo_move_to( text_cr, x, y + m_font->ascent );
pango_cairo_show_glyph_string( text_cr, font->gobj(), grl.gobj() );
if( bold ) {
cairo_move_to( text_cr, x + 1.0, y + m_font->ascent );
pango_cairo_show_glyph_string( text_cr, font->gobj(), grl.gobj() );
}

x += width;
}

// 実際のラインの長さ(x - rect->x)とlayout_one_text_node()で計算した
// 近似値(rect->width)を一致させる ( 応急処置 )
if( ! args.byte_to && std::abs( ( x - args.rect->x ) - args.rect->width ) > 2 ) {
args.rect->width = x - args.rect->x;
}
}


/** @brief 文字を描画する関数 (Pango::Layout を使うバージョン)
*
* @param[in] args 文字の描写に使うデータ
*/
void DrawAreaBase::render_text_pangolayout( RenderTextArguments& args )
{
const Gdk::RGBA& fg = m_color[ args.color ];
const Gdk::RGBA& bg = m_color[ args.color_back ];
using PA = Pango::Attribute;
auto foreground = PA::create_attr_foreground( fg.get_red_u(), fg.get_green_u(), fg.get_blue_u() );
auto background = PA::create_attr_background( bg.get_red_u(), bg.get_green_u(), bg.get_blue_u() );

m_pango_layout->set_text( Glib::ustring( args.text, args.n_ustr ) );

Pango::AttrList attr;
attr.insert( foreground );
attr.insert( background );
m_pango_layout->set_attributes( attr );
cairo_move_to( args.text_cr, args.x, args.y );
pango_cairo_show_layout( args.text_cr, m_pango_layout->gobj() );

// Pango::Weight属性を使うと文字幅が変わりレイアウトが乱れる
// そこで文字を重ねて描画することで太字を表示する
if( args.bold ) {
Pango::AttrList overlapping;
overlapping.insert( foreground );
m_pango_layout->set_attributes( overlapping );
cairo_move_to( args.text_cr, args.x + 1.0, args.y );
pango_cairo_show_layout( args.text_cr, m_pango_layout->gobj() );
}
}


/** @brief 整数 -> 文字列変換してレイアウトに何番目の投稿と発言数をセット
*
Expand Down
21 changes: 21 additions & 0 deletions src/article/drawareabase.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,22 @@ namespace ARTICLE
int lower; // 画面下、大きい値
};

/// @brief 文字を描写する関数は変数が多いため構造体を使って参照を渡す
struct RenderTextArguments
{
cairo_t* text_cr;
struct RECTANGLE* rect; // NOTE: rect->width は更新されることがある
const char* text;
int n_ustr;
int x;
int y;
int color;
int color_back;
int width_line;
int byte_to;
bool bold;
};

///////////////////////////////////


Expand Down Expand Up @@ -242,6 +258,9 @@ namespace ARTICLE
guint id; // コールバックのID
} m_deceleration{};

/// @brief 文字を描画するメンバー関数の関数ポインター
void (DrawAreaBase::*m_render_text)( RenderTextArguments& args );

public:

SIG_BUTTON_PRESS sig_button_press(){ return m_sig_button_press; }
Expand Down Expand Up @@ -423,6 +442,8 @@ namespace ARTICLE
void draw_one_text_node( LAYOUT* layout, const CLIPINFO& ci );
void draw_string( LAYOUT* node, const CLIPINFO& ci,
const int color, const int color_back, const int byte_from, const int byte_to );
void render_text_glyphstring( RenderTextArguments& args );
void render_text_pangolayout( RenderTextArguments& args );
bool draw_one_img_node( LAYOUT* layout, const CLIPINFO& ci );
char get_layout_fontid(LAYOUT *layout ) const;
void set_node_font( LAYOUT* layout );
Expand Down
1 change: 1 addition & 0 deletions src/config/aboutconfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ void AboutConfig::append_rows()
append_row( "書き込み履歴のあるスレを削除する時にダイアログを表示", get_confitem()->show_del_written_thread_diag, CONF_SHOW_DEL_WRITTEN_THREAD_DIAG );
append_row( "スレを削除する時に画像キャッシュも削除する ( 0: ダイアログ表示 1: 削除 2: 削除しない )", get_confitem()->delete_img_in_thread, CONF_DELETE_IMG_IN_THREAD );
append_row( "最大表示可能レス数", get_confitem()->max_resnumber, CONF_MAX_RESNUMBER );
append_row( "スレビューのテキストを描画する方法 ( 0: PangoGlyphString 1: PangoLayout )", get_confitem()->text_rendering_method, CONF_TEXT_RENDERING_METHOD );

// 書き込みウィンドウ
append_row( "" );
Expand Down
4 changes: 4 additions & 0 deletions src/config/configitems.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,9 @@ bool ConfigItems::load( const bool restore )
//最大表示可能レス数
max_resnumber = cf.get_option_int( "max_resnumber", CONF_MAX_RESNUMBER, 1, std::numeric_limits< int >::max() - 1 );

// スレビューのテキストを描画する方法 ( 0: PangoGlyphString 1: PangoLayout )
text_rendering_method = cf.get_option_int( "text_rendering_method", CONF_TEXT_RENDERING_METHOD, 0, 1 );

// FIFOの作成などにエラーがあったらダイアログを表示する
show_diag_fifo_error = cf.get_option_bool( "show_diag_fifo_error", CONF_SHOW_DIAG_FIFO_ERROR );

Expand Down Expand Up @@ -954,6 +957,7 @@ void ConfigItems::save_impl( const std::string& path )
cf.update( "show_del_written_thread_diag", show_del_written_thread_diag );
cf.update( "delete_img_in_thread", delete_img_in_thread );
cf.update( "max_resnumber", max_resnumber );
cf.update( "text_rendering_method", text_rendering_method );
cf.update( "show_diag_fifo_error", show_diag_fifo_error );
cf.update( "save_session", save_session );

Expand Down
3 changes: 3 additions & 0 deletions src/config/configitems.h
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,9 @@ namespace CONFIG
//最大表示可能レス数
int max_resnumber{};

/// @brief スレビューのテキストを描画する方法 ( 0: PangoGlyphString 1: PangoLayout )
int text_rendering_method{};

// FIFOの作成などにエラーがあったらダイアログを表示する
bool show_diag_fifo_error{};

Expand Down
5 changes: 5 additions & 0 deletions src/config/defaultconf.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,11 @@ namespace CONFIG
CONF_SHOW_DEL_WRITTEN_THREAD_DIAG = 1, // 書き込み履歴のあるスレを削除する時にダイアログを表示
CONF_DELETE_IMG_IN_THREAD = 0, // スレを削除する時に画像キャッシュも削除する ( 0: ダイアログ表示 1: 削除 2: 削除しない )
CONF_MAX_RESNUMBER = 65536, //最大表示可能レス数
#ifdef USE_PANGOLAYOUT
CONF_TEXT_RENDERING_METHOD = 1, ///< スレビューのテキストを描画する方法 ( 0: PangoGlyphString 1: PangoLayout )
#else
CONF_TEXT_RENDERING_METHOD = 0, ///< スレビューのテキストを描画する方法 ( 0: PangoGlyphString 1: PangoLayout )
#endif
CONF_SHOW_DIAG_FIFO_ERROR = 1, // FIFOの作成などにエラーがあったらダイアログを表示する
CONF_SAVE_SESSION = 0, // 指定した分ごとにセッションを自動保存 (0: 保存しない)
CONF_BROKEN_SJIS_BE_UTF8 = 0, ///< 不正なMS932文字列をUTF-8と見なす
Expand Down
2 changes: 2 additions & 0 deletions src/config/globalconf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,8 @@ void CONFIG::set_delete_img_in_thread( const int set ){ get_confitem()->delete_i
int CONFIG::get_max_resnumber(){ return get_confitem()->max_resnumber; }
void CONFIG::set_max_resnumber( const int set ){ get_confitem()->max_resnumber = set; }

/// @brief スレビューのテキストを描画する方法 ( 0: PangoGlyphString 1: PangoLayout )
int CONFIG::get_text_rendering_method() { return get_confitem()->text_rendering_method; }

// FIFOの作成などにエラーがあったらダイアログを表示する
bool CONFIG::get_show_diag_fifo_error(){ return get_confitem()->show_diag_fifo_error; }
Expand Down
3 changes: 3 additions & 0 deletions src/config/globalconf.h
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,9 @@ namespace CONFIG
int get_max_resnumber();
void set_max_resnumber( const int set );

// スレビューのテキストを描画する方法 ( 0: PangoGlyphString 1: PangoLayout )
int get_text_rendering_method();

// FIFOの作成などにエラーがあったらダイアログを表示する
bool get_show_diag_fifo_error();
void set_show_diag_fifo_error( const bool set );
Expand Down

0 comments on commit 350e30a

Please sign in to comment.