rays 0.4.0 → 0.5.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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/.doc/ext/rays/bitmap.cpp +28 -8
  3. data/.doc/ext/rays/bounds.cpp +1 -1
  4. data/.doc/ext/rays/camera.cpp +5 -5
  5. data/.doc/ext/rays/color.cpp +1 -1
  6. data/.doc/ext/rays/color_space.cpp +10 -6
  7. data/.doc/ext/rays/font.cpp +116 -18
  8. data/.doc/ext/rays/image.cpp +27 -4
  9. data/.doc/ext/rays/matrix.cpp +1 -1
  10. data/.doc/ext/rays/painter.cpp +5 -5
  11. data/.doc/ext/rays/point.cpp +1 -1
  12. data/.doc/ext/rays/polygon.cpp +4 -4
  13. data/.doc/ext/rays/polyline.cpp +2 -2
  14. data/.doc/ext/rays/shader.cpp +2 -2
  15. data/.github/workflows/release-gem.yml +2 -49
  16. data/.github/workflows/tag.yml +5 -28
  17. data/.github/workflows/test.yml +1 -37
  18. data/ChangeLog.md +21 -0
  19. data/Gemfile.lock +13 -8
  20. data/Rakefile +2 -2
  21. data/VERSION +1 -1
  22. data/ext/rays/bitmap.cpp +28 -8
  23. data/ext/rays/bounds.cpp +1 -1
  24. data/ext/rays/camera.cpp +5 -5
  25. data/ext/rays/color.cpp +1 -1
  26. data/ext/rays/color_space.cpp +10 -6
  27. data/ext/rays/defs.h +3 -3
  28. data/ext/rays/extconf.rb +6 -5
  29. data/ext/rays/font.cpp +120 -18
  30. data/ext/rays/image.cpp +27 -4
  31. data/ext/rays/matrix.cpp +1 -1
  32. data/ext/rays/painter.cpp +5 -5
  33. data/ext/rays/point.cpp +1 -1
  34. data/ext/rays/polygon.cpp +4 -4
  35. data/ext/rays/polyline.cpp +2 -2
  36. data/ext/rays/shader.cpp +2 -2
  37. data/include/rays/bitmap.h +2 -0
  38. data/include/rays/font.h +46 -4
  39. data/include/rays/image.h +9 -5
  40. data/include/rays/painter.h +3 -1
  41. data/include/rays/ruby/color_space.h +2 -0
  42. data/include/rays/shader.h +3 -0
  43. data/lib/rays/font.rb +4 -1
  44. data/lib/rays/image.rb +2 -0
  45. data/lib/rays/painter.rb +5 -5
  46. data/rays.gemspec +3 -3
  47. data/src/bitmap.cpp +107 -0
  48. data/src/color.cpp +17 -0
  49. data/src/font.cpp +121 -25
  50. data/src/font.h +7 -5
  51. data/src/image.cpp +102 -100
  52. data/src/ios/font.mm +77 -24
  53. data/src/opengl/color_space.cpp +4 -1
  54. data/src/opengl/painter.cpp +86 -18
  55. data/src/opengl/shader.cpp +15 -13
  56. data/src/opengl/texture.cpp +2 -2
  57. data/src/opengl/win32/opengl.cpp +17 -12
  58. data/src/osx/font.mm +77 -24
  59. data/src/painter.cpp +12 -12
  60. data/src/painter.h +5 -1
  61. data/src/polygon.cpp +21 -21
  62. data/src/polyline.cpp +4 -4
  63. data/src/sdl/bitmap.cpp +16 -10
  64. data/src/sdl/font.cpp +56 -50
  65. data/src/win32/bitmap.cpp +22 -13
  66. data/src/win32/font.cpp +43 -44
  67. data/src/win32/gdi.cpp +43 -46
  68. data/src/win32/gdi.h +6 -1
  69. data/src/win32/rays.cpp +18 -1
  70. data/test/test_bitmap.rb +28 -10
  71. data/test/test_font.rb +58 -0
  72. data/test/test_image.rb +29 -6
  73. data/test/test_painter.rb +39 -0
  74. metadata +8 -8
  75. data/.github/workflows/utils.rb +0 -127
data/src/sdl/font.cpp CHANGED
@@ -20,7 +20,11 @@ namespace Rays
20
20
 
21
21
  String name;
22
22
 
23
- coord size = 0;
23
+ coord size = 0;
24
+
25
+ int weight = Font::WEIGHT_NORMAL;
26
+
27
+ bool italic = false;
24
28
 
25
29
  virtual ~Data ()
26
30
  {
@@ -63,7 +67,7 @@ namespace Rays
63
67
 
64
68
  String path;
65
69
 
66
- SDLFontData (const char* path, coord size)
70
+ SDLFontData (const char* path, coord size, int weight, bool italic)
67
71
  {
68
72
  if (!path)
69
73
  argument_error(__FILE__, __LINE__);
@@ -72,8 +76,16 @@ namespace Rays
72
76
  if (!font)
73
77
  rays_error(__FILE__, __LINE__, "failed to open font: %s", TTF_GetError());
74
78
 
75
- this->path = path;
76
- this->size = size;
79
+ this->path = path;
80
+ this->size = size;
81
+ this->weight = weight;
82
+ this->italic = italic;
83
+
84
+ int style = TTF_STYLE_NORMAL;
85
+ if (weight >= Font::WEIGHT_SEMIBOLD) style |= TTF_STYLE_BOLD;
86
+ if (italic) style |= TTF_STYLE_ITALIC;
87
+ if (style != TTF_STYLE_NORMAL)
88
+ TTF_SetFontStyle(font, style);
77
89
 
78
90
  const char* family = TTF_FontFaceFamilyName(font);
79
91
  if (family) this->name = family;
@@ -91,8 +103,9 @@ namespace Rays
91
103
  rays_error(__FILE__, __LINE__, "TTF_RenderUTF8_Blended failed: %s", TTF_GetError());
92
104
 
93
105
  SDL_Rect dst = {(int) x, (int) y, surface->w, surface->h};
106
+ // blending onto zeros premultiplies the straight alpha of SDL_ttf
94
107
  SDL_FillRect(target, &dst, 0);
95
- SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_NONE);
108
+ SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
96
109
  SDL_BlitSurface(surface, NULL, target, &dst);
97
110
  SDL_FreeSurface(surface);
98
111
  }
@@ -126,7 +139,7 @@ namespace Rays
126
139
 
127
140
  Data* dup (coord size) const override
128
141
  {
129
- return new SDLFontData(path.c_str(), size);
142
+ return new SDLFontData(path.c_str(), size, weight, italic);
130
143
  }
131
144
 
132
145
  };// SDLData
@@ -144,22 +157,22 @@ namespace Rays
144
157
  });
145
158
 
146
159
  EM_JS(double, rays_wasm_font_text_width_, (
147
- const char* str, const char* name, double size),
160
+ const char* str, const char* name, double size, int weight, int italic),
148
161
  {
149
162
  const s = UTF8ToString(str);
150
163
  const n = UTF8ToString(name);
151
164
  const c = Module._raysFontContext;
152
- c.font = `${size}px "${n}"`;
165
+ c.font = `${italic ? 'italic' : 'normal'} ${weight} ${size}px "${n}"`;
153
166
  return c.measureText(s).width;
154
167
  });
155
168
 
156
169
  EM_JS(void, rays_wasm_font_get_metrics_, (
157
- const char* name, double size,
170
+ const char* name, double size, int weight, int italic,
158
171
  double* out_ascent, double* out_descent, double* out_leading),
159
172
  {
160
173
  const n = UTF8ToString(name);
161
174
  const c = Module._raysFontContext;
162
- c.font = `${size}px "${n}"`;
175
+ c.font = `${italic ? 'italic' : 'normal'} ${weight} ${size}px "${n}"`;
163
176
  const m = c.measureText('Mgjpqy');
164
177
  const asc = Math.max(
165
178
  m. fontBoundingBoxAscent ?? 0,
@@ -174,29 +187,30 @@ namespace Rays
174
187
  });
175
188
 
176
189
  EM_JS(void*, rays_wasm_font_render_, (
177
- const char* str, const char* name, double size,
190
+ const char* str, const char* name, double size, int weight, int italic,
178
191
  int* out_width, int* out_height, double* out_ascent, double* out_descent),
179
192
  {
180
- const s = UTF8ToString(str);
181
- const n = UTF8ToString(name);
182
- const c = Module._raysFontContext;
183
- const cv = Module._raysFontCanvas;
184
- c.font = `${size}px "${n}"`;
185
- const m = c.measureText(s);
186
- const asc = Math.max(
193
+ const s = UTF8ToString(str);
194
+ const n = UTF8ToString(name);
195
+ const c = Module._raysFontContext;
196
+ const cv = Module._raysFontCanvas;
197
+ const font = `${italic ? 'italic' : 'normal'} ${weight} ${size}px "${n}"`;
198
+ c.font = font;
199
+ const m = c.measureText(s);
200
+ const asc = Math.max(
187
201
  m. fontBoundingBoxAscent ?? 0,
188
202
  m.actualBoundingBoxAscent ?? size * 0.8);
189
- const dsc = Math.max(
203
+ const dsc = Math.max(
190
204
  m. fontBoundingBoxDescent ?? 0,
191
205
  m.actualBoundingBoxDescent ?? size * 0.2);
192
- const w = Math.max(1, Math.ceil(m.width));
193
- const h = Math.max(1, Math.ceil(asc + dsc));
206
+ const w = Math.max(1, Math.ceil(m.width));
207
+ const h = Math.max(1, Math.ceil(asc + dsc));
194
208
 
195
209
  if (cv.width < w) cv.width = w;
196
210
  if (cv.height < h) cv.height = h;
197
211
 
198
212
  c.clearRect(0, 0, cv.width, cv.height);
199
- c.font = `${size}px "${n}"`;// re-apply after canvas resize
213
+ c.font = font;// re-apply after canvas resize
200
214
  c.fillStyle = 'white';
201
215
  c.textBaseline = 'alphabetic';
202
216
  c.fillText(s, 0, asc);
@@ -234,12 +248,14 @@ namespace Rays
234
248
  struct CanvasFontData : public RawFont::Data
235
249
  {
236
250
 
237
- CanvasFontData (const char* name, coord size)
251
+ CanvasFontData (const char* name, coord size, int weight, bool italic)
238
252
  {
239
253
  rays_wasm_font_init_();
240
254
 
241
- this->name = name && *name != '\0' ? name : "sans-serif";
242
- this->size = size;
255
+ this->name = name && *name != '\0' ? name : "sans-serif";
256
+ this->size = size;
257
+ this->weight = weight;
258
+ this->italic = italic;
243
259
  }
244
260
 
245
261
  void draw_string (SDL_Surface* target, const char* str, coord x, coord y) override
@@ -248,7 +264,7 @@ namespace Rays
248
264
  double ascent = 0, descent = 0;
249
265
  std::shared_ptr<void> pixels(
250
266
  rays_wasm_font_render_(
251
- str, name.c_str(), (double) size,
267
+ str, name.c_str(), (double) size, weight, italic,
252
268
  &w, &h, &ascent, &descent),
253
269
  free);
254
270
  if (!pixels || w <= 0 || h <= 0) return;
@@ -260,21 +276,24 @@ namespace Rays
260
276
  rays_error(__FILE__, __LINE__, "SDL_CreateRGBSurfaceFrom failed: %s", SDL_GetError());
261
277
 
262
278
  SDL_Rect dest = {(int) x, (int) y, w, h};
279
+ // blending onto zeros premultiplies the straight alpha of the canvas
263
280
  SDL_FillRect(target, &dest, 0);
264
- SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_NONE);
281
+ SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
265
282
  SDL_BlitSurface(surface, NULL, target, &dest);
266
283
  SDL_FreeSurface(surface);
267
284
  }
268
285
 
269
286
  coord get_width (const char* str) override
270
287
  {
271
- return (coord) rays_wasm_font_text_width_(str, name.c_str(), (double) size);
288
+ return (coord) rays_wasm_font_text_width_(
289
+ str, name.c_str(), (double) size, weight, italic);
272
290
  }
273
291
 
274
292
  coord get_height (coord* ascent, coord* descent, coord* leading) override
275
293
  {
276
294
  double asc = 0, desc = 0, lead = 0;
277
- rays_wasm_font_get_metrics_(name.c_str(), (double) size, &asc, &desc, &lead);
295
+ rays_wasm_font_get_metrics_(
296
+ name.c_str(), (double) size, weight, italic, &asc, &desc, &lead);
278
297
 
279
298
  if (ascent) *ascent = (coord) asc;
280
299
  if (descent) *descent = (coord) desc;
@@ -290,7 +309,7 @@ namespace Rays
290
309
 
291
310
  Data* dup (coord size) const override
292
311
  {
293
- return new CanvasFontData(name.c_str(), size);
312
+ return new CanvasFontData(name.c_str(), size, weight, italic);
294
313
  }
295
314
 
296
315
  };// CanvasData
@@ -334,7 +353,7 @@ namespace Rays
334
353
  RawFont_load (const char* path, coord size)
335
354
  {
336
355
  RawFont rawfont;
337
- rawfont.self.reset(new SDLFontData(path, size));
356
+ rawfont.self.reset(new SDLFontData(path, size, Font::WEIGHT_NORMAL, false));
338
357
  return rawfont;
339
358
  }
340
359
 
@@ -344,29 +363,23 @@ namespace Rays
344
363
  }
345
364
 
346
365
  static RawFont::Data*
347
- create_data (const char* name, coord size)
366
+ create_data (const char* name, coord size, int weight, bool italic)
348
367
  {
349
368
  #ifdef WASM
350
- return new CanvasFontData(name, size);
369
+ return new CanvasFontData(name, size, weight, italic);
351
370
  #else
352
371
  if (name)
353
372
  not_implemented_error(__FILE__, __LINE__);
354
- return new SDLFontData("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", size);
373
+ return new SDLFontData(
374
+ "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", size, weight, italic);
355
375
  #endif
356
376
  }
357
377
 
358
- RawFont::RawFont (const char* name, coord size)
359
- : self(create_data(name, size))
378
+ RawFont::RawFont (const char* name, coord size, int weight, bool italic)
379
+ : self(create_data(name, size, weight, italic))
360
380
  {
361
381
  }
362
382
 
363
- RawFont::RawFont (const This& obj, coord size)
364
- {
365
- if (!obj) return;
366
-
367
- self.reset(obj.self->dup(size));
368
- }
369
-
370
383
  RawFont::~RawFont ()
371
384
  {
372
385
  }
@@ -398,13 +411,6 @@ namespace Rays
398
411
  return self->name;
399
412
  }
400
413
 
401
- coord
402
- RawFont::size () const
403
- {
404
- if (!*this) return 0;
405
- return self->size;
406
- }
407
-
408
414
  coord
409
415
  RawFont::get_width (const char* str) const
410
416
  {
data/src/win32/bitmap.cpp CHANGED
@@ -1,11 +1,15 @@
1
1
  #include "../bitmap.h"
2
2
 
3
3
 
4
+ #define STBI_WINDOWS_UTF8
5
+ #define STBIW_WINDOWS_UTF8
6
+
4
7
  #define STB_IMAGE_IMPLEMENTATION
5
8
  #include <stb_image.h>
6
9
  #define STB_IMAGE_WRITE_IMPLEMENTATION
7
10
  #include <stb_image_write.h>
8
11
 
12
+ #include <memory>
9
13
  #include "rays/exception.h"
10
14
  #include "rays/image.h"
11
15
  #include "rays/painter.h"
@@ -166,13 +170,13 @@ namespace Rays
166
170
  }
167
171
 
168
172
  const auto& cs = bitmap.color_space();
169
- size_t w = bitmap.width();
170
- size_t h = bitmap.height();
171
- size_t pitch = w * cs.Bpp();
173
+ int w = bitmap.width();
174
+ int h = bitmap.height();
175
+ int row_size = w * cs.Bpp();
172
176
 
173
- std::unique_ptr<uchar[]> pixels(new uchar[h * pitch]);
174
- for (size_t y = 0; y < h; ++y)
175
- memcpy(pixels.get() + pitch * y, bitmap.at<uchar>(0, y), pitch);
177
+ std::unique_ptr<uchar[]> pixels(new uchar[h * row_size]);
178
+ for (int y = 0; y < h; ++y)
179
+ memcpy(pixels.get() + row_size * y, bitmap.at<uchar>(0, y), row_size);
176
180
 
177
181
  String ext = extension;
178
182
  ext.downcase();
@@ -207,6 +211,10 @@ namespace Rays
207
211
  p.end();
208
212
  bmp = img.bitmap();
209
213
  }
214
+
215
+ if (bmp.color_space().has_alpha())
216
+ bmp = bmp.dup(false);// stb_image_write expects straight alpha
217
+
210
218
  save_bitmap(bmp, path);
211
219
  }
212
220
 
@@ -217,16 +225,17 @@ namespace Rays
217
225
  argument_error(__FILE__, __LINE__);
218
226
 
219
227
  int w = 0, h = 0, Bpp = 0;
220
- uchar* pixels = stbi_load(path, &w, &h, &Bpp, 0);
228
+ std::unique_ptr<uchar, decltype(&stbi_image_free)>
229
+ pixels(stbi_load(path, &w, &h, &Bpp, 0), stbi_image_free);
221
230
  if (!pixels)
222
231
  rays_error(__FILE__, __LINE__, "failed to load: '%s'", path);
223
232
 
224
233
  ColorSpace cs;
225
234
  switch (Bpp)
226
235
  {
227
- case 1: cs = GRAY_8; break;
228
- case 3: cs = RGB_888; break;
229
- case 4: cs = RGBA_8888; break;
236
+ case 1: cs = GRAY_8; break;
237
+ case 3: cs = RGB_888; break;
238
+ case 4: cs = ColorSpace(RGBA_8888, false); break;// stb_image gives straight alpha
230
239
  default:
231
240
  rays_error(__FILE__, __LINE__, "unsupported image file: '%s'", path);
232
241
  }
@@ -235,11 +244,11 @@ namespace Rays
235
244
  if (!bmp)
236
245
  rays_error(__FILE__, __LINE__, "failed to create Bitmap object");
237
246
 
238
- int pitch = Bpp * w;
247
+ int size = Bpp * w;
239
248
  for (int y = 0; y < h; ++y)
240
- memcpy(bmp.at<uchar>(0, y), pixels + pitch * y, pitch);
249
+ memcpy(bmp.at<uchar>(0, y), pixels.get() + size * y, size);
241
250
 
242
- return bmp;
251
+ return cs.has_alpha() ? bmp.dup(true) : bmp;
243
252
  }
244
253
 
245
254
  HBITMAP
data/src/win32/font.cpp CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
 
4
4
  #include <assert.h>
5
+ #include <string>
5
6
  #include <set>
6
7
  #include "rays/exception.h"
7
8
  #include "gdi.h"
@@ -16,7 +17,7 @@ namespace Rays
16
17
 
17
18
  Win32::Font font;
18
19
 
19
- String path;
20
+ mutable coord height = -1, ascent = 0, descent = 0, leading = 0;
20
21
 
21
22
  };// RawFont::Data
22
23
 
@@ -40,15 +41,18 @@ namespace Rays
40
41
 
41
42
  static int CALLBACK
42
43
  enum_callback (
43
- const ENUMLOGFONT* elf, const NEWTEXTMETRIC* ntm, DWORD font_type, LPARAM lp)
44
+ const ENUMLOGFONTW* elf, const NEWTEXTMETRICW* ntm, DWORD font_type, LPARAM lp)
44
45
  {
45
- const auto* params = (EnumFontFamiliesCallbackParams*) lp;
46
- const char* name = params->fullname
47
- ? (const char*) elf->elfFullName
48
- : (const char*) elf->elfLogFont.lfFaceName;
46
+ const auto* params = (EnumFontFamiliesCallbackParams*) lp;
47
+ const wchar_t* name = params->fullname
48
+ ? elf->elfFullName
49
+ : elf->elfLogFont.lfFaceName;
49
50
 
50
- if (name && *name != '\0' && *name != '@')
51
- params->names->insert(name);
51
+ if (name && *name != L'\0' && *name != L'@')
52
+ {
53
+ size_t max_ = params->fullname ? LF_FULLFACESIZE : LF_FACESIZE;
54
+ params->names->insert(String(name, wcsnlen(name, max_)));
55
+ }
52
56
 
53
57
  return TRUE;
54
58
  }
@@ -57,16 +61,19 @@ namespace Rays
57
61
  get_font_names (
58
62
  StringSet* names, HDC hdc, const char* query = NULL, bool fullname = false)
59
63
  {
60
- assert(!query || strlen(query) < LF_FACESIZE);
61
-
62
- LOGFONT lf = {0};
64
+ LOGFONTW lf = {0};
63
65
  lf.lfCharSet = DEFAULT_CHARSET;
64
66
 
65
- if (query) strcpy(lf.lfFaceName, query);
67
+ if (query)
68
+ {
69
+ std::wstring wquery = String(query).to_wstr();
70
+ assert(wquery.size() < LF_FACESIZE);
71
+ wcsncpy(lf.lfFaceName, wquery.c_str(), LF_FACESIZE - 1);
72
+ }
66
73
 
67
74
  EnumFontFamiliesCallbackParams params(names, fullname);
68
- EnumFontFamiliesEx(
69
- hdc, &lf, (FONTENUMPROC) &enum_callback, (LPARAM) &params, 0);
75
+ EnumFontFamiliesExW(
76
+ hdc, &lf, (FONTENUMPROCW) &enum_callback, (LPARAM) &params, 0);
70
77
  }
71
78
 
72
79
  const FontFamilyMap&
@@ -105,18 +112,9 @@ namespace Rays
105
112
  {
106
113
  }
107
114
 
108
- RawFont::RawFont (const char* name, coord size)
109
- {
110
- self->font = Win32::Font(name, size);
111
- }
112
-
113
- RawFont::RawFont (const This& obj, coord size)
115
+ RawFont::RawFont (const char* name, coord size, int weight, bool italic)
114
116
  {
115
- const char* path = obj.self->path.empty() ? NULL : obj.self->path.c_str();
116
- if (path)
117
- *this = RawFont_load(path, size);
118
- else
119
- self->font = Win32::Font(obj.name().c_str(), size);
117
+ self->font = Win32::Font(name, size, weight, italic);
120
118
  }
121
119
 
122
120
  RawFont::~RawFont ()
@@ -142,8 +140,10 @@ namespace Rays
142
140
  if (!*this)
143
141
  invalid_state_error(__FILE__, __LINE__);
144
142
 
143
+ std::wstring wstr = String(str).to_wstr();
144
+
145
145
  coord width = 0, height = 0;
146
- if (!self->font.get_extent(&width, &height, str))
146
+ if (!self->font.get_extent(&width, &height, wstr.c_str()))
147
147
  rays_error(__FILE__, __LINE__, "failed to get font extent.");
148
148
 
149
149
  DC dc = hdc;
@@ -155,7 +155,7 @@ namespace Rays
155
155
  dc.set_text_color(RGB(255, 255, 255));
156
156
  dc.set_back_color(RGB(0, 0, 0));
157
157
 
158
- BOOL ret = TextOutA(dc.handle(), x, y, str, strlen(str));
158
+ BOOL ret = TextOutW(dc.handle(), x, y, wstr.c_str(), (int) wstr.size());
159
159
 
160
160
  dc.set_font(font);
161
161
  dc.set_text_color(text_color);
@@ -172,13 +172,6 @@ namespace Rays
172
172
  return self->font.name();
173
173
  }
174
174
 
175
- coord
176
- RawFont::size () const
177
- {
178
- if (!*this) return 0;
179
- return self->font.size();
180
- }
181
-
182
175
  coord
183
176
  RawFont::get_width (const char* str) const
184
177
  {
@@ -203,24 +196,30 @@ namespace Rays
203
196
  if (!*this)
204
197
  invalid_state_error(__FILE__, __LINE__);
205
198
 
206
- if (ascent || descent || leading)
199
+ if (self->height < 0)
207
200
  {
208
201
  Win32::DC dc(GetDC(NULL), true, Win32::DC::RELEASE_DC);
209
202
  dc.set_font(self->font);
210
203
 
211
- TEXTMETRIC tm;
212
- GetTextMetrics(dc.handle(), &tm);
204
+ TEXTMETRICW tm;
205
+ if (!GetTextMetricsW(dc.handle(), &tm))
206
+ rays_error(__FILE__, __LINE__, "failed to get font metrics");
207
+
208
+ coord height;
209
+ if (!self->font.get_extent(NULL, &height, L"X"))
210
+ rays_error(__FILE__, __LINE__, "failed to get font height");
213
211
 
214
- if (ascent) *ascent = tm.tmAscent;
215
- if (descent) *descent = tm.tmDescent;
216
- if (leading) *leading = tm.tmExternalLeading;
212
+ self->height = height;
213
+ self->ascent = tm.tmAscent;
214
+ self->descent = tm.tmDescent;
215
+ self->leading = tm.tmExternalLeading;
217
216
  }
218
217
 
219
- coord height;
220
- if (!self->font.get_extent(NULL, &height, "X"))
221
- rays_error(__FILE__, __LINE__, "failed to get font height");
218
+ if (ascent) *ascent = self->ascent;
219
+ if (descent) *descent = self->descent;
220
+ if (leading) *leading = self->leading;
222
221
 
223
- return height;
222
+ return self->height;
224
223
  }
225
224
 
226
225
  RawFont::operator bool () const
data/src/win32/gdi.cpp CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
 
4
4
  #include <assert.h>
5
+ #include <math.h>
6
+ #include <string>
5
7
  #include <vector>
6
8
 
7
9
 
@@ -117,7 +119,7 @@ namespace Rays
117
119
  return false;
118
120
 
119
121
  LOGPEN logpen;
120
- if (!GetObject(handle(), sizeof(logpen), &logpen))
122
+ if (!GetObjectW(handle(), sizeof(logpen), &logpen))
121
123
  return false;
122
124
 
123
125
  if (red) *red = GetRValue(logpen.lopnColor);
@@ -179,7 +181,7 @@ namespace Rays
179
181
  return false;
180
182
 
181
183
  LOGBRUSH logbrush;
182
- if (!GetObject(handle(), sizeof(logbrush), &logbrush))
184
+ if (!GetObjectW(handle(), sizeof(logbrush), &logbrush))
183
185
  return false;
184
186
 
185
187
  if (red) *red = GetRValue(logbrush.lbColor);
@@ -215,34 +217,34 @@ namespace Rays
215
217
 
216
218
 
217
219
  static HFONT
218
- create_font (const char* name, coord size = 0)
220
+ create_font (const char* name, coord size, int weight, bool italic)
219
221
  {
220
- NONCLIENTMETRICSA metrics;
222
+ NONCLIENTMETRICSW metrics;
221
223
  memset(&metrics, 0, sizeof(metrics));
222
224
  metrics.cbSize = sizeof(metrics);
223
225
 
224
- if (!SystemParametersInfoA(
226
+ if (!SystemParametersInfoW(
225
227
  SPI_GETNONCLIENTMETRICS, sizeof(metrics), &metrics, 0))
226
228
  {
227
229
  return NULL;
228
230
  }
229
231
 
230
- LOGFONTA& logfont = metrics.lfMessageFont;
232
+ LOGFONTW& logfont = metrics.lfMessageFont;
231
233
 
232
234
  if (name)
233
- strcpy(logfont.lfFaceName, name);
234
-
235
- if (size == 0)
236
- logfont.lfHeight = 0;
237
- else
238
235
  {
239
- logfont.lfHeight = -MulDiv(
240
- size,
241
- GetDeviceCaps(screen_dc().handle(), LOGPIXELSY),
242
- 72);
236
+ std::wstring wname = String(name).to_wstr();
237
+ wcsncpy(logfont.lfFaceName, wname.c_str(), LF_FACESIZE - 1);
238
+ logfont.lfFaceName[LF_FACESIZE - 1] = L'\0';
243
239
  }
244
240
 
245
- return CreateFontIndirectA(&logfont);
241
+ logfont.lfHeight = size == 0 ? 0 : -(LONG) fmax(1, round(size));
242
+
243
+ if (weight == 0) weight = 1;// 0 == FW_DONTCARE
244
+ if (weight >= 0) logfont.lfWeight = weight;
245
+ if (italic) logfont.lfItalic = TRUE;
246
+
247
+ return CreateFontIndirectW(&logfont);
246
248
  }
247
249
 
248
250
 
@@ -252,9 +254,9 @@ namespace Rays
252
254
  self->handle.reset(handle, owner);
253
255
  }
254
256
 
255
- Font::Font (const char* name, coord size)
257
+ Font::Font (const char* name, coord size, int weight, bool italic)
256
258
  {
257
- self->handle.reset(create_font(name, size));
259
+ self->handle.reset(create_font(name, size, weight, italic));
258
260
  }
259
261
 
260
262
  Font::~Font ()
@@ -262,16 +264,15 @@ namespace Rays
262
264
  }
263
265
 
264
266
  static bool
265
- calc_size (
266
- coord* width, coord* height, HDC hdc, const char* str)
267
+ calc_size (coord* width, coord* height, HDC hdc, const wchar_t* str)
267
268
  {
268
269
  if (!width || !height || !hdc || !str) return false;
269
270
 
270
- bool empty = *str == '\0';
271
- if (empty) str = " ";
271
+ bool empty = *str == L'\0';
272
+ if (empty) str = L" ";
272
273
 
273
274
  RECT rect = {0, 0, 0, 0};
274
- int ret = DrawTextA(
275
+ int ret = DrawTextW(
275
276
  hdc, str, -1, &rect,
276
277
  DT_EXPANDTABS | DT_NOPREFIX | DT_CALCRECT);
277
278
  if (!ret) return false;
@@ -282,10 +283,16 @@ namespace Rays
282
283
  }
283
284
 
284
285
  bool
285
- Font::get_extent (
286
- coord* width, coord* height, const char* str, HDC hdc)
286
+ Font::get_extent (coord* width, coord* height, const char* str, HDC hdc)
287
+ {
288
+ if (!str) return false;
289
+ return get_extent(width, height, String(str).to_wstr().c_str(), hdc);
290
+ }
291
+
292
+ bool
293
+ Font::get_extent (coord* width, coord* height, const wchar_t* str, HDC hdc)
287
294
  {
288
- if (!*this || (!width && !height))
295
+ if (!*this || (!width && !height) || !str)
289
296
  return false;
290
297
 
291
298
  if (width) *width = 0;
@@ -312,12 +319,12 @@ namespace Rays
312
319
  {
313
320
  if (!*this) return "";
314
321
 
315
- LOGFONT logfont;
322
+ LOGFONTW logfont;
316
323
  int size = sizeof(logfont);
317
- if (GetObject(self->handle.handle(), size, &logfont) != size)
324
+ if (GetObjectW(self->handle.handle(), size, &logfont) != size)
318
325
  return "";
319
326
 
320
- return logfont.lfFaceName;
327
+ return String(logfont.lfFaceName, wcsnlen(logfont.lfFaceName, LF_FACESIZE));
321
328
  }
322
329
 
323
330
  coord
@@ -325,22 +332,12 @@ namespace Rays
325
332
  {
326
333
  if (!*this) return 0;
327
334
 
328
- LOGFONT logfont;
335
+ LOGFONTW logfont;
329
336
  int size = sizeof(logfont);
330
- if (GetObject(self->handle.handle(), size, &logfont) != size)
337
+ if (GetObjectW(self->handle.handle(), size, &logfont) != size)
331
338
  return 0;
332
339
 
333
- if (logfont.lfHeight >= 0)
334
- return logfont.lfHeight;
335
-
336
- if (logfont.lfHeight < 0)
337
- {
338
- return -MulDiv(
339
- logfont.lfHeight, 72,
340
- GetDeviceCaps(screen_dc().handle(), LOGPIXELSY));
341
- }
342
- else
343
- return logfont.lfHeight;
340
+ return logfont.lfHeight >= 0 ? logfont.lfHeight : -logfont.lfHeight;
344
341
  }
345
342
 
346
343
  HFONT
@@ -373,8 +370,8 @@ namespace Rays
373
370
  static bool
374
371
  load_bitmap (uint id, HINSTANCE hinst = NULL)
375
372
  {
376
- if (!hinst) hinst = (HINSTANCE) GetModuleHandle(NULL);
377
- self->handle.reset(LoadBitmap(hinst, MAKEINTRESOURCE(id)));
373
+ if (!hinst) hinst = (HINSTANCE) GetModuleHandleW(NULL);
374
+ self->handle.reset(LoadBitmapW(hinst, MAKEINTRESOURCEW(id)));
378
375
  return !!self->handle;
379
376
  }
380
377
  #endif
@@ -398,7 +395,7 @@ namespace Rays
398
395
  Bitmap::width () const
399
396
  {
400
397
  BITMAP bmp;
401
- if (!*this || !GetObject(handle(), sizeof(bmp), &bmp))
398
+ if (!*this || !GetObjectW(handle(), sizeof(bmp), &bmp))
402
399
  return 0;
403
400
  return bmp.bmWidth;
404
401
  }
@@ -407,7 +404,7 @@ namespace Rays
407
404
  Bitmap::height () const
408
405
  {
409
406
  BITMAP bmp;
410
- if (!*this || !GetObject(handle(), sizeof(bmp), &bmp))
407
+ if (!*this || !GetObjectW(handle(), sizeof(bmp), &bmp))
411
408
  return 0;
412
409
  return bmp.bmHeight;
413
410
  }