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.
- checksums.yaml +4 -4
- data/Gosu/Audio.hpp +23 -25
- data/Gosu/Graphics.hpp +16 -12
- data/Gosu/Image.hpp +3 -0
- data/Gosu/Version.hpp +2 -2
- data/lib/gosu.rb +2 -2
- data/lib/gosu/compat.rb +1 -1
- data/lib/gosu/patches.rb +5 -0
- data/lib/gosu/swig_patches.rb +1 -1
- data/rdoc/gosu.rb +10 -10
- data/src/Audio.cpp +93 -228
- data/src/AudioImpl.cpp +94 -0
- data/src/AudioImpl.hpp +33 -0
- data/src/AudioToolboxFile.hpp +14 -18
- data/src/Bitmap.cpp +36 -30
- data/src/BitmapIO.cpp +14 -23
- data/src/BlockAllocator.cpp +7 -10
- data/src/BlockAllocator.hpp +2 -4
- data/src/Channel.cpp +89 -0
- data/src/Color.cpp +4 -9
- data/src/DirectoriesApple.cpp +13 -13
- data/src/DirectoriesUnix.cpp +8 -7
- data/src/DirectoriesWin.cpp +12 -11
- data/src/EmptyImageData.hpp +54 -0
- data/src/FileUnix.cpp +12 -9
- data/src/FileWin.cpp +8 -7
- data/src/Font.cpp +12 -13
- data/src/FormattedString.cpp +237 -0
- data/src/FormattedString.hpp +14 -265
- data/src/GosuViewController.cpp +2 -5
- data/src/Graphics.cpp +38 -39
- data/src/IO.cpp +11 -10
- data/src/Image.cpp +16 -9
- data/src/Input.cpp +16 -15
- data/src/InputUIKit.cpp +8 -7
- data/src/Macro.cpp +11 -11
- data/src/Math.cpp +9 -8
- data/src/RubyGosu.cxx +129 -99
- data/src/TextApple.cpp +19 -13
- data/src/TextInput.cpp +23 -22
- data/src/TextWin.cpp +17 -19
- data/src/Texture.cpp +15 -10
- data/src/Transform.cpp +13 -17
- data/src/Utility.cpp +3 -2
- data/src/UtilityApple.cpp +10 -11
- data/src/UtilityWin.cpp +2 -1
- data/src/Version.cpp +5 -4
- data/src/WinMain.cpp +3 -3
- data/src/WinUtility.cpp +7 -6
- data/src/Window.cpp +11 -10
- data/src/WindowUIKit.cpp +9 -8
- data/src/stb_image.h +782 -480
- data/src/stb_image_write.h +425 -15
- data/src/stb_vorbis.c +82 -32
- metadata +8 -4
- data/src/ALChannelManagement.hpp +0 -119
data/src/FileWin.cpp
CHANGED
@@ -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
|
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
|
-
|
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
|
-
|
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(
|
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(
|
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(
|
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");
|
data/src/Font.cpp
CHANGED
@@ -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
|
-
|
23
|
+
unique_ptr<Image> image;
|
23
24
|
double factor;
|
24
25
|
};
|
25
26
|
typedef array<CharInfo, 65536> Plane;
|
26
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
126
|
-
|
127
|
-
|
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
|
-
|
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
|
-
|
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"<", 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">", 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"&", 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
|
+
}
|
data/src/FormattedString.hpp
CHANGED
@@ -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
|
-
|
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
|
-
|
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"<", 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">", 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"&", 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
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
+
|