gosu 0.12.1 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/Gosu/Audio.hpp +23 -25
  3. data/Gosu/Graphics.hpp +16 -12
  4. data/Gosu/Image.hpp +3 -0
  5. data/Gosu/Version.hpp +2 -2
  6. data/lib/gosu.rb +2 -2
  7. data/lib/gosu/compat.rb +1 -1
  8. data/lib/gosu/patches.rb +5 -0
  9. data/lib/gosu/swig_patches.rb +1 -1
  10. data/rdoc/gosu.rb +10 -10
  11. data/src/Audio.cpp +93 -228
  12. data/src/AudioImpl.cpp +94 -0
  13. data/src/AudioImpl.hpp +33 -0
  14. data/src/AudioToolboxFile.hpp +14 -18
  15. data/src/Bitmap.cpp +36 -30
  16. data/src/BitmapIO.cpp +14 -23
  17. data/src/BlockAllocator.cpp +7 -10
  18. data/src/BlockAllocator.hpp +2 -4
  19. data/src/Channel.cpp +89 -0
  20. data/src/Color.cpp +4 -9
  21. data/src/DirectoriesApple.cpp +13 -13
  22. data/src/DirectoriesUnix.cpp +8 -7
  23. data/src/DirectoriesWin.cpp +12 -11
  24. data/src/EmptyImageData.hpp +54 -0
  25. data/src/FileUnix.cpp +12 -9
  26. data/src/FileWin.cpp +8 -7
  27. data/src/Font.cpp +12 -13
  28. data/src/FormattedString.cpp +237 -0
  29. data/src/FormattedString.hpp +14 -265
  30. data/src/GosuViewController.cpp +2 -5
  31. data/src/Graphics.cpp +38 -39
  32. data/src/IO.cpp +11 -10
  33. data/src/Image.cpp +16 -9
  34. data/src/Input.cpp +16 -15
  35. data/src/InputUIKit.cpp +8 -7
  36. data/src/Macro.cpp +11 -11
  37. data/src/Math.cpp +9 -8
  38. data/src/RubyGosu.cxx +129 -99
  39. data/src/TextApple.cpp +19 -13
  40. data/src/TextInput.cpp +23 -22
  41. data/src/TextWin.cpp +17 -19
  42. data/src/Texture.cpp +15 -10
  43. data/src/Transform.cpp +13 -17
  44. data/src/Utility.cpp +3 -2
  45. data/src/UtilityApple.cpp +10 -11
  46. data/src/UtilityWin.cpp +2 -1
  47. data/src/Version.cpp +5 -4
  48. data/src/WinMain.cpp +3 -3
  49. data/src/WinUtility.cpp +7 -6
  50. data/src/Window.cpp +11 -10
  51. data/src/WindowUIKit.cpp +9 -8
  52. data/src/stb_image.h +782 -480
  53. data/src/stb_image_write.h +425 -15
  54. data/src/stb_vorbis.c +82 -32
  55. metadata +8 -4
  56. data/src/ALChannelManagement.hpp +0 -119
@@ -4,7 +4,8 @@
4
4
  #include "WinUtility.hpp"
5
5
  #include <Gosu/IO.hpp>
6
6
  #include <Gosu/Utility.hpp>
7
- #include <windows.h>
7
+ #include <windows.h>
8
+ using namespace std;
8
9
 
9
10
  // TODO: Error checking
10
11
 
@@ -20,7 +21,7 @@ struct Gosu::File::Impl
20
21
  }
21
22
  };
22
23
 
23
- Gosu::File::File(const std::string& filename, FileMode mode)
24
+ Gosu::File::File(const string& filename, FileMode mode)
24
25
  : pimpl(new Impl)
25
26
  {
26
27
  DWORD access;
@@ -38,7 +39,7 @@ Gosu::File::File(const std::string& filename, FileMode mode)
38
39
  DWORD share_mode = FILE_SHARE_READ;
39
40
  DWORD creation_disp = (mode == FM_READ) ? OPEN_EXISTING : OPEN_ALWAYS;
40
41
 
41
- std::wstring wfilename = utf8_to_wstring(filename);
42
+ wstring wfilename = utf8_to_wstring(filename);
42
43
  pimpl->handle = CreateFileW(wfilename.c_str(), access, share_mode, 0, creation_disp,
43
44
  FILE_ATTRIBUTE_NORMAL, 0);
44
45
  if (pimpl->handle == INVALID_HANDLE_VALUE) {
@@ -53,12 +54,12 @@ Gosu::File::~File()
53
54
  {
54
55
  }
55
56
 
56
- std::size_t Gosu::File::size() const
57
+ size_t Gosu::File::size() const
57
58
  {
58
59
  return GetFileSize(pimpl->handle, 0);
59
60
  }
60
61
 
61
- void Gosu::File::resize(std::size_t new_size)
62
+ void Gosu::File::resize(size_t new_size)
62
63
  {
63
64
  if (SetFilePointer(pimpl->handle, new_size, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
64
65
  throw_last_winapi_error("setting the file pointer");
@@ -66,7 +67,7 @@ void Gosu::File::resize(std::size_t new_size)
66
67
  winapi_check(SetEndOfFile(pimpl->handle), "resizing a file");
67
68
  }
68
69
 
69
- void Gosu::File::read(std::size_t offset, std::size_t length, void* dest_buffer) const
70
+ void Gosu::File::read(size_t offset, size_t length, void* dest_buffer) const
70
71
  {
71
72
  if (SetFilePointer(pimpl->handle, offset, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
72
73
  throw_last_winapi_error("setting the file pointer");
@@ -75,7 +76,7 @@ void Gosu::File::read(std::size_t offset, std::size_t length, void* dest_buffer)
75
76
  winapi_check(ReadFile(pimpl->handle, dest_buffer, length, &dummy, 0));
76
77
  }
77
78
 
78
- void Gosu::File::write(std::size_t offset, std::size_t length, const void* source_buffer)
79
+ void Gosu::File::write(size_t offset, size_t length, const void* source_buffer)
79
80
  {
80
81
  if (SetFilePointer(pimpl->handle, offset, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
81
82
  throw_last_winapi_error("setting the file pointer");
@@ -5,6 +5,7 @@
5
5
  #include <Gosu/Image.hpp>
6
6
  #include <Gosu/Math.hpp>
7
7
  #include <Gosu/Text.hpp>
8
+ #include <Gosu/Utility.hpp>
8
9
  #include <array>
9
10
  #include <cassert>
10
11
  #include <map>
@@ -19,11 +20,11 @@ struct Gosu::Font::Impl
19
20
  // the first plane will ever be touched.
20
21
  struct CharInfo
21
22
  {
22
- std::unique_ptr<Image> image;
23
+ unique_ptr<Image> image;
23
24
  double factor;
24
25
  };
25
26
  typedef array<CharInfo, 65536> Plane;
26
- std::unique_ptr<Plane> planes[16][FF_COMBINATIONS];
27
+ unique_ptr<Plane> planes[16][FF_COMBINATIONS];
27
28
 
28
29
  map<string, shared_ptr<Image>> entity_cache;
29
30
 
@@ -57,7 +58,7 @@ struct Gosu::Font::Impl
57
58
 
58
59
  if (info.image.get()) return *info.image;
59
60
 
60
- std::string char_string = wstring_to_utf8(std::wstring(1, wc));
61
+ string char_string = wstring_to_utf8(wstring(1, wc));
61
62
  // TODO: Would be nice to have.
62
63
  // if (is_formatting_char(wc))
63
64
  // char_string.clear();
@@ -102,7 +103,7 @@ unsigned Gosu::Font::flags() const
102
103
 
103
104
  double Gosu::Font::text_width(const string& text, double scale_x) const
104
105
  {
105
- std::wstring wtext = utf8_to_wstring(text);
106
+ wstring wtext = utf8_to_wstring(text);
106
107
  FormattedString fs(wtext.c_str(), flags());
107
108
  double result = 0;
108
109
  for (unsigned i = 0; i < fs.length(); ++i) {
@@ -116,15 +117,15 @@ double Gosu::Font::text_width(const string& text, double scale_x) const
116
117
  void Gosu::Font::draw(const string& text, double x, double y, ZPos z,
117
118
  double scale_x, double scale_y, Color c, AlphaMode mode) const
118
119
  {
119
- std::wstring wtext = utf8_to_wstring(text);
120
+ wstring wtext = utf8_to_wstring(text);
120
121
  FormattedString fs(wtext.c_str(), flags());
121
122
 
122
123
  for (unsigned i = 0; i < fs.length(); ++i) {
123
124
  const Image& image = pimpl->image_at(fs, i);
124
125
  double factor = pimpl->factor_at(fs, i);
125
- Gosu::Color color = fs.entity_at(i)
126
- ? Gosu::Color(fs.color_at(i).alpha() * c.alpha() / 255, 255, 255, 255)
127
- : Gosu::multiply(fs.color_at(i), c);
126
+ Color color = fs.entity_at(i)
127
+ ? Color(fs.color_at(i).alpha() * c.alpha() / 255, 255, 255, 255)
128
+ : multiply(fs.color_at(i), c);
128
129
  image.draw(x, y, z, scale_x * factor, scale_y * factor, color, mode);
129
130
  x += image.width() * scale_x * factor;
130
131
  }
@@ -149,17 +150,15 @@ void Gosu::Font::set_image(wchar_t wc, const Image& image)
149
150
  void Gosu::Font::set_image(wchar_t wc, unsigned font_flags, const Image& image)
150
151
  {
151
152
  Impl::CharInfo& ci = pimpl->char_info(wc, font_flags);
152
- if (ci.image.get()) {
153
- throw logic_error("Cannot set image for the same character twice");
154
- }
155
- ci.image.reset(new Gosu::Image(image));
153
+ if (ci.image.get()) throw logic_error("Cannot set image for the same character twice");
154
+ ci.image.reset(new Image(image));
156
155
  ci.factor = 1.0;
157
156
  }
158
157
 
159
158
  void Gosu::Font::draw_rot(const string& text, double x, double y, ZPos z, double angle,
160
159
  double scale_x, double scale_y, Color c, AlphaMode mode) const
161
160
  {
162
- Gosu::Graphics::transform(rotate(angle, x, y), [&] {
161
+ Graphics::transform(rotate(angle, x, y), [&] {
163
162
  draw(text, x, y, z, scale_x, scale_y, c, mode);
164
163
  });
165
164
  }
@@ -0,0 +1,237 @@
1
+ #include "FormattedString.hpp"
2
+ #include <Gosu/Utility.hpp>
3
+ #include <cwchar>
4
+ #include <cwctype>
5
+ using namespace std;
6
+
7
+ static unsigned flags(int b, int u, int i)
8
+ {
9
+ unsigned flags = 0;
10
+ if (b > 0) flags |= Gosu::FF_BOLD;
11
+ if (u > 0) flags |= Gosu::FF_UNDERLINE;
12
+ if (i > 0) flags |= Gosu::FF_ITALIC;
13
+ return flags;
14
+ }
15
+
16
+ bool Gosu::FormattedString::FormattedChar::same_style_as(const FormattedChar& other) const
17
+ {
18
+ return wc && other.wc && color == other.color && flags == other.flags;
19
+ }
20
+
21
+ Gosu::FormattedString::FormattedString()
22
+ {
23
+ }
24
+
25
+ Gosu::FormattedString::FormattedString(const wchar_t* html, unsigned base_flags)
26
+ {
27
+ // Remove \r characters if existent. Avoid a copy if we don't need one.
28
+ wstring unixified;
29
+ // We have to explicitly qualify wcschr to avoid an ambiguity on macOS.
30
+ if (std::wcschr(html, L'\r')) {
31
+ unixified.resize(wcslen(html));
32
+ unsigned pos = 0;
33
+ while (*html) {
34
+ if (*html != '\r') {
35
+ unixified[pos++] = *html;
36
+ }
37
+ ++html;
38
+ }
39
+ unixified.resize(pos);
40
+ html = unixified.c_str();
41
+ }
42
+
43
+ size_t len = wcslen(html);
44
+
45
+ // Just skip all this if there are entities or formatting tags in the string.
46
+ if (wcscspn(html, L"<&") == len) {
47
+ simple_string = html;
48
+ simple_flags = base_flags;
49
+ return;
50
+ }
51
+
52
+ unsigned pos = 0;
53
+ int b = (base_flags & FF_BOLD) ? 1 : 0,
54
+ u = (base_flags & FF_UNDERLINE) ? 1 : 0,
55
+ i = (base_flags & FF_ITALIC) ? 1 : 0;
56
+ vector<Color> c;
57
+ c.push_back(0xffffffff);
58
+ while (pos < len) {
59
+ if (!wcsncmp(html + pos, L"<b>", 3)) {
60
+ b += 1;
61
+ pos += 3;
62
+ continue;
63
+ }
64
+ if (!wcsncmp(html + pos, L"</b>", 4)) {
65
+ b -= 1;
66
+ pos += 4;
67
+ continue;
68
+ }
69
+ if (!wcsncmp(html + pos, L"<u>", 3)) {
70
+ u += 1;
71
+ pos += 3;
72
+ continue;
73
+ }
74
+ if (!wcsncmp(html + pos, L"</u>", 4)) {
75
+ u -= 1;
76
+ pos += 4;
77
+ continue;
78
+ }
79
+ if (!wcsncmp(html + pos, L"<i>", 3)) {
80
+ i += 1;
81
+ pos += 3;
82
+ continue;
83
+ }
84
+ if (!wcsncmp(html + pos, L"</i>", 4)) {
85
+ i -= 1;
86
+ pos += 4;
87
+ continue;
88
+ }
89
+ if (!wcsncmp(html + pos, L"<c=", 3) && len >= pos + 10 && html[pos + 9] == L'>') {
90
+ unsigned rgb = static_cast<uint32_t>(wcstoul(html + pos + 3, 0, 16));
91
+ c.push_back(0xff000000 | rgb);
92
+ pos += 10;
93
+ continue;
94
+ }
95
+ if (!wcsncmp(html + pos, L"<c=", 3) && len >= pos + 12 && html[pos + 11] == L'>') {
96
+ unsigned argb = static_cast<uint32_t>(wcstoul(html + pos + 3, 0, 16));
97
+ c.push_back(argb);
98
+ pos += 12;
99
+ continue;
100
+ }
101
+ if (!wcsncmp(html + pos, L"</c>", 4)) {
102
+ if (c.size() > 1) {
103
+ c.pop_back();
104
+ }
105
+ pos += 4;
106
+ continue;
107
+ }
108
+ if (!wcsncmp(html + pos, L"&lt;", 4)) {
109
+ FormattedChar fc = { L'<', c.back(), flags(b, u, i) };
110
+ characters.push_back(fc);
111
+ pos += 4;
112
+ continue;
113
+ }
114
+ if (!wcsncmp(html + pos, L"&gt;", 4)) {
115
+ FormattedChar fc = { L'>', c.back(), flags(b, u, i) };
116
+ characters.push_back(fc);
117
+ pos += 4;
118
+ continue;
119
+ }
120
+ if (!wcsncmp(html + pos, L"&amp;", 5)) {
121
+ FormattedChar fc = { L'&', c.back(), flags(b, u, i) };
122
+ characters.push_back(fc);
123
+ pos += 5;
124
+ continue;
125
+ }
126
+ if (html[pos] == L'&' && html[pos + 1]) {
127
+ int end_of_entity = pos + 1;
128
+ while (html[end_of_entity] != L';') {
129
+ if (!iswalnum(static_cast<wint_t>(html[end_of_entity]))) {
130
+ goto normal_character;
131
+ }
132
+ end_of_entity += 1;
133
+ if (end_of_entity >= len) {
134
+ goto normal_character;
135
+ }
136
+ }
137
+ wstring entity(html + pos + 1, html + end_of_entity);
138
+ FormattedChar fc = { 0, c.back(), 0, wstring_to_utf8(entity) };
139
+ if (!is_entity(fc.entity)) {
140
+ goto normal_character;
141
+ }
142
+ characters.push_back(fc);
143
+ pos = end_of_entity + 1;
144
+ continue;
145
+ }
146
+
147
+ normal_character:
148
+ FormattedChar fc = { html[pos], c.back(), flags(b, u, i) };
149
+ characters.push_back(fc);
150
+ pos += 1;
151
+ }
152
+ }
153
+
154
+ wstring Gosu::FormattedString::unformat() const
155
+ {
156
+ if (characters.empty()) return simple_string;
157
+
158
+ wstring result(characters.size(), 0);
159
+ for (int i = 0; i < characters.size(); ++i) {
160
+ result[i] = characters[i].wc;
161
+ }
162
+ return result;
163
+ }
164
+
165
+ const char* Gosu::FormattedString::entity_at(unsigned index) const
166
+ {
167
+ if (characters.empty()) return nullptr;
168
+ if (characters[index].wc != 0) return nullptr;
169
+ if (characters[index].entity.empty()) return nullptr;
170
+
171
+ return characters[index].entity.c_str();
172
+ }
173
+
174
+ wchar_t Gosu::FormattedString::char_at(unsigned index) const
175
+ {
176
+ return characters.empty() ? simple_string[index] : characters[index].wc;
177
+ }
178
+
179
+ unsigned Gosu::FormattedString::flags_at(unsigned index) const
180
+ {
181
+ return characters.empty() ? simple_flags : characters[index].flags;
182
+ }
183
+
184
+ Gosu::Color Gosu::FormattedString::color_at(unsigned index) const
185
+ {
186
+ return characters.empty() ? Color::WHITE : characters[index].color;
187
+ }
188
+
189
+ size_t Gosu::FormattedString::length() const
190
+ {
191
+ return characters.empty() ? simple_string.length() : characters.size();
192
+ }
193
+
194
+ Gosu::FormattedString Gosu::FormattedString::range(size_t begin, size_t end) const
195
+ {
196
+ FormattedString result;
197
+ if (characters.empty()) {
198
+ result.simple_string.assign(simple_string.begin() + begin,
199
+ simple_string.begin() + end);
200
+ result.simple_flags = simple_flags;
201
+ }
202
+ else {
203
+ result.characters.assign(characters.begin() + begin,
204
+ characters.begin() + end);
205
+ }
206
+ return result;
207
+ }
208
+
209
+ vector<Gosu::FormattedString> Gosu::FormattedString::split_lines() const
210
+ {
211
+ vector<FormattedString> result;
212
+ unsigned begin = 0;
213
+ for (unsigned cur = 0; cur < length(); ++cur) {
214
+ if (char_at(cur) == L'\n') {
215
+ result.push_back(range(begin, cur));
216
+ begin = cur + 1;
217
+ }
218
+ }
219
+ result.push_back(range(begin, length()));
220
+ return result;
221
+ }
222
+
223
+ vector<Gosu::FormattedString> Gosu::FormattedString::split_parts() const
224
+ {
225
+ if (characters.empty()) return vector<FormattedString>(1, *this);
226
+
227
+ vector<FormattedString> result;
228
+ unsigned begin = 0;
229
+ for (unsigned cur = 1; cur < length(); ++cur) {
230
+ if (!characters[begin].same_style_as(characters[cur])) {
231
+ result.push_back(range(begin, cur));
232
+ begin = cur;
233
+ }
234
+ }
235
+ result.push_back(range(begin, length()));
236
+ return result;
237
+ }
@@ -3,13 +3,6 @@
3
3
  #include "GraphicsImpl.hpp"
4
4
  #include <Gosu/Color.hpp>
5
5
  #include <Gosu/GraphicsBase.hpp>
6
- #include <Gosu/Utility.hpp>
7
- #include <cassert>
8
- #include <cstdint>
9
- #include <cwchar>
10
- #include <cwctype>
11
- #include <stdexcept>
12
- #include <utility>
13
6
  #include <vector>
14
7
 
15
8
  namespace Gosu
@@ -19,14 +12,11 @@ namespace Gosu
19
12
  struct FormattedChar
20
13
  {
21
14
  wchar_t wc;
22
- Gosu::Color color;
15
+ Color color;
23
16
  unsigned flags;
24
17
  std::string entity;
25
18
 
26
- bool same_style_as(const FormattedChar& other) const
27
- {
28
- return wc && other.wc && color == other.color && flags == other.flags;
29
- }
19
+ bool same_style_as(const FormattedChar& other) const;
30
20
  };
31
21
 
32
22
  // If characters.empty(), use these for the whole string.
@@ -35,264 +25,23 @@ namespace Gosu
35
25
  // If not characters.empty(), ignore above fields and use this.
36
26
  std::vector<FormattedChar> characters;
37
27
 
38
- static unsigned flags(int b, int u, int i)
39
- {
40
- unsigned flags = 0;
41
- if (b > 0) flags |= FF_BOLD;
42
- if (u > 0) flags |= FF_UNDERLINE;
43
- if (i > 0) flags |= FF_ITALIC;
44
- return flags;
45
- }
46
-
47
28
  public:
48
- FormattedString()
49
- {
50
- }
29
+ FormattedString();
30
+ FormattedString(const wchar_t* html, unsigned base_flags);
51
31
 
52
- explicit FormattedString(const wchar_t* html, unsigned base_flags)
53
- {
54
- // Remove \r characters if existent. Avoid a copy if we don't need one.
55
- std::wstring unixified;
56
- if (std::wcschr(html, L'\r')) {
57
- unixified.resize(std::wcslen(html));
58
- unsigned pos = 0;
59
- while (*html) {
60
- if (*html != '\r') {
61
- unixified[pos++] = *html;
62
- }
63
- ++html;
64
- }
65
- unixified.resize(pos);
66
- html = unixified.c_str();
67
- }
68
-
69
- std::size_t len = std::wcslen(html);
70
-
71
- // Just skip all this if there are entities or formatting tags in the string.
72
- if (std::wcscspn(html, L"<&") == len) {
73
- simple_string = html;
74
- simple_flags = base_flags;
75
- return;
76
- }
77
-
78
- unsigned pos = 0;
79
- int b = (base_flags & FF_BOLD) ? 1 : 0,
80
- u = (base_flags & FF_UNDERLINE) ? 1 : 0,
81
- i = (base_flags & FF_ITALIC) ? 1 : 0;
82
- std::vector<Gosu::Color> c;
83
- c.push_back(0xffffffff);
84
- while (pos < len) {
85
- if (!std::wcsncmp(html + pos, L"<b>", 3)) {
86
- b += 1;
87
- pos += 3;
88
- continue;
89
- }
90
- if (!std::wcsncmp(html + pos, L"</b>", 4)) {
91
- b -= 1;
92
- pos += 4;
93
- continue;
94
- }
95
- if (!std::wcsncmp(html + pos, L"<u>", 3)) {
96
- u += 1;
97
- pos += 3;
98
- continue;
99
- }
100
- if (!std::wcsncmp(html + pos, L"</u>", 4)) {
101
- u -= 1;
102
- pos += 4;
103
- continue;
104
- }
105
- if (!std::wcsncmp(html + pos, L"<i>", 3)) {
106
- i += 1;
107
- pos += 3;
108
- continue;
109
- }
110
- if (!std::wcsncmp(html + pos, L"</i>", 4)) {
111
- i -= 1;
112
- pos += 4;
113
- continue;
114
- }
115
- if (!std::wcsncmp(html + pos, L"<c=", 3) && len >= pos + 10
116
- && html[pos + 9] == L'>') {
117
- using namespace std;
118
- unsigned rgb = static_cast<std::uint32_t>(wcstoul(html + pos + 3, 0, 16));
119
- c.push_back(0xff000000 | rgb);
120
- pos += 10;
121
- continue;
122
- }
123
- if (!std::wcsncmp(html + pos, L"<c=", 3) && len >= pos + 12
124
- && html[pos + 11] == L'>') {
125
- using namespace std;
126
- unsigned argb = static_cast<std::uint32_t>(wcstoul(html + pos + 3, 0, 16));
127
- c.push_back(argb);
128
- pos += 12;
129
- continue;
130
- }
131
- if (!std::wcsncmp(html + pos, L"</c>", 4)) {
132
- if (c.size() > 1) {
133
- c.pop_back();
134
- }
135
- pos += 4;
136
- continue;
137
- }
138
- if (!std::wcsncmp(html + pos, L"&lt;", 4)) {
139
- FormattedChar fc = { L'<', c.back(), flags(b, u, i) };
140
- characters.push_back(fc);
141
- pos += 4;
142
- continue;
143
- }
144
- if (!std::wcsncmp(html + pos, L"&gt;", 4)) {
145
- FormattedChar fc = { L'>', c.back(), flags(b, u, i) };
146
- characters.push_back(fc);
147
- pos += 4;
148
- continue;
149
- }
150
- if (!std::wcsncmp(html + pos, L"&amp;", 5)) {
151
- FormattedChar fc = { L'&', c.back(), flags(b, u, i) };
152
- characters.push_back(fc);
153
- pos += 5;
154
- continue;
155
- }
156
- if (html[pos] == L'&' && html[pos + 1]) {
157
- int end_of_entity = pos + 1;
158
- while (html[end_of_entity] != L';') {
159
- using namespace std;
160
- if (!iswalnum(static_cast<wint_t>(html[end_of_entity]))) {
161
- goto normal_character;
162
- }
163
- end_of_entity += 1;
164
- if (end_of_entity >= len) {
165
- goto normal_character;
166
- }
167
- }
168
- std::wstring entity(html + pos + 1, html + end_of_entity);
169
- FormattedChar fc = { 0, c.back(), 0, wstring_to_utf8(entity) };
170
- if (!is_entity(fc.entity)) {
171
- goto normal_character;
172
- }
173
- characters.push_back(fc);
174
- pos = end_of_entity + 1;
175
- continue;
176
- }
177
-
178
- normal_character:
179
- FormattedChar fc = { html[pos], c.back(), flags(b, u, i) };
180
- characters.push_back(fc);
181
- pos += 1;
182
- }
183
- }
32
+ std::wstring unformat() const;
184
33
 
185
- std::wstring unformat() const
186
- {
187
- if (characters.empty()) {
188
- return simple_string;
189
- }
190
-
191
- std::wstring result(characters.size(), 0);
192
- for (int i = 0; i < characters.size(); ++i) {
193
- result[i] = characters[i].wc;
194
- }
195
- return result;
196
- }
34
+ const char* entity_at(unsigned index) const;
35
+ wchar_t char_at(unsigned index) const;
36
+ unsigned flags_at(unsigned index) const;
37
+ Color color_at(unsigned index) const;
197
38
 
198
- const char* entity_at(unsigned index) const
199
- {
200
- if (characters.empty()) {
201
- return nullptr;
202
- }
203
-
204
- if (characters[index].wc != 0 || characters[index].entity.empty()) {
205
- return nullptr;
206
- }
207
-
208
- return characters[index].entity.c_str();
209
- }
39
+ std::size_t length() const;
210
40
 
211
- wchar_t char_at(unsigned index) const
212
- {
213
- if (characters.empty()) {
214
- return simple_string[index];
215
- }
216
- else {
217
- return characters[index].wc;
218
- }
219
- }
41
+ FormattedString range(std::size_t begin, std::size_t end) const;
220
42
 
221
- unsigned flags_at(unsigned index) const
222
- {
223
- if (characters.empty()) {
224
- return simple_flags;
225
- }
226
- else {
227
- return characters[index].flags;
228
- }
229
- }
230
-
231
- Gosu::Color color_at(unsigned index) const
232
- {
233
- if (characters.empty()) {
234
- return Color::WHITE;
235
- }
236
- else {
237
- return characters[index].color;
238
- }
239
- }
240
-
241
- std::size_t length() const
242
- {
243
- if (std::size_t len = characters.size()) {
244
- return len;
245
- }
246
- else {
247
- return simple_string.length();
248
- }
249
- }
250
-
251
- FormattedString range(std::size_t begin, std::size_t end) const
252
- {
253
- FormattedString result;
254
- if (characters.empty()) {
255
- result.simple_string.assign(simple_string.begin() + begin,
256
- simple_string.begin() + end);
257
- result.simple_flags = simple_flags;
258
- }
259
- else {
260
- result.characters.assign(characters.begin() + begin,
261
- characters.begin() + end);
262
- }
263
- return result;
264
- }
265
-
266
- std::vector<FormattedString> split_lines() const
267
- {
268
- std::vector<FormattedString> result;
269
- unsigned begin = 0;
270
- for (unsigned cur = 0; cur < length(); ++cur) {
271
- if (char_at(cur) == L'\n') {
272
- result.push_back(range(begin, cur));
273
- begin = cur + 1;
274
- }
275
- }
276
- result.push_back(range(begin, length()));
277
- return result;
278
- }
279
-
280
- std::vector<FormattedString> split_parts() const
281
- {
282
- if (characters.empty()) {
283
- return std::vector<FormattedString>(1, *this);
284
- }
285
-
286
- std::vector<FormattedString> result;
287
- unsigned begin = 0;
288
- for (unsigned cur = 1; cur < length(); ++cur) {
289
- if (!characters[begin].same_style_as(characters[cur])) {
290
- result.push_back(range(begin, cur));
291
- begin = cur;
292
- }
293
- }
294
- result.push_back(range(begin, length()));
295
- return result;
296
- }
43
+ std::vector<FormattedString> split_lines() const;
44
+ std::vector<FormattedString> split_parts() const;
297
45
  };
298
46
  }
47
+