gosu 1.4.6 → 2.0.0.pre6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (170) hide show
  1. checksums.yaml +4 -4
  2. data/COPYING +2 -1
  3. data/dependencies/SDL/include/SDL_atomic.h +2 -3
  4. data/dependencies/SDL/include/SDL_audio.h +7 -7
  5. data/dependencies/SDL/include/SDL_blendmode.h +1 -1
  6. data/dependencies/SDL/include/SDL_endian.h +3 -3
  7. data/dependencies/SDL/include/SDL_gamecontroller.h +4 -4
  8. data/dependencies/SDL/include/SDL_hints.h +72 -28
  9. data/dependencies/SDL/include/SDL_joystick.h +8 -5
  10. data/dependencies/SDL/include/SDL_keycode.h +1 -1
  11. data/dependencies/SDL/include/SDL_main.h +7 -0
  12. data/dependencies/SDL/include/SDL_mouse.h +6 -7
  13. data/dependencies/SDL/include/SDL_mutex.h +79 -5
  14. data/dependencies/SDL/include/SDL_opengl_glext.h +5 -1
  15. data/dependencies/SDL/include/SDL_power.h +7 -8
  16. data/dependencies/SDL/include/SDL_render.h +5 -0
  17. data/dependencies/SDL/include/SDL_revision.h +2 -2
  18. data/dependencies/SDL/include/SDL_sensor.h +1 -1
  19. data/dependencies/SDL/include/SDL_stdinc.h +19 -11
  20. data/dependencies/SDL/include/SDL_thread.h +2 -2
  21. data/dependencies/SDL/include/SDL_version.h +2 -2
  22. data/dependencies/SDL/include/SDL_video.h +30 -2
  23. data/dependencies/SDL/include/begin_code.h +7 -7
  24. data/dependencies/SDL/include/close_code.h +2 -2
  25. data/dependencies/SDL/lib/x64/libSDL2.dll.a +0 -0
  26. data/dependencies/SDL/lib/x86/libSDL2.dll.a +0 -0
  27. data/dependencies/SDL_sound/SDL_sound.h +1 -1
  28. data/dependencies/SDL_sound/dr_flac.h +48 -23
  29. data/dependencies/SDL_sound/dr_mp3.h +34 -14
  30. data/dependencies/SDL_sound/stb_vorbis.h +3 -2
  31. data/dependencies/mojoAL/mojoal.c +1 -1
  32. data/ext/{gosu → gosu-ffi}/extconf.rb +34 -33
  33. data/ext/gosu-ffi/gosu-ffi.def +464 -0
  34. data/ffi/Gosu.cpp +307 -0
  35. data/ffi/Gosu.h +84 -0
  36. data/ffi/Gosu_Channel.cpp +62 -0
  37. data/ffi/Gosu_Channel.h +17 -0
  38. data/ffi/Gosu_Color.cpp +132 -0
  39. data/ffi/Gosu_Color.h +31 -0
  40. data/ffi/Gosu_Constants.cpp +334 -0
  41. data/ffi/Gosu_FFI.h +34 -0
  42. data/ffi/Gosu_FFI_internal.h +161 -0
  43. data/ffi/Gosu_Font.cpp +92 -0
  44. data/ffi/Gosu_Font.h +32 -0
  45. data/ffi/Gosu_Image.cpp +206 -0
  46. data/ffi/Gosu_Image.h +60 -0
  47. data/ffi/Gosu_Sample.cpp +29 -0
  48. data/ffi/Gosu_Sample.h +14 -0
  49. data/ffi/Gosu_Song.cpp +69 -0
  50. data/ffi/Gosu_Song.h +18 -0
  51. data/ffi/Gosu_TextInput.cpp +94 -0
  52. data/ffi/Gosu_TextInput.h +25 -0
  53. data/ffi/Gosu_Window.cpp +314 -0
  54. data/ffi/Gosu_Window.h +78 -0
  55. data/include/Gosu/Audio.hpp +6 -11
  56. data/include/Gosu/Bitmap.hpp +38 -53
  57. data/include/Gosu/Buffer.hpp +54 -0
  58. data/include/Gosu/Color.hpp +27 -35
  59. data/include/Gosu/Directories.hpp +25 -28
  60. data/include/Gosu/Drawable.hpp +58 -0
  61. data/include/Gosu/Font.hpp +6 -5
  62. data/include/Gosu/Fwd.hpp +4 -6
  63. data/include/Gosu/Gosu.hpp +5 -5
  64. data/include/Gosu/Graphics.hpp +51 -61
  65. data/include/Gosu/GraphicsBase.hpp +1 -11
  66. data/include/Gosu/Image.hpp +11 -14
  67. data/include/Gosu/Math.hpp +50 -72
  68. data/include/Gosu/Transform.hpp +32 -0
  69. data/include/Gosu/Utility.hpp +51 -1
  70. data/include/Gosu/Version.hpp +3 -3
  71. data/include/Gosu/Window.hpp +15 -9
  72. data/lib/SDL2.dll +0 -0
  73. data/lib/gosu/channel.rb +49 -0
  74. data/lib/gosu/color.rb +150 -0
  75. data/lib/gosu/compat.rb +29 -8
  76. data/lib/gosu/constants.rb +386 -0
  77. data/lib/gosu/ffi.rb +258 -0
  78. data/lib/gosu/font.rb +56 -0
  79. data/lib/gosu/gl_tex_info.rb +33 -0
  80. data/lib/gosu/gosu.rb +210 -0
  81. data/lib/gosu/image.rb +141 -0
  82. data/lib/gosu/numeric.rb +17 -0
  83. data/lib/gosu/preview.rb +6 -6
  84. data/lib/gosu/sample.rb +24 -0
  85. data/lib/gosu/song.rb +56 -0
  86. data/lib/gosu/text_input.rb +69 -0
  87. data/lib/gosu/window.rb +228 -0
  88. data/lib/gosu.rb +29 -8
  89. data/lib64/SDL2.dll +0 -0
  90. data/rdoc/gosu.rb +0 -2
  91. data/src/Audio.cpp +12 -12
  92. data/src/AudioFile.hpp +5 -4
  93. data/src/AudioFileAudioToolbox.cpp +8 -8
  94. data/src/AudioFileSDLSound.cpp +7 -10
  95. data/src/BinPacker.cpp +187 -0
  96. data/src/BinPacker.hpp +55 -0
  97. data/src/Bitmap.cpp +166 -144
  98. data/src/BitmapIO.cpp +60 -86
  99. data/src/Buffer.cpp +159 -0
  100. data/src/Color.cpp +75 -80
  101. data/src/Directories.cpp +47 -0
  102. data/src/DirectoriesUIKit.cpp +50 -0
  103. data/src/DrawOp.hpp +9 -4
  104. data/src/DrawOpQueue.hpp +2 -2
  105. data/src/Drawable.cpp +95 -0
  106. data/src/EmptyDrawable.hpp +38 -0
  107. data/src/FPS.cpp +31 -0
  108. data/src/Font.cpp +104 -74
  109. data/src/GosuGLView.cpp +14 -6
  110. data/src/GosuViewController.cpp +2 -10
  111. data/src/Graphics.cpp +60 -126
  112. data/src/GraphicsImpl.hpp +17 -47
  113. data/src/Image.cpp +41 -35
  114. data/src/Input.cpp +7 -8
  115. data/src/Macro.cpp +6 -6
  116. data/src/Macro.hpp +4 -4
  117. data/src/MarkupParser.cpp +5 -5
  118. data/src/Math.cpp +35 -22
  119. data/src/OffScreenTarget.cpp +53 -49
  120. data/src/OffScreenTarget.hpp +13 -11
  121. data/src/OpenGLContext.cpp +117 -0
  122. data/src/OpenGLContext.hpp +41 -0
  123. data/src/RenderState.hpp +21 -19
  124. data/src/Resolution.cpp +23 -21
  125. data/src/TexChunk.cpp +35 -80
  126. data/src/TexChunk.hpp +44 -35
  127. data/src/Text.cpp +1 -1
  128. data/src/TextBuilder.cpp +35 -21
  129. data/src/TextBuilder.hpp +6 -9
  130. data/src/Texture.cpp +62 -80
  131. data/src/Texture.hpp +25 -23
  132. data/src/TiledDrawable.cpp +150 -0
  133. data/src/TiledDrawable.hpp +47 -0
  134. data/src/TimingApple.cpp +1 -1
  135. data/src/Transform.cpp +45 -50
  136. data/src/TransformStack.hpp +16 -16
  137. data/src/TrueTypeFont.cpp +59 -51
  138. data/src/TrueTypeFont.hpp +6 -7
  139. data/src/TrueTypeFontApple.cpp +28 -19
  140. data/src/TrueTypeFontUnix.cpp +27 -23
  141. data/src/TrueTypeFontWin.cpp +30 -30
  142. data/src/Utility.cpp +84 -21
  143. data/src/UtilityWin.cpp +45 -0
  144. data/src/Window.cpp +92 -142
  145. data/src/WindowUIKit.cpp +14 -14
  146. metadata +72 -31
  147. data/include/Gosu/IO.hpp +0 -254
  148. data/include/Gosu/ImageData.hpp +0 -53
  149. data/include/Gosu/Inspection.hpp +0 -7
  150. data/lib/gosu/patches.rb +0 -66
  151. data/lib/gosu/run.rb +0 -20
  152. data/lib/gosu/swig_patches.rb +0 -110
  153. data/src/BlockAllocator.cpp +0 -131
  154. data/src/BlockAllocator.hpp +0 -32
  155. data/src/DirectoriesApple.cpp +0 -69
  156. data/src/DirectoriesUnix.cpp +0 -46
  157. data/src/DirectoriesWin.cpp +0 -65
  158. data/src/EmptyImageData.hpp +0 -52
  159. data/src/FileUnix.cpp +0 -99
  160. data/src/FileWin.cpp +0 -88
  161. data/src/IO.cpp +0 -60
  162. data/src/Iconv.hpp +0 -51
  163. data/src/Inspection.cpp +0 -27
  164. data/src/LargeImageData.cpp +0 -215
  165. data/src/LargeImageData.hpp +0 -39
  166. data/src/Log.hpp +0 -19
  167. data/src/RubyGosu.cxx +0 -13100
  168. data/src/RubyGosu.h +0 -49
  169. data/src/WinUtility.cpp +0 -61
  170. data/src/WinUtility.hpp +0 -27
@@ -14,7 +14,7 @@ namespace Gosu
14
14
  Transforms absolute;
15
15
  // Points to one absolute transform.
16
16
  Transforms::const_iterator current_iterator;
17
-
17
+
18
18
  void make_current(const Transform& transform)
19
19
  {
20
20
  current_iterator = std::find(absolute.begin(), absolute.end(), transform);
@@ -22,12 +22,12 @@ namespace Gosu
22
22
  current_iterator = absolute.insert(absolute.end(), transform);
23
23
  }
24
24
  }
25
-
25
+
26
26
  public:
27
27
  TransformStack()
28
28
  {
29
29
  reset();
30
- individual.front() = absolute.front() = scale(1);
30
+ individual.front() = absolute.front() = Transform::scale(1);
31
31
  }
32
32
 
33
33
  void reset()
@@ -39,18 +39,18 @@ namespace Gosu
39
39
  absolute.resize(1);
40
40
  current_iterator = absolute.begin();
41
41
  }
42
-
42
+
43
43
  TransformStack(const TransformStack& other)
44
44
  {
45
45
  *this = other;
46
46
  }
47
-
47
+
48
48
  // Custom assignment to ensure valid current_iterator
49
49
  TransformStack& operator=(const TransformStack& other)
50
50
  {
51
51
  individual = other.individual;
52
52
  absolute = other.absolute;
53
-
53
+
54
54
  // Reset our current_iterator to point to the respective element
55
55
  // in our own 'absolute' transforms by iterating both lists up to
56
56
  // the other lists' current iterator
@@ -60,39 +60,39 @@ namespace Gosu
60
60
  ++current_iterator;
61
61
  ++other_iterator;
62
62
  }
63
-
63
+
64
64
  return *this;
65
65
  }
66
-
66
+
67
67
  void set_base_transform(const Transform& base_transform)
68
68
  {
69
69
  assert (individual.size() == 1);
70
70
  assert (absolute.size() == 1);
71
-
71
+
72
72
  individual.front() = absolute.front() = base_transform;
73
73
  }
74
-
74
+
75
75
  const Transform& current()
76
76
  {
77
77
  return *current_iterator;
78
78
  }
79
-
79
+
80
80
  void push(const Transform& transform)
81
81
  {
82
82
  individual.push_back(transform);
83
- Transform result = concat(transform, current());
83
+ Transform result = transform * current();
84
84
  make_current(result);
85
85
  }
86
-
86
+
87
87
  void pop()
88
88
  {
89
89
  assert (individual.size() > 1);
90
-
90
+
91
91
  individual.pop_back();
92
- Transform result = scale(1);
92
+ Transform result = Transform::scale(1);
93
93
  for (Transforms::reverse_iterator it = individual.rbegin(),
94
94
  end = individual.rend(); it != end; ++it)
95
- result = concat(result, *it);
95
+ result = result * *it;
96
96
  make_current(result);
97
97
  }
98
98
  };
data/src/TrueTypeFont.cpp CHANGED
@@ -1,9 +1,10 @@
1
1
  #include "TrueTypeFont.hpp"
2
- #include <Gosu/IO.hpp>
2
+ #include <Gosu/Buffer.hpp>
3
3
  #include <Gosu/Text.hpp>
4
4
  #include <Gosu/Utility.hpp>
5
5
  #include <algorithm>
6
6
  #include <map>
7
+ #include <mutex>
7
8
  #include <stdexcept>
8
9
 
9
10
  #define STB_TRUETYPE_IMPLEMENTATION
@@ -11,23 +12,25 @@
11
12
 
12
13
  struct Gosu::TrueTypeFont::Impl : private Gosu::Noncopyable
13
14
  {
14
- stbtt_fontinfo info{};
15
+ stbtt_fontinfo info {};
15
16
  std::shared_ptr<TrueTypeFont> fallback;
16
17
 
17
18
  // The height of the ascent in internal font metrics (an arbitrary integer scale). The ascent is
18
19
  // the part of the font above the baseline (which TrueType considers to be at y = 0).
19
- int ascent{};
20
+ int ascent = 0;
20
21
 
21
22
  // Scaling factor from internal font metrics (an arbitrary integer scale) to a font with
22
23
  // height = 1px.
23
24
  double base_scale;
24
25
 
25
- Impl(const unsigned char* ttf_data, std::shared_ptr<TrueTypeFont> fallback)
26
- : fallback{move(fallback)}
26
+ Impl(const std::uint8_t* ttf_data, std::shared_ptr<TrueTypeFont> fallback)
27
+ : fallback(std::move(fallback))
27
28
  {
28
29
  auto offset = stbtt_GetFontOffsetForIndex(ttf_data, 0);
29
30
  int success = stbtt_InitFont(&info, ttf_data, offset);
30
- if (!success) throw std::runtime_error{"Invalid TrueType font data"};
31
+ if (!success) {
32
+ throw std::runtime_error("Invalid TrueType font data");
33
+ }
31
34
 
32
35
  // Calculate metrics.
33
36
  int descent, line_gap;
@@ -40,7 +43,9 @@ struct Gosu::TrueTypeFont::Impl : private Gosu::Noncopyable
40
43
  double draw_text(const std::u32string& text, bool is_end, double height, Bitmap* bitmap,
41
44
  double x, double y, Color c)
42
45
  {
43
- if (text.empty()) return 0;
46
+ if (text.empty()) {
47
+ return 0;
48
+ }
44
49
 
45
50
  // The 'x' parameter is used as the running cursor variable in this method.
46
51
 
@@ -51,7 +56,9 @@ struct Gosu::TrueTypeFont::Impl : private Gosu::Noncopyable
51
56
  for (std::size_t index = 0; index < text.size(); ++index) {
52
57
  auto codepoint = text[index];
53
58
  // Silently skip control characters, including the \r in Windows-style line breaks.
54
- if (codepoint < ' ') continue;
59
+ if (codepoint < ' ') {
60
+ continue;
61
+ }
55
62
 
56
63
  int glyph = stbtt_FindGlyphIndex(&info, static_cast<int>(codepoint));
57
64
  // Handle missing characters in this font...
@@ -98,10 +105,11 @@ struct Gosu::TrueTypeFont::Impl : private Gosu::Noncopyable
98
105
  float fscale = static_cast<float>(scale);
99
106
  int last_xoff, last_width;
100
107
  // TODO: Don't allocate a buffer just to get metrics!
101
- std::shared_ptr<unsigned char> unused_data{
102
- stbtt_GetGlyphBitmapSubpixel(&info, fscale, fscale, shift_x, 0, last_glyph,
103
- &last_width, nullptr, &last_xoff, nullptr),
104
- std::free};
108
+ std::shared_ptr<std::uint8_t> unused_data {
109
+ stbtt_GetGlyphBitmapSubpixel(&info, fscale, fscale, shift_x, 0, last_glyph,
110
+ &last_width, nullptr, &last_xoff, nullptr),
111
+ std::free
112
+ };
105
113
  // Move the cursor to the right if pixels have been touched by draw_glyph that are
106
114
  // to the right of the current cursor.
107
115
  // If the last character extends to the right of the cursor, then this prevents the
@@ -144,16 +152,16 @@ struct Gosu::TrueTypeFont::Impl : private Gosu::Noncopyable
144
152
  int w, h, xoff, yoff;
145
153
  // As an optimization, this method/class could try to re-use a buffer for rasterization
146
154
  // instead of having stb_truetype allocate a fresh one for each draw_glyph call.
147
- std::shared_ptr<unsigned char> pixels{stbtt_GetGlyphBitmapSubpixel(&info, fscale, fscale,
148
- shift_x, shift_y, glyph,
149
- &w, &h, &xoff, &yoff),
150
- std::free};
155
+ std::shared_ptr<std::uint8_t> pixels(stbtt_GetGlyphBitmapSubpixel(&info, fscale, fscale, //
156
+ shift_x, shift_y, glyph,
157
+ &w, &h, &xoff, &yoff),
158
+ std::free);
151
159
 
152
160
  int target_y = static_cast<int>(y + ascent * scale + yoff);
153
161
  blend_into_bitmap(bitmap, pixels.get(), x + xoff, target_y, w, h, c);
154
162
  }
155
163
 
156
- static void blend_into_bitmap(Bitmap& bitmap, const unsigned char* pixels, //
164
+ static void blend_into_bitmap(Bitmap& bitmap, const std::uint8_t* pixels, //
157
165
  int x, int y, int w, int h, Color c)
158
166
  {
159
167
  int stride = w;
@@ -188,9 +196,9 @@ struct Gosu::TrueTypeFont::Impl : private Gosu::Noncopyable
188
196
  }
189
197
  };
190
198
 
191
- Gosu::TrueTypeFont::TrueTypeFont(const unsigned char* ttf_data,
199
+ Gosu::TrueTypeFont::TrueTypeFont(const std::uint8_t* ttf_data,
192
200
  std::shared_ptr<TrueTypeFont> fallback)
193
- : m_impl{new Impl(ttf_data, std::move(fallback))}
201
+ : m_impl(new Impl(ttf_data, std::move(fallback)))
194
202
  {
195
203
  }
196
204
 
@@ -200,31 +208,33 @@ double Gosu::TrueTypeFont::draw_text(const std::u32string& text, double height,
200
208
  return m_impl->draw_text(text, true, height, bitmap, x, y, c);
201
209
  }
202
210
 
203
- bool Gosu::TrueTypeFont::matches(const unsigned char* ttf_data, const std::string& font_name,
211
+ bool Gosu::TrueTypeFont::matches(const std::uint8_t* ttf_data, const std::string& font_name,
204
212
  unsigned font_flags)
205
213
  {
206
214
  // Gosu::FontFlags uses the same values as the STBTT_ macros, except for this one.
207
215
  int flags = (font_flags == 0 ? STBTT_MACSTYLE_NONE : static_cast<int>(font_flags));
208
216
 
209
- return stbtt_FindMatchingFont(ttf_data, font_name.c_str(), flags) >= 0 ||
210
- stbtt_FindMatchingFont(ttf_data, font_name.c_str(), STBTT_MACSTYLE_DONTCARE) >= 0;
217
+ return stbtt_FindMatchingFont(ttf_data, font_name.c_str(), flags) >= 0
218
+ || stbtt_FindMatchingFont(ttf_data, font_name.c_str(), STBTT_MACSTYLE_DONTCARE) >= 0;
211
219
  }
212
220
 
213
- static Gosu::TrueTypeFont& font_with_stack(std::vector<const unsigned char*> ttf_stack)
221
+ static Gosu::TrueTypeFont& font_with_stack(std::vector<const std::uint8_t*> ttf_stack)
214
222
  {
215
- // TODO: Make this cache thread-safe.
216
- static std::map<const unsigned char*, std::shared_ptr<Gosu::TrueTypeFont>> cache_by_data;
223
+ static std::map<const std::uint8_t*, std::shared_ptr<Gosu::TrueTypeFont>> cache_by_data;
224
+ static std::recursive_mutex mutex;
225
+ std::scoped_lock lock(mutex);
217
226
 
218
- // Filter out any fonts that could not be found, as well as duplicates.
219
- auto end = unique(ttf_stack.begin(), ttf_stack.end());
220
- end = remove(ttf_stack.begin(), end, nullptr);
221
- ttf_stack.erase(end, ttf_stack.end());
227
+ // Filter out any fonts that could not be found, as well as (adjacent) duplicates.
228
+ ttf_stack.erase(std::remove(ttf_stack.begin(), ttf_stack.end(), nullptr), ttf_stack.end());
229
+ ttf_stack.erase(std::unique(ttf_stack.begin(), ttf_stack.end()), ttf_stack.end());
222
230
 
223
231
  // This cannot happen because ttf_stack contains ttf_fallback_data(), which never returns null.
224
- if (ttf_stack.empty()) throw std::logic_error{"Empty font stack"};
232
+ if (ttf_stack.empty()) {
233
+ throw std::logic_error("Empty font stack");
234
+ }
225
235
 
226
236
  std::shared_ptr<Gosu::TrueTypeFont> head_of_stack = nullptr;
227
- for (const unsigned char* ttf_data : ttf_stack) {
237
+ for (const std::uint8_t* ttf_data : ttf_stack) {
228
238
  auto& font_ptr = cache_by_data[ttf_data];
229
239
  if (!font_ptr) {
230
240
  font_ptr = std::make_shared<Gosu::TrueTypeFont>(ttf_data, head_of_stack);
@@ -236,17 +246,20 @@ static Gosu::TrueTypeFont& font_with_stack(std::vector<const unsigned char*> ttf
236
246
 
237
247
  Gosu::TrueTypeFont& Gosu::font_by_name(const std::string& font_name, unsigned font_flags)
238
248
  {
239
- // TODO: Make this cache thread-safe.
240
249
  static std::map<std::pair<std::string, unsigned>, TrueTypeFont*> cache_by_name_and_flags;
250
+ static std::recursive_mutex mutex;
251
+ std::scoped_lock lock(mutex);
241
252
 
242
253
  auto& font_ptr = cache_by_name_and_flags[make_pair(font_name, font_flags)];
243
254
  if (!font_ptr) {
244
255
  // Build a stack of TTF data in order of preference, where the fallback font is at the
245
256
  // front, and the desired font with all the right font flags (most preferable) at the back.
246
- std::vector<const unsigned char*> ttf_stack;
257
+ std::vector<const std::uint8_t*> ttf_stack;
247
258
  ttf_stack.push_back(ttf_fallback_data());
248
259
  ttf_stack.push_back(ttf_data_by_name(default_font_name(), 0));
249
- if (font_flags != 0) ttf_stack.push_back(ttf_data_by_name(default_font_name(), font_flags));
260
+ if (font_flags != 0) {
261
+ ttf_stack.push_back(ttf_data_by_name(default_font_name(), font_flags));
262
+ }
250
263
 
251
264
  if (font_name.find_first_of("./\\") != std::string::npos) {
252
265
  // A filename? Load it and add it to the stack.
@@ -255,30 +268,25 @@ Gosu::TrueTypeFont& Gosu::font_by_name(const std::string& font_name, unsigned fo
255
268
  else if (font_name != default_font_name()) {
256
269
  // A font name? Add it to the stack, both with font_flags and without.
257
270
  ttf_stack.push_back(ttf_data_by_name(font_name, 0));
258
- if (font_flags != 0) ttf_stack.push_back(ttf_data_by_name(font_name, font_flags));
271
+ if (font_flags != 0) {
272
+ ttf_stack.push_back(ttf_data_by_name(font_name, font_flags));
273
+ }
259
274
  }
260
275
 
261
- font_ptr = &font_with_stack(move(ttf_stack));
276
+ font_ptr = &font_with_stack(std::move(ttf_stack));
262
277
  }
263
278
 
264
279
  return *font_ptr;
265
280
  }
266
281
 
267
- const unsigned char* Gosu::ttf_data_from_file(const std::string& filename)
282
+ const std::uint8_t* Gosu::ttf_data_from_file(const std::string& filename)
268
283
  {
269
- // TODO: Make this cache thread-safe.
270
- static std::map<std::string, std::shared_ptr<Buffer>> ttf_file_cache;
271
-
272
- auto& buffer_ptr = ttf_file_cache[filename];
273
- if (!buffer_ptr) {
274
- buffer_ptr = std::make_shared<Buffer>();
275
- try {
276
- load_file(*buffer_ptr, filename);
277
- } catch (...) {
278
- // Prevent partially loaded files from getting stuck in the cache.
279
- buffer_ptr = nullptr;
280
- throw;
281
- }
284
+ static std::map<std::string, Buffer> ttf_file_cache;
285
+ static std::recursive_mutex mutex;
286
+ std::scoped_lock lock(mutex);
287
+
288
+ if (!ttf_file_cache.contains(filename)) {
289
+ ttf_file_cache.emplace(filename, load_file(filename));
282
290
  }
283
- return static_cast<const unsigned char*>(buffer_ptr->data());
291
+ return ttf_file_cache.at(filename).data();
284
292
  }
data/src/TrueTypeFont.hpp CHANGED
@@ -1,11 +1,10 @@
1
1
  #pragma once
2
2
 
3
3
  #include <Gosu/Bitmap.hpp>
4
- #include <Gosu/IO.hpp>
4
+ #include <cstdint>
5
5
  #include <functional>
6
6
  #include <memory>
7
7
  #include <string>
8
- #include <vector>
9
8
 
10
9
  namespace Gosu
11
10
  {
@@ -16,7 +15,7 @@ namespace Gosu
16
15
 
17
16
  public:
18
17
  /// The caller must ensure that the ttf_data pointer will outlive this object.
19
- TrueTypeFont(const unsigned char* ttf_data, std::shared_ptr<TrueTypeFont> fallback);
18
+ TrueTypeFont(const std::uint8_t* ttf_data, std::shared_ptr<TrueTypeFont> fallback);
20
19
 
21
20
  /// Returns the right edge of a string when rendered onto a bitmap at the given position,
22
21
  /// and with the given height.
@@ -25,7 +24,7 @@ namespace Gosu
25
24
  Bitmap* bitmap, double x, double y, Color c);
26
25
 
27
26
  /// Returns true if the supplied buffer seems to be a font of the given name.
28
- static bool matches(const unsigned char* ttf_data, //
27
+ static bool matches(const std::uint8_t* ttf_data, //
29
28
  const std::string& font_name, unsigned font_flags);
30
29
  };
31
30
 
@@ -49,15 +48,15 @@ namespace Gosu
49
48
  /// 3. As a last resort, Gosu could implement faux bold and faux italics. I think faux
50
49
  /// underlines are a must anyway, since no font provides a dedicated TTF file for that.
51
50
  /// These options are not mutually exclusive.
52
- const unsigned char* ttf_data_from_file(const std::string& filename);
51
+ const std::uint8_t* ttf_data_from_file(const std::string& filename);
53
52
 
54
53
  /// This method loads a system font with the given flags.
55
54
  /// This method has a different implementation on each platform.
56
55
  /// In case of failure, this method returns nullptr.
57
- const unsigned char* ttf_data_by_name(const std::string& font_name, unsigned font_flags);
56
+ const std::uint8_t* ttf_data_by_name(const std::string& font_name, unsigned font_flags);
58
57
 
59
58
  /// Returns the TTF data of a font that supports as many glyphs as possible.
60
59
  /// This method has a different implementation on each platform.
61
60
  /// In case of failure, this method must not return nullptr, but raise an exception.
62
- const unsigned char* ttf_fallback_data();
61
+ const std::uint8_t* ttf_fallback_data();
63
62
  }
@@ -2,50 +2,55 @@
2
2
  #if defined(GOSU_IS_MAC)
3
3
 
4
4
  #include <Gosu/Text.hpp>
5
- #include "Log.hpp"
6
5
  #include "TrueTypeFont.hpp"
7
6
  #include <CoreText/CoreText.h>
8
7
  #include <Foundation/Foundation.h>
9
8
  #include <map>
10
9
 
11
- const unsigned char* Gosu::ttf_data_by_name(const std::string& font_name, unsigned font_flags)
10
+ const std::uint8_t* Gosu::ttf_data_by_name(const std::string& font_name, unsigned font_flags)
12
11
  {
13
- // TODO: Make this cache thread-safe.
14
- static std::map<std::pair<std::string, unsigned>, const unsigned char*> ttf_file_cache;
12
+ static std::map<std::pair<std::string, unsigned>, const std::uint8_t*> ttf_file_cache;
13
+ static std::recursive_mutex mutex;
14
+ std::scoped_lock lock(mutex);
15
15
 
16
16
  auto& ttf_ptr = ttf_file_cache[make_pair(font_name, font_flags)];
17
- if (ttf_ptr) return ttf_ptr;
18
-
19
- log("Trying to find a font named '%s', flags=%x", font_name.c_str(), font_flags);
17
+ if (ttf_ptr) {
18
+ return ttf_ptr;
19
+ }
20
20
 
21
21
  unsigned symbolic_traits = 0;
22
- if (font_flags & Gosu::FF_BOLD) symbolic_traits |= kCTFontTraitBold;
23
- if (font_flags & Gosu::FF_ITALIC) symbolic_traits |= kCTFontTraitItalic;
22
+ if (font_flags & Gosu::FF_BOLD) {
23
+ symbolic_traits |= kCTFontTraitBold;
24
+ }
25
+ if (font_flags & Gosu::FF_ITALIC) {
26
+ symbolic_traits |= kCTFontTraitItalic;
27
+ }
24
28
 
25
29
  NSDictionary* attributes = @{
26
- ((__bridge id) kCTFontNameAttribute): [NSString stringWithUTF8String:font_name.c_str()],
27
- ((__bridge id) kCTFontTraitsAttribute):
28
- @{((__bridge id) kCTFontSymbolicTrait): @(symbolic_traits)}
30
+ ((__bridge id)kCTFontNameAttribute) : [NSString stringWithUTF8String:font_name.c_str()],
31
+ ((__bridge id)kCTFontTraitsAttribute) :
32
+ @ { ((__bridge id)kCTFontSymbolicTrait) : @(symbolic_traits) }
29
33
  };
30
34
  CTFontDescriptorRef descriptor =
31
- // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
32
- CTFontDescriptorCreateWithAttributes((__bridge CFDictionaryRef) attributes);
35
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
36
+ CTFontDescriptorCreateWithAttributes((__bridge CFDictionaryRef)attributes);
33
37
 
34
38
  if (descriptor) {
35
39
  CTFontRef font = CTFontCreateWithFontDescriptorAndOptions(descriptor, 20, nullptr, 0);
36
40
  if (font) {
41
+ // GCOV_EXCL_START: This does not seem to happen anymore on recent macOS versions.
37
42
  if ((CTFontGetSymbolicTraits(font) & symbolic_traits) != symbolic_traits) {
38
43
  // For some reason the initial call to CTFontCreateWithFontDescriptorAndOptions does
39
44
  // not respect the requested font traits. Explicitly requesting the traits again
40
45
  // seems to help. Tested on macOS 11.2.2.
41
46
  CTFontRef correct_font = CTFontCreateCopyWithSymbolicTraits(
42
- font, 0.0, nullptr, symbolic_traits, symbolic_traits);
47
+ font, 0.0, nullptr, symbolic_traits, symbolic_traits);
43
48
  CFRelease(font);
44
49
  font = correct_font;
45
50
  }
51
+ // GCOV_EXCL_END
46
52
  NSURL* url = CFBridgingRelease(CTFontCopyAttribute(font, kCTFontURLAttribute));
47
53
  if (url && url.fileSystemRepresentation) {
48
- log("Loading file '%s'", url.fileSystemRepresentation);
49
54
  ttf_ptr = ttf_data_from_file(url.fileSystemRepresentation);
50
55
  }
51
56
  CFRelease(font);
@@ -56,13 +61,17 @@ const unsigned char* Gosu::ttf_data_by_name(const std::string& font_name, unsign
56
61
  return ttf_ptr;
57
62
  }
58
63
 
59
- const unsigned char* Gosu::ttf_fallback_data()
64
+ const std::uint8_t* Gosu::ttf_fallback_data()
60
65
  {
61
66
  // Prefer Arial Unicode MS as a fallback because it covers a lot of Unicode.
62
- static const unsigned char* arial_unicode = ttf_data_by_name("Arial Unicode MS", 0);
63
- if (arial_unicode) return arial_unicode;
67
+ static const std::uint8_t* arial_unicode = ttf_data_by_name("Arial Unicode MS", 0);
68
+ if (arial_unicode) {
69
+ return arial_unicode;
70
+ }
64
71
 
72
+ // GCOV_EXCL_START: We do not want to delete system fonts in order to test this line.
65
73
  return ttf_data_from_file("/Library/Fonts/Arial.ttf");
74
+ // GCOV_EXCL_END
66
75
  }
67
76
 
68
77
  std::string Gosu::default_font_name()
@@ -1,23 +1,23 @@
1
1
  #include <Gosu/Platform.hpp>
2
2
  #if defined(GOSU_IS_X)
3
3
 
4
- #include <Gosu/IO.hpp>
5
4
  #include <Gosu/Text.hpp>
6
5
  #include <Gosu/Utility.hpp>
7
- #include "Log.hpp"
8
6
  #include "TrueTypeFont.hpp"
9
7
  #include <fontconfig/fontconfig.h>
10
8
  #include <map>
9
+ #include <mutex>
11
10
 
12
- const unsigned char* Gosu::ttf_data_by_name(const std::string& font_name, unsigned font_flags)
11
+ const std::uint8_t* Gosu::ttf_data_by_name(const std::string& font_name, unsigned font_flags)
13
12
  {
14
- // TODO: Make this cache thread-safe.
15
- static std::map<std::pair<std::string, unsigned>, const unsigned char*> ttf_file_cache;
13
+ static std::map<std::pair<std::string, unsigned>, const std::uint8_t*> ttf_file_cache;
14
+ static std::recursive_mutex mutex;
15
+ std::scoped_lock lock(mutex);
16
16
 
17
17
  auto& ttf_ptr = ttf_file_cache[make_pair(font_name, font_flags)];
18
- if (ttf_ptr) return ttf_ptr;
19
-
20
- log("Trying to find a font named '%s', flags=%x", font_name.c_str(), font_flags);
18
+ if (ttf_ptr) {
19
+ return ttf_ptr;
20
+ }
21
21
 
22
22
  static FcConfig* config = FcInitLoadConfigAndFonts();
23
23
  if (config) {
@@ -31,8 +31,6 @@ const unsigned char* Gosu::ttf_data_by_name(const std::string& font_name, unsign
31
31
  FcObjectSet* props = FcObjectSetBuild(FC_FILE, FC_WEIGHT, FC_SLANT, nullptr);
32
32
 
33
33
  if (FcFontSet* fonts = FcFontList(config, pattern, props)) {
34
- log("Looking for the best candidate among %d matching fonts", (int) fonts->nfont);
35
-
36
34
  // Among all matching fonts, find the variant that is the best fit for our font_flags.
37
35
  std::string best_filename;
38
36
  int best_diff;
@@ -72,7 +70,6 @@ const unsigned char* Gosu::ttf_data_by_name(const std::string& font_name, unsign
72
70
  }
73
71
  }
74
72
  if (!best_filename.empty()) {
75
- log("Loading best candidate '%s'", best_filename.c_str());
76
73
  ttf_ptr = ttf_data_from_file(best_filename.c_str());
77
74
  }
78
75
 
@@ -86,9 +83,9 @@ const unsigned char* Gosu::ttf_data_by_name(const std::string& font_name, unsign
86
83
  return ttf_ptr;
87
84
  }
88
85
 
89
- static const unsigned char* ttf_data_of_default_sans_serif_font()
86
+ static const std::uint8_t* ttf_data_of_default_sans_serif_font()
90
87
  {
91
- const unsigned char* ttf_ptr = nullptr;
88
+ const std::uint8_t* ttf_ptr = nullptr;
92
89
 
93
90
  // At this point, we already have an open FcConfig, and can pass nullptr to these functions.
94
91
  FcPattern* pattern = FcNameParse(reinterpret_cast<const FcChar8*>("sans-serif"));
@@ -99,7 +96,6 @@ static const unsigned char* ttf_data_of_default_sans_serif_font()
99
96
  if (match_result == FcResultMatch) {
100
97
  FcChar8* filename;
101
98
  if (FcPatternGetString(pattern, FC_FILE, 0, &filename) == FcResultMatch) {
102
- Gosu::log("Found the default sans-serif font: '%s'", filename);
103
99
  ttf_ptr = Gosu::ttf_data_from_file(reinterpret_cast<char*>(filename));
104
100
  }
105
101
  }
@@ -108,24 +104,32 @@ static const unsigned char* ttf_data_of_default_sans_serif_font()
108
104
  return ttf_ptr;
109
105
  }
110
106
 
111
- const unsigned char* Gosu::ttf_fallback_data()
107
+ const std::uint8_t* Gosu::ttf_fallback_data()
112
108
  {
113
109
  // Prefer Arial Unicode MS as a fallback because it covers a lot of Unicode in a single file.
114
110
  // This is also the fallback font on Windows and macOS.
115
- static const unsigned char* arial_unicode = ttf_data_by_name("Arial Unicode MS", 0);
116
- if (arial_unicode) return arial_unicode;
111
+ static const std::uint8_t* arial_unicode = ttf_data_by_name("Arial Unicode MS", 0);
112
+ if (arial_unicode) {
113
+ return arial_unicode;
114
+ }
117
115
 
118
116
  // DejaVu has at least some Unicode coverage (though no CJK).
119
- static const unsigned char* deja_vu = ttf_data_by_name("DejaVu", 0);
120
- if (deja_vu) return deja_vu;
117
+ static const std::uint8_t* deja_vu = ttf_data_by_name("DejaVu", 0);
118
+ if (deja_vu) {
119
+ return deja_vu;
120
+ }
121
121
 
122
122
  // Unifont has pretty good Unicode coverage, but looks extremely ugly.
123
- static const unsigned char* unifont = ttf_data_by_name("Unifont", 0);
124
- if (unifont) return unifont;
123
+ static const std::uint8_t* unifont = ttf_data_by_name("Unifont", 0);
124
+ if (unifont) {
125
+ return unifont;
126
+ }
125
127
 
126
128
  // If none of the fonts above work, try to use the default sans-serif font.
127
- static const unsigned char* default_font = ttf_data_of_default_sans_serif_font();
128
- if (default_font) return default_font;
129
+ static const std::uint8_t* default_font = ttf_data_of_default_sans_serif_font();
130
+ if (default_font) {
131
+ return default_font;
132
+ }
129
133
 
130
134
  // If nothing else works, try to load a file from this hardcoded path.
131
135
  return ttf_data_from_file("/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf");