rays 0.1.47 → 0.1.49

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