From beedca2fba5742bdfea84f5ee58168393777a5a5 Mon Sep 17 00:00:00 2001 From: Niels Martin Hansen Date: Wed, 24 Jun 2009 22:22:45 +0000 Subject: [PATCH] Fix #884, annoying wxString::Trim is destructive and there's no non-destructive variant. Adding a new function to utils.cpp to test whether a string is "blank", ie. empty or whitespace-only, as well as a function to check if a wchar_t is a whitspace character. Trimming was used to test whether a string was blank or not, and this caused the source syllable texts to be altered when the kanji interpolation algorithm was run. Originally committed to SVN as r3085. --- aegisub/src/auto4_lua_assfile.cpp | 3 ++- aegisub/src/auto4_ruby_assfile.cpp | 3 ++- aegisub/src/dialog_kanji_timer.cpp | 19 ++++++++--------- aegisub/src/utils.cpp | 33 ++++++++++++++++++++++++++++++ aegisub/src/utils.h | 2 ++ 5 files changed, 47 insertions(+), 13 deletions(-) diff --git a/aegisub/src/auto4_lua_assfile.cpp b/aegisub/src/auto4_lua_assfile.cpp index 0afdbba3c..f340d8982 100644 --- a/aegisub/src/auto4_lua_assfile.cpp +++ b/aegisub/src/auto4_lua_assfile.cpp @@ -42,6 +42,7 @@ #include "ass_style.h" #include "ass_file.h" #include "ass_override.h" +#include "utils.h" #ifdef __WINDOWS__ #include "../../contrib/lua51/src/lualib.h" @@ -78,7 +79,7 @@ namespace Automation4 { lua_pushstring(L, raw.mb_str(wxConvUTF8)); lua_setfield(L, -2, "raw"); - if (raw.Trim().IsEmpty()) { + if (StringEmptyOrWhitespace(raw)) { lua_pushstring(L, "clear"); } else if (raw[0] == _T(';')) { diff --git a/aegisub/src/auto4_ruby_assfile.cpp b/aegisub/src/auto4_ruby_assfile.cpp index ca992343b..5b985e4ce 100644 --- a/aegisub/src/auto4_ruby_assfile.cpp +++ b/aegisub/src/auto4_ruby_assfile.cpp @@ -46,6 +46,7 @@ #include "ass_style.h" #include "ass_file.h" #include "ass_override.h" +#include "utils.h" #include #include #include @@ -67,7 +68,7 @@ namespace Automation4 { rb_hash_aset(ass_entry, STR2SYM("raw"), rb_str_new2(e->GetEntryData().mb_str(wxConvUTF8))); VALUE entry_class; - if (raw.Trim().IsEmpty()) { + if (StringEmptyOrWhitespace(raw)) { entry_class = STR2SYM("clear"); } else if (raw[0] == _T(';')) { diff --git a/aegisub/src/dialog_kanji_timer.cpp b/aegisub/src/dialog_kanji_timer.cpp index b182ba73d..c289b1eac 100644 --- a/aegisub/src/dialog_kanji_timer.cpp +++ b/aegisub/src/dialog_kanji_timer.cpp @@ -64,11 +64,11 @@ class KaraokeLineMatchDisplay : public wxControl { struct MatchSyllable { int dur; wxString text; - MatchSyllable() : dur(0) { } + MatchSyllable(int _dur, const wxString &_text) : dur(_dur), text(_text) { } }; struct MatchGroup { - std::vector src; - typedef std::vector::iterator SrcIterator; + std::vector src; + typedef std::vector::iterator SrcIterator; wxString dst; int duration; int last_render_width; @@ -79,8 +79,8 @@ class KaraokeLineMatchDisplay : public wxControl { std::vector matched_groups; typedef std::vector::iterator MatchedGroupIterator; // Unmatched source syllables - std::deque unmatched_source; - typedef std::deque::iterator UnmatchedSourceIterator; + std::deque unmatched_source; + typedef std::deque::iterator UnmatchedSourceIterator; // Unmatched destination text wxString unmatched_destination; @@ -374,10 +374,7 @@ void KaraokeLineMatchDisplay::SetInputData(const AssDialogue *src, const AssDial // Start from 1 instead of 0: The first syllable is actually everything before the first for (size_t i = 1; i < kara.size(); ++i) { - MatchSyllable syl; - syl.text = kara[i].text; - syl.dur = kara[i].duration; - unmatched_source.push_back(syl); + unmatched_source.push_back(MatchSyllable(kara[i].duration, kara[i].text)); } delete varsrc; } @@ -521,7 +518,7 @@ void KaraokeLineMatchDisplay::AutoMatchJapanese() // Now the source syllable might consist of just whitespace. // Eat all whitespace at the start of the destination. - if (src.Trim().size() == 0) + if (StringEmptyOrWhitespace(src)) { trycatchingmorespaces: // ASCII space @@ -594,7 +591,7 @@ trycatchingmorespaces: // Yay! Time to interpolate. // Special case: If the last source syllable before the matching one is // empty or contains just whitespace, don't include that one. - if (src_lookahead_pos > 1 && unmatched_source[src_lookahead_pos-2].text.Trim().size() == 0) + if (src_lookahead_pos > 1 && StringEmptyOrWhitespace(unmatched_source[src_lookahead_pos-2].text)) src_lookahead_pos -= 1; // Special case: Just one source syllable matching, pick all destination found if (src_lookahead_pos == 2) diff --git a/aegisub/src/utils.cpp b/aegisub/src/utils.cpp index 9e193a674..e305dde74 100644 --- a/aegisub/src/utils.cpp +++ b/aegisub/src/utils.cpp @@ -303,6 +303,39 @@ void GetWordBoundaries(const wxString text,IntPairVector &results,int start,int } +///////////////////////////////////////////////////////// +// Determine whether wchar 'c' is a whitespace character +bool IsWhitespace(wchar_t c) +{ + const wchar_t whitespaces[] = { + // http://en.wikipedia.org/wiki/Space_(punctuation)#Table_of_spaces + 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x0020, 0x0085, 0x00A0, + 0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, + 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x2028, 0x2029, 0x202F, + 0x025F, 0x3000, 0xFEFF + }; + const size_t num_chars = sizeof(whitespaces) / sizeof(whitespaces[0]); + + for (size_t i = 0; i < num_chars; ++i) + if (whitespaces[i] == c) + return true; + + return false; +} + + +/////////////////////////////////////////////////////////////// +// Returns true if str is empty of consists of only whitespace +bool StringEmptyOrWhitespace(const wxString &str) +{ + for (size_t i = 0; i < str.size(); ++i) + if (!IsWhitespace(str[i])) + return false; + + return true; +} + + ///////////////////// // String to integer // wxString::ToLong() is slow and not as flexible diff --git a/aegisub/src/utils.h b/aegisub/src/utils.h index 2d8c1ba5b..88965a46a 100644 --- a/aegisub/src/utils.h +++ b/aegisub/src/utils.h @@ -68,6 +68,8 @@ wxString PrettySize(int bytes); wxMenuItem *AppendBitmapMenuItem (wxMenu* parentMenu,int id,wxString text,wxString help,wxBitmap bmp,int pos=-1); int SmallestPowerOf2(int x); void GetWordBoundaries(const wxString text,IntPairVector &results,int start=0,int end=-1); +bool IsWhitespace(wchar_t c); +bool StringEmptyOrWhitespace(const wxString &str); int AegiStringToInt(const wxString &str,int start=0,int end=-1); int AegiStringToFix(const wxString &str,size_t decimalPlaces,int start=0,int end=-1); wxIcon BitmapToIcon(wxBitmap bmp);