gosu 0.12.1 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
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
+