rays 0.1.47 → 0.1.49

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 (89) hide show
  1. checksums.yaml +4 -4
  2. data/.doc/ext/rays/bitmap.cpp +287 -46
  3. data/.doc/ext/rays/camera.cpp +2 -2
  4. data/.doc/ext/rays/color.cpp +11 -0
  5. data/.doc/ext/rays/defs.cpp +32 -8
  6. data/.doc/ext/rays/font.cpp +50 -2
  7. data/.doc/ext/rays/image.cpp +3 -3
  8. data/.doc/ext/rays/matrix.cpp +65 -7
  9. data/.doc/ext/rays/native.cpp +2 -4
  10. data/.doc/ext/rays/painter.cpp +117 -9
  11. data/.doc/ext/rays/point.cpp +1 -11
  12. data/.doc/ext/rays/polygon.cpp +133 -97
  13. data/.doc/ext/rays/polyline.cpp +89 -10
  14. data/.doc/ext/rays/rays.cpp +80 -0
  15. data/.doc/ext/rays/{noise.cpp → util.cpp} +2 -2
  16. data/ChangeLog.md +46 -0
  17. data/VERSION +1 -1
  18. data/ext/rays/bitmap.cpp +288 -46
  19. data/ext/rays/camera.cpp +2 -2
  20. data/ext/rays/color.cpp +13 -1
  21. data/ext/rays/defs.cpp +32 -8
  22. data/ext/rays/defs.h +56 -3
  23. data/ext/rays/font.cpp +56 -4
  24. data/ext/rays/image.cpp +3 -3
  25. data/ext/rays/matrix.cpp +69 -7
  26. data/ext/rays/native.cpp +2 -4
  27. data/ext/rays/painter.cpp +132 -13
  28. data/ext/rays/point.cpp +1 -12
  29. data/ext/rays/polygon.cpp +136 -99
  30. data/ext/rays/polyline.cpp +95 -9
  31. data/ext/rays/rays.cpp +80 -0
  32. data/ext/rays/{noise.cpp → util.cpp} +2 -2
  33. data/include/rays/color.h +3 -1
  34. data/include/rays/defs.h +24 -26
  35. data/include/rays/font.h +17 -3
  36. data/include/rays/image.h +1 -1
  37. data/include/rays/matrix.h +24 -0
  38. data/include/rays/painter.h +24 -0
  39. data/include/rays/polygon.h +68 -43
  40. data/include/rays/polyline.h +17 -2
  41. data/include/rays/ruby/polygon.h +0 -11
  42. data/include/rays/ruby/rays.h +4 -0
  43. data/include/rays/{noise.h → util.h} +2 -2
  44. data/lib/rays/color.rb +7 -1
  45. data/lib/rays/font.rb +1 -1
  46. data/lib/rays/image.rb +11 -1
  47. data/lib/rays/matrix.rb +16 -0
  48. data/lib/rays/painter.rb +18 -7
  49. data/lib/rays/point.rb +5 -1
  50. data/lib/rays/polygon.rb +44 -35
  51. data/lib/rays/polyline.rb +54 -8
  52. data/lib/rays.rb +0 -1
  53. data/rays.gemspec +2 -2
  54. data/src/color.cpp +11 -2
  55. data/src/font.cpp +37 -18
  56. data/src/font.h +6 -5
  57. data/src/image.cpp +58 -14
  58. data/src/ios/font.mm +89 -32
  59. data/src/ios/helper.h +2 -2
  60. data/src/ios/helper.mm +2 -2
  61. data/src/matrix.cpp +45 -0
  62. data/src/osx/font.mm +93 -33
  63. data/src/osx/helper.h +2 -2
  64. data/src/osx/helper.mm +2 -2
  65. data/src/painter.cpp +246 -114
  66. data/src/painter.h +11 -3
  67. data/src/polygon.cpp +431 -332
  68. data/src/polyline.cpp +138 -27
  69. data/src/polyline.h +3 -5
  70. data/src/shader.cpp +36 -4
  71. data/src/shader.h +1 -1
  72. data/src/texture.cpp +23 -4
  73. data/src/texture.h +2 -0
  74. data/src/{noise.cpp → util.cpp} +1 -1
  75. data/src/win32/font.cpp +1 -1
  76. data/test/test_bitmap.rb +12 -5
  77. data/test/test_color.rb +25 -4
  78. data/test/test_font.rb +23 -2
  79. data/test/test_image.rb +44 -18
  80. data/test/test_matrix.rb +22 -0
  81. data/test/test_painter.rb +27 -0
  82. data/test/test_point.rb +1 -1
  83. data/test/test_polygon.rb +52 -45
  84. data/test/test_polyline.rb +191 -72
  85. metadata +12 -18
  86. data/.doc/ext/rays/polygon_line.cpp +0 -97
  87. data/ext/rays/polygon_line.cpp +0 -100
  88. data/lib/rays/polygon_line.rb +0 -33
  89. data/test/test_polygon_line.rb +0 -164
data/lib/rays/polygon.rb CHANGED
@@ -8,74 +8,83 @@ module Rays
8
8
  class Polygon
9
9
 
10
10
  include Enumerable
11
+ include Comparable
11
12
 
12
- def initialize(*args, loop: true)
13
- setup args, loop
13
+ def initialize(*args, loop: true, colors: nil, texcoords: nil)
14
+ setup args, loop, colors, texcoords
14
15
  end
15
16
 
16
- def transform(matrix = nil, &block)
17
- lines = to_a
18
- lines = lines.map {|line| line.transform matrix} if matrix
19
- lines = block.call lines if block
20
- self.class.new(*lines)
17
+ def transform(&block)
18
+ polylines = block.call to_a
19
+ self.class.new(*polylines)
21
20
  end
22
21
 
23
22
  def intersects(obj)
24
23
  !(self & obj).empty?
25
24
  end
26
25
 
27
- def self.points(*args)
28
- points! args
26
+ def <=>(o)
27
+ (size <=> o.size).then {|cmp| return cmp if cmp != 0}
28
+ to_a.zip(o.to_a).each {|a, b| cmp = a <=> b; return cmp if cmp != 0}
29
+ 0
29
30
  end
30
31
 
31
- def self.lines(*args)
32
- lines! args
32
+ def inspect()
33
+ "#<Rays::Polygon [#{map {|polyline| polyline.inspect}.join ', '}]>"
33
34
  end
34
35
 
35
- def self.line_strip(*args, loop: false)
36
- line_strip! args, loop
36
+ def self.points(*points)
37
+ points! points
37
38
  end
38
39
 
39
- def self.rect(
40
- *args, round: nil, lt: nil, rt: nil, lb: nil, rb: nil,
41
- nsegment: nil)
40
+ def self.line(*points, loop: false)
41
+ line! points, loop
42
+ end
42
43
 
43
- rect! args, round, lt, rt, lb, rb, nsegment
44
+ def self.lines(*points)
45
+ lines! points
44
46
  end
45
47
 
46
- def self.ellipse(
47
- *args, center: nil, radius: nil, hole: nil, from: nil, to: nil,
48
- nsegment: nil)
48
+ def self.triangles(*points, loop: true, colors: nil, texcoords: nil)
49
+ triangles! points, loop, colors, texcoords
50
+ end
49
51
 
50
- ellipse! args, center, radius, hole, from, to, nsegment
52
+ def self.triangle_strip(*points, colors: nil, texcoords: nil)
53
+ triangle_strip! points, colors, texcoords
51
54
  end
52
55
 
53
- def self.triangles(*args, loop: true)
54
- triangles! args, loop
56
+ def self.triangle_fan(*points, colors: nil, texcoords: nil)
57
+ triangle_fan! points, colors, texcoords
55
58
  end
56
59
 
57
- def self.triangle_strip(*args)
58
- triangle_strip! args
60
+ def self.rect(
61
+ *args, round: nil, lt: nil, rt: nil, lb: nil, rb: nil,
62
+ nsegment: nil)
63
+
64
+ rect! args, round, lt, rt, lb, rb, nsegment
59
65
  end
60
66
 
61
- def self.triangle_fan(*args)
62
- triangle_fan! args
67
+ def self.quads(*points, loop: true, colors: nil, texcoords: nil)
68
+ quads! points, loop, colors, texcoords
63
69
  end
64
70
 
65
- def self.quads(*args, loop: true)
66
- quads! args, loop
71
+ def self.quad_strip(*points, colors: nil, texcoords: nil)
72
+ quad_strip! points, colors, texcoords
67
73
  end
68
74
 
69
- def self.quad_strip(*args)
70
- quad_strip! args
75
+ def self.ellipse(
76
+ *args, center: nil, radius: nil, hole: nil, from: nil, to: nil,
77
+ nsegment: nil)
78
+
79
+ ellipse! args, center, radius, hole, from, to, nsegment
71
80
  end
72
81
 
73
- def self.curve(*args, loop: false)
74
- curve! args, loop
82
+ def self.curve(*points, loop: false, nsegment: nil)
83
+ curve! points, loop, nsegment
75
84
  end
76
85
 
77
- def self.bezier(*args, loop: false)
78
- bezier! args, loop
86
+ def self.bezier(*points, loop: false, nsegment: nil)
87
+ bezier! points, loop, nsegment
79
88
  end
80
89
 
81
90
  end# Polygon
data/lib/rays/polyline.rb CHANGED
@@ -7,20 +7,66 @@ module Rays
7
7
  class Polyline
8
8
 
9
9
  include Enumerable
10
+ include Comparable
10
11
 
11
- def initialize(*points, loop: false)
12
- setup points, loop
12
+ def initialize(
13
+ *points, loop: false, fill: nil, colors: nil, texcoords: nil, hole: false)
14
+
15
+ setup points, loop, (fill != nil ? fill : loop), colors, texcoords, hole
16
+ end
17
+
18
+ def with(**kwargs)
19
+ points_, loop_, fill_, colors_, texcoords_, hole_ =
20
+ kwargs.values_at :points, :loop, :fill, :colors, :texcoords, :hole
21
+ self.class.new(
22
+ *(points_ || (points? ? points : [])),
23
+ loop: loop_ != nil ? loop_ : loop?,
24
+ fill: fill_ != nil ? fill_ : fill?,
25
+ colors: colors_ || (colors? ? colors : nil),
26
+ texcoords: texcoords_ || (texcoords? ? texcoords : nil),
27
+ hole: hole_ != nil ? hole_ : hole?)
28
+ end
29
+
30
+ def points()
31
+ each_point.to_a
32
+ end
33
+
34
+ def colors()
35
+ each_color.to_a
36
+ end
37
+
38
+ def texcoords()
39
+ each_texcoord.to_a
40
+ end
41
+
42
+ def each_point(&block)
43
+ block ? each_point!(&block) : enum_for(:each_point!)
44
+ end
45
+
46
+ def each_color(&block)
47
+ block ? each_color!(&block) : enum_for(:each_color!)
48
+ end
49
+
50
+ def each_texcoord(&block)
51
+ block ? each_texcoord!(&block) : enum_for(:each_texcoord!)
13
52
  end
14
53
 
15
- def transform(matrix = nil, loop: loop?, &block)
16
- points = to_a
17
- points = points.map {|point| matrix * point} if matrix
18
- points = block.call points if block
19
- self.class.new(*points, loop: loop)
54
+ alias each each_point
55
+
56
+ def <=>(o)
57
+ (size <=> o.size) .then {|cmp| return cmp if cmp != 0}
58
+ (loop? <=> o.loop?).then {|cmp| return cmp if cmp != 0}
59
+ (fill? <=> o.fill?).then {|cmp| return cmp if cmp != 0}
60
+ points .zip(o.points) .each {|a, b| cmp = a <=> b; return cmp if cmp != 0}
61
+ colors .zip(o.colors) .each {|a, b| cmp = a <=> b; return cmp if cmp != 0}
62
+ texcoords.zip(o.texcoords).each {|a, b| cmp = a <=> b; return cmp if cmp != 0}
63
+ 0
20
64
  end
21
65
 
22
66
  def inspect()
23
- "#<Rays::Polyline #{to_a.join ', '}, loop: #{loop?}>"
67
+ p = points.map {|o| o.to_a.join ','}.join ', '
68
+ c, t = colors.size, texcoords.size
69
+ "#<Rays::Polyline [#{p}] loop:#{loop?} fill:#{fill?} hole:#{hole?} colors:#{c} texcoords:#{t}>"
24
70
  end
25
71
 
26
72
  end# Polyline
data/lib/rays.rb CHANGED
@@ -10,7 +10,6 @@ require 'rays/matrix'
10
10
  require 'rays/painter'
11
11
  require 'rays/polyline'
12
12
  require 'rays/polygon'
13
- require 'rays/polygon_line'
14
13
  require 'rays/bitmap'
15
14
  require 'rays/image'
16
15
  require 'rays/font'
data/rays.gemspec CHANGED
@@ -25,8 +25,8 @@ Gem::Specification.new do |s|
25
25
  s.platform = Gem::Platform::RUBY
26
26
  s.required_ruby_version = '>= 3.0.0'
27
27
 
28
- s.add_runtime_dependency 'xot', '~> 0.1.41'
29
- s.add_runtime_dependency 'rucy', '~> 0.1.42'
28
+ s.add_runtime_dependency 'xot', '~> 0.1.42'
29
+ s.add_runtime_dependency 'rucy', '~> 0.1.44'
30
30
 
31
31
  s.files = `git ls-files`.split $/
32
32
  s.executables = s.files.grep(%r{^bin/}) {|f| File.basename f}
data/src/color.cpp CHANGED
@@ -47,8 +47,17 @@ namespace Rays
47
47
  hue = fmod(hue, 1.f);
48
48
  if (hue < 0) hue += 1.f;
49
49
 
50
- auto c = glm::rgbColor(Vec3(hue * 360.f, saturation, value));
51
- return Color(c[0], c[1], c[2], alpha);
50
+ auto rgb = glm::rgbColor(Vec3(hue * 360.f, saturation, value));
51
+ return Color(rgb[0], rgb[1], rgb[2], alpha);
52
+ }
53
+
54
+ void
55
+ get_hsv (float* hue, float* saturation, float* value, const Color& color)
56
+ {
57
+ auto hsv = glm::hsvColor(Vec3(color.r, color.g, color.b));
58
+ if (hue) *hue = hsv[0] / 360.f;
59
+ if (saturation) *saturation = hsv[1];
60
+ if (value) *value = hsv[2];
52
61
  }
53
62
 
54
63
 
data/src/font.cpp CHANGED
@@ -27,7 +27,7 @@ namespace Rays
27
27
  if (pixel_density != for_pixel_density)
28
28
  {
29
29
  rawfont_for_pixel_density =
30
- RawFont(rawfont.name(), rawfont.size() * pixel_density);
30
+ RawFont(rawfont, rawfont.size() * pixel_density);
31
31
  for_pixel_density = pixel_density;
32
32
  }
33
33
 
@@ -37,8 +37,16 @@ namespace Rays
37
37
  };// Font::Data
38
38
 
39
39
 
40
+ Font
41
+ load_font (const char* path, coord size)
42
+ {
43
+ Font font;
44
+ font.self->rawfont = RawFont_load(path, size);
45
+ return font;
46
+ }
47
+
40
48
  const Font&
41
- default_font ()
49
+ get_default_font ()
42
50
  {
43
51
  static const Font FONT(NULL);
44
52
  return FONT;
@@ -50,21 +58,6 @@ namespace Rays
50
58
  return font.self->get_raw(pixel_density);
51
59
  }
52
60
 
53
- coord
54
- Font_get_width (const Font& font, float pixel_density, const char* str)
55
- {
56
- return Font_get_raw(font, pixel_density).get_width(str);
57
- }
58
-
59
- coord
60
- Font_get_height (
61
- const Font& font, float pixel_density,
62
- coord* ascent, coord* descent, coord* leading)
63
- {
64
- return Font_get_raw(font, pixel_density)
65
- .get_height(ascent, descent, leading);
66
- }
67
-
68
61
 
69
62
  Font::Font ()
70
63
  {
@@ -79,12 +72,26 @@ namespace Rays
79
72
  {
80
73
  }
81
74
 
75
+ Font
76
+ Font::dup () const
77
+ {
78
+ Font f;
79
+ f.self->rawfont = RawFont(self->rawfont, self->rawfont.size());
80
+ return f;
81
+ }
82
+
82
83
  String
83
84
  Font::name () const
84
85
  {
85
86
  return self->rawfont.name();
86
87
  }
87
88
 
89
+ void
90
+ Font::set_size (coord size)
91
+ {
92
+ self->rawfont = RawFont(self->rawfont, size);
93
+ }
94
+
88
95
  coord
89
96
  Font::size () const
90
97
  {
@@ -94,7 +101,19 @@ namespace Rays
94
101
  coord
95
102
  Font::get_width (const char* str) const
96
103
  {
97
- return self->rawfont.get_width(str);
104
+ if (!strchr(str, '\n'))
105
+ return self->rawfont.get_width(str);
106
+
107
+ Xot::StringList lines;
108
+ split(&lines, str);
109
+
110
+ coord width = 0;
111
+ for (const auto& line : lines)
112
+ {
113
+ coord w = self->rawfont.get_width(line.c_str());
114
+ if (w > width) width = w;
115
+ }
116
+ return width;
98
117
  }
99
118
 
100
119
  coord
data/src/font.h CHANGED
@@ -15,11 +15,15 @@ namespace Rays
15
15
  class RawFont
16
16
  {
17
17
 
18
+ typedef RawFont This;
19
+
18
20
  public:
19
21
 
20
22
  RawFont ();
21
23
 
22
- RawFont (const char* name, coord size = 0);
24
+ RawFont (const char* name, coord size);
25
+
26
+ RawFont (const This& obj, coord size);
23
27
 
24
28
  ~RawFont ();
25
29
 
@@ -51,11 +55,8 @@ namespace Rays
51
55
 
52
56
  const RawFont& Font_get_raw (const Font& font, float pixel_density);
53
57
 
54
- coord Font_get_width (const Font& font, float pixel_density, const char* str);
55
58
 
56
- coord Font_get_height (
57
- const Font& font, float pixel_density,
58
- coord* ascent = NULL, coord* descent = NULL, coord* leading = NULL);
59
+ RawFont RawFont_load (const char* path, coord size);
59
60
 
60
61
 
61
62
  }// Rays
data/src/image.cpp CHANGED
@@ -10,6 +10,13 @@
10
10
  #include "texture.h"
11
11
 
12
12
 
13
+ #if 0
14
+ #define PRINT_MODIFIED_FLAGS(message) self->print_modified_flags(message)
15
+ #else
16
+ #define PRINT_MODIFIED_FLAGS(message)
17
+ #endif
18
+
19
+
13
20
  namespace Rays
14
21
  {
15
22
 
@@ -27,6 +34,16 @@ namespace Rays
27
34
 
28
35
  mutable Texture texture;
29
36
 
37
+ void print_modified_flags (const char* message)
38
+ {
39
+ printf("%s: %d %d %d %d \n",
40
+ message,
41
+ bitmap ? 1 : 0,
42
+ Bitmap_get_modified(bitmap) ? 1 : 0,
43
+ texture ? 1 : 0,
44
+ texture.modified() ? 1 : 0);
45
+ }
46
+
30
47
  };// Image::Data
31
48
 
32
49
 
@@ -82,18 +99,30 @@ namespace Rays
82
99
  if (!self->bitmap)
83
100
  {
84
101
  if (self->texture)
102
+ {
103
+ PRINT_MODIFIED_FLAGS("new bitmap from texture");
85
104
  self->bitmap = Bitmap_from(self->texture);
105
+ }
86
106
  else
107
+ {
108
+ PRINT_MODIFIED_FLAGS("new bitmap");
87
109
  self->bitmap = Bitmap(self->width, self->height, self->color_space);
110
+ }
88
111
  clear_modified_flags(image);
89
112
  }
90
- else if (
91
- self->texture &&
92
- self->texture.modified() &&
93
- !Bitmap_get_modified(self->bitmap))
113
+ else if (self->texture && self->texture.modified())
94
114
  {
95
- self->bitmap = Bitmap_from(self->texture);
96
- clear_modified_flags(image);
115
+ if (Bitmap_get_modified(self->bitmap))
116
+ {
117
+ invalid_state_error(
118
+ __FILE__, __LINE__, "bitmap and texture modifications conflicted");
119
+ }
120
+ else
121
+ {
122
+ PRINT_MODIFIED_FLAGS("bitmap from texture");
123
+ self->bitmap = Bitmap_from(self->texture);
124
+ clear_modified_flags(image);
125
+ }
97
126
  }
98
127
 
99
128
  return self->bitmap;
@@ -115,9 +144,13 @@ namespace Rays
115
144
  if (!self->texture)
116
145
  {
117
146
  if (self->bitmap)
147
+ {
148
+ PRINT_MODIFIED_FLAGS("new texture from bitmap");
118
149
  self->texture = Texture(self->bitmap);
150
+ }
119
151
  else
120
152
  {
153
+ PRINT_MODIFIED_FLAGS("new texture");
121
154
  self->texture = Texture(self->width, self->height, self->color_space);
122
155
 
123
156
  Painter p = image.painter();
@@ -127,13 +160,19 @@ namespace Rays
127
160
  }
128
161
  clear_modified_flags(&image);
129
162
  }
130
- else if (
131
- self->bitmap &&
132
- Bitmap_get_modified(self->bitmap) &&
133
- !self->texture.modified())
163
+ else if (self->bitmap && Bitmap_get_modified(self->bitmap))
134
164
  {
135
- self->texture = Texture(self->bitmap);
136
- clear_modified_flags(&image);
165
+ if (self->texture.modified())
166
+ {
167
+ invalid_state_error(
168
+ __FILE__, __LINE__, "texture and bitmap modifications conflicted");
169
+ }
170
+ else
171
+ {
172
+ PRINT_MODIFIED_FLAGS("texture from bitmap");
173
+ self->texture = self->bitmap;
174
+ clear_modified_flags(&image);
175
+ }
137
176
  }
138
177
 
139
178
  return self->texture;
@@ -232,15 +271,20 @@ namespace Rays
232
271
  }
233
272
 
234
273
  Bitmap&
235
- Image::bitmap ()
274
+ Image::bitmap (bool modify)
236
275
  {
276
+ if (modify)
277
+ {
278
+ if (!self->bitmap) get_bitmap(this);
279
+ Bitmap_set_modified(&self->bitmap);
280
+ }
237
281
  return get_bitmap(this);
238
282
  }
239
283
 
240
284
  const Bitmap&
241
285
  Image::bitmap () const
242
286
  {
243
- return get_bitmap(const_cast<Image*>(this));
287
+ return const_cast<Image*>(this)->bitmap();
244
288
  }
245
289
 
246
290
  Image::operator bool () const
data/src/ios/font.mm CHANGED
@@ -2,6 +2,7 @@
2
2
  #include "../font.h"
3
3
 
4
4
 
5
+ #include <memory>
5
6
  #import <CoreGraphics/CGContext.h>
6
7
  #import <CoreText/CoreText.h>
7
8
  #include "rays/exception.h"
@@ -12,15 +13,23 @@ namespace Rays
12
13
  {
13
14
 
14
15
 
16
+ typedef std::shared_ptr<const __CFDictionary> CFDictionaryPtr;
17
+
18
+ typedef std::shared_ptr<const __CFAttributedString> CFAttributedStringPtr;
19
+
20
+ typedef std::shared_ptr<CGDataProvider> CGDataProviderPtr;
21
+
22
+ typedef std::shared_ptr<CGFont> CGFontPtr;
23
+
24
+ typedef std::shared_ptr<const __CTLine> CTLinePtr;
25
+
26
+
15
27
  struct RawFont::Data
16
28
  {
17
29
 
18
- CTFontRef font;
30
+ CTFontRef font = NULL;
19
31
 
20
- Data ()
21
- : font(NULL)
22
- {
23
- }
32
+ String path;
24
33
 
25
34
  ~Data ()
26
35
  {
@@ -34,7 +43,7 @@ namespace Rays
34
43
  };// RawFont::Data
35
44
 
36
45
 
37
- static CTLineRef
46
+ static CTLinePtr
38
47
  make_line (CTFontRef font, const char* str)
39
48
  {
40
49
  if (!font || !str || *str == '\0')
@@ -50,18 +59,65 @@ namespace Rays
50
59
  };
51
60
  size_t nkeys = sizeof(keys) / sizeof(keys[0]);
52
61
 
53
- CFDictionaryRef attr = CFDictionaryCreate(
54
- NULL, (const void**) &keys, (const void**) &values, nkeys,
55
- &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
62
+ CFDictionaryPtr attr(
63
+ CFDictionaryCreate(
64
+ NULL, (const void**) &keys, (const void**) &values, nkeys,
65
+ &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks),
66
+ CFRelease);
56
67
 
57
- CFAttributedStringRef attrstr = CFAttributedStringCreate(
58
- NULL, cfstring(str).get(), attr);
59
- CFRelease(attr);
68
+ CFAttributedStringPtr attrstr(
69
+ CFAttributedStringCreate(NULL, cfstring(str).get(), attr.get()),
70
+ CFRelease);
60
71
 
61
- CTLineRef line = CTLineCreateWithAttributedString(attrstr);
62
- CFRelease(attrstr);
72
+ return CTLinePtr(
73
+ CTLineCreateWithAttributedString(attrstr.get()),
74
+ CFRelease);
75
+ }
63
76
 
64
- return line;
77
+ const FontFamilyMap&
78
+ get_font_families ()
79
+ {
80
+ static const FontFamilyMap MAP = []() {
81
+ FontFamilyMap map;
82
+ for (NSString* family in UIFont.familyNames)
83
+ {
84
+ FontFamilyMap::mapped_type array;
85
+ for (NSString* name in [UIFont fontNamesForFamilyName: family])
86
+ array.emplace_back(name.UTF8String);
87
+ map[family.UTF8String] = array;
88
+ }
89
+ return map;
90
+ }();
91
+ return MAP;
92
+ }
93
+
94
+ RawFont
95
+ RawFont_load (const char* path, coord size)
96
+ {
97
+ if (!path)
98
+ argument_error(__FILE__, __LINE__);
99
+
100
+ CGDataProviderPtr data_provider(
101
+ CGDataProviderCreateWithFilename(path),
102
+ CGDataProviderRelease);
103
+ if (!data_provider)
104
+ rays_error(__FILE__, __LINE__, "failed to create CGDataProvider");
105
+
106
+ CGFontPtr cgfont(
107
+ CGFontCreateWithDataProvider(data_provider.get()),
108
+ CGFontRelease);
109
+ if (!cgfont)
110
+ rays_error(__FILE__, __LINE__, "failed to create CGFont");
111
+
112
+ CTFontRef ctfont = CTFontCreateWithGraphicsFont(
113
+ cgfont.get(), size, NULL, NULL);
114
+ if (!ctfont)
115
+ rays_error(__FILE__, __LINE__, "failed to create CTFont");
116
+
117
+ RawFont rawfont;
118
+ rawfont.self->font = ctfont;
119
+ rawfont.self->path = path;
120
+ return rawfont;
65
121
  }
66
122
 
67
123
 
@@ -76,6 +132,15 @@ namespace Rays
76
132
  : CTFontCreateUIFontForLanguage(kCTFontSystemFontType, size, NULL);
77
133
  }
78
134
 
135
+ RawFont::RawFont (const This& obj, coord size)
136
+ {
137
+ const char* path = obj.self->path.empty() ? NULL : obj.self->path.c_str();
138
+ if (path)
139
+ *this = RawFont_load(path, size);
140
+ else
141
+ self->font = CTFontCreateWithName(cfstring(obj.name()).get(), size, NULL);
142
+ }
143
+
79
144
  RawFont::~RawFont ()
80
145
  {
81
146
  }
@@ -92,15 +157,13 @@ namespace Rays
92
157
 
93
158
  if (*str == '\0') return;
94
159
 
95
- CTLineRef line = make_line(self->font, str);
160
+ CTLinePtr line = make_line(self->font, str);
96
161
  if (!line)
97
162
  rays_error(__FILE__, __LINE__, "creating CTLineRef failed.");
98
163
 
99
- coord width = 0, height = 0, ascent = 0;
100
- width = get_width(str);
101
- height = get_height(&ascent);
102
-
103
- height = ceil(height);
164
+ coord width, height, ascent = 0;
165
+ width = ceil(get_width(str));
166
+ height = ceil(get_height(&ascent));
104
167
  ascent = floor(ascent);
105
168
 
106
169
  CGRect rect = CGRectMake(x, context_height - height - y, width, height);
@@ -112,10 +175,8 @@ namespace Rays
112
175
  CGContextSaveGState(context);
113
176
  CGContextSetTextMatrix(context, CGAffineTransformIdentity);
114
177
  CGContextSetTextPosition(context, x, context_height - ascent - y);
115
- CTLineDraw(line, context);
178
+ CTLineDraw(line.get(), context);
116
179
  CGContextRestoreGState(context);
117
-
118
- CFRelease(line);
119
180
  }
120
181
 
121
182
  String
@@ -123,14 +184,13 @@ namespace Rays
123
184
  {
124
185
  if (!*this) return "";
125
186
 
126
- CFStringRef str = CTFontCopyFullName(self->font);
187
+ CFStringPtr str(CTFontCopyFullName(self->font), CFRelease);
127
188
 
128
189
  enum {BUFSIZE = 2048};
129
190
  char buf[BUFSIZE + 1];
130
- if (!CFStringGetCString(str, buf, BUFSIZE, kCFStringEncodingUTF8))
191
+ if (!CFStringGetCString(str.get(), buf, BUFSIZE, kCFStringEncodingUTF8))
131
192
  buf[0] = '\0';
132
193
 
133
- CFRelease(str);
134
194
  return buf;
135
195
  }
136
196
 
@@ -152,14 +212,11 @@ namespace Rays
152
212
 
153
213
  if (*str == '\0') return 0;
154
214
 
155
- CTLineRef line = make_line(self->font, str);
215
+ CTLinePtr line = make_line(self->font, str);
156
216
  if (!line)
157
217
  rays_error(__FILE__, __LINE__, "creating CTLineRef failed.");
158
218
 
159
- coord w = CTLineGetTypographicBounds(line, NULL, NULL, NULL);
160
- CFRelease(line);
161
-
162
- return w;
219
+ return CTLineGetTypographicBounds(line.get(), NULL, NULL, NULL);
163
220
  }
164
221
 
165
222
  coord