rubyquartz 0.1.2

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 (96) hide show
  1. data/COPYRIGHT +24 -0
  2. data/History.txt +9 -0
  3. data/Manifest.txt +95 -0
  4. data/README.txt +71 -0
  5. data/Rakefile +51 -0
  6. data/ext/ExportedSymbols.txt +1 -0
  7. data/ext/bitmap.c +129 -0
  8. data/ext/bitmap.h +38 -0
  9. data/ext/bitmap_context.c +67 -0
  10. data/ext/bitmap_context.h +31 -0
  11. data/ext/color.c +145 -0
  12. data/ext/color.h +34 -0
  13. data/ext/colorspace.c +94 -0
  14. data/ext/colorspace.h +33 -0
  15. data/ext/context.c +393 -0
  16. data/ext/context.h +33 -0
  17. data/ext/extconf.rb +48 -0
  18. data/ext/font.c +148 -0
  19. data/ext/font.h +32 -0
  20. data/ext/function.c +124 -0
  21. data/ext/function.h +32 -0
  22. data/ext/image.c +140 -0
  23. data/ext/image.h +31 -0
  24. data/ext/image_source.c +143 -0
  25. data/ext/image_source.h +31 -0
  26. data/ext/pdf_document.c +91 -0
  27. data/ext/pdf_document.h +31 -0
  28. data/ext/pdf_page.c +79 -0
  29. data/ext/pdf_page.h +31 -0
  30. data/ext/point.c +42 -0
  31. data/ext/point.h +32 -0
  32. data/ext/rect.c +45 -0
  33. data/ext/rect.h +32 -0
  34. data/ext/rubyquartz.c +80 -0
  35. data/ext/rubyquartz.h +29 -0
  36. data/ext/rubyquartz_prefix.h +45 -0
  37. data/ext/shading.c +68 -0
  38. data/ext/shading.h +32 -0
  39. data/ext/size.c +42 -0
  40. data/ext/size.h +32 -0
  41. data/ext/text.c +258 -0
  42. data/ext/text.h +39 -0
  43. data/ext/utilities.c +181 -0
  44. data/ext/utilities.h +43 -0
  45. data/lib/rubyquartz.rb +59 -0
  46. data/lib/rubyquartz/bitmap.rb +62 -0
  47. data/lib/rubyquartz/bitmap_context.rb +50 -0
  48. data/lib/rubyquartz/color.rb +68 -0
  49. data/lib/rubyquartz/colorspace.rb +42 -0
  50. data/lib/rubyquartz/context.rb +116 -0
  51. data/lib/rubyquartz/font.rb +48 -0
  52. data/lib/rubyquartz/function.rb +57 -0
  53. data/lib/rubyquartz/image.rb +48 -0
  54. data/lib/rubyquartz/image_source.rb +50 -0
  55. data/lib/rubyquartz/pdf_document.rb +47 -0
  56. data/lib/rubyquartz/pdf_page.rb +54 -0
  57. data/lib/rubyquartz/point.rb +63 -0
  58. data/lib/rubyquartz/rect.rb +127 -0
  59. data/lib/rubyquartz/shading.rb +48 -0
  60. data/lib/rubyquartz/size.rb +39 -0
  61. data/lib/rubyquartz/text.rb +50 -0
  62. data/test/images/TestContext.test_begin_path.png +0 -0
  63. data/test/images/TestContext.test_draw_image.png +0 -0
  64. data/test/images/TestContext.test_draw_path.png +0 -0
  65. data/test/images/TestContext.test_draw_pdf.png +0 -0
  66. data/test/images/TestContext.test_draw_shading_axial.png +0 -0
  67. data/test/images/TestContext.test_draw_text.png +0 -0
  68. data/test/images/TestContext.test_draw_text_baseline_aligned.png +0 -0
  69. data/test/images/TestContext.test_draw_text_flipped.png +0 -0
  70. data/test/images/TestContext.test_draw_text_flipped_non_zero_point.png +0 -0
  71. data/test/images/TestContext.test_draw_text_non_zero_point.png +0 -0
  72. data/test/images/TestContext.test_fill.png +0 -0
  73. data/test/images/TestContext.test_gsave.png +0 -0
  74. data/test/images/TestContext.test_gsave_block.png +0 -0
  75. data/test/images/TestContext.test_line_width.png +0 -0
  76. data/test/images/TestContext.test_lineto.png +0 -0
  77. data/test/images/TestContext.test_rotate.png +0 -0
  78. data/test/images/TestContext.test_rounded_rect.png +0 -0
  79. data/test/images/TestContext.test_scale.png +0 -0
  80. data/test/images/TestContext.test_set_line_dash.png +0 -0
  81. data/test/images/TestContext.test_shadow.png +0 -0
  82. data/test/images/TestContext.test_stroke_rect.png +0 -0
  83. data/test/images/TestContext.test_text_bounds.png +0 -0
  84. data/test/images/TestContext.test_translate.png +0 -0
  85. data/test/inputs/circle.pdf +0 -0
  86. data/test/inputs/wash.png +0 -0
  87. data/test/rubyquartz_test.rb +51 -0
  88. data/test/tc_bitmap_context.rb +43 -0
  89. data/test/tc_color.rb +43 -0
  90. data/test/tc_context.rb +315 -0
  91. data/test/tc_font.rb +54 -0
  92. data/test/tc_image_source.rb +69 -0
  93. data/test/tc_pdf_document.rb +63 -0
  94. data/test/tc_pdf_page.rb +53 -0
  95. data/test/tc_text.rb +39 -0
  96. metadata +156 -0
data/ext/text.c ADDED
@@ -0,0 +1,258 @@
1
+ /*
2
+ * Copyright (c) 2006, The Omni Group. All rights reserved.
3
+ *
4
+ * Redistribution and use in source and binary forms, with or without
5
+ * modification, are permitted provided that the following conditions
6
+ * are met:
7
+ * 1. Redistributions of source code must retain the above copyright
8
+ * notice, this list of conditions and the following disclaimer.
9
+ * 2. Redistributions in binary form must reproduce the above copyright
10
+ * notice, this list of conditions and the following disclaimer in the
11
+ * documentation and/or other materials provided with the distribution.
12
+ * 3. Neither the name of The Omni Group ("Omni") nor the names of
13
+ * its contributors may be used to endorse or promote products derived
14
+ * from this software without specific prior written permission.
15
+ *
16
+ * THIS SOFTWARE IS PROVIDED BY OMNI AND ITS CONTRIBUTORS "AS IS" AND
17
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
+ * ARE DISCLAIMED. IN NO EVENT SHALL OMNI OR ITS CONTRIBUTORS BE LIABLE FOR
20
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26
+ * POSSIBILITY OF SUCH DAMAGE.
27
+ */
28
+
29
+ #include "text.h"
30
+
31
+ #include "font.h"
32
+ #include "color.h"
33
+
34
+ #import <Cocoa/Cocoa.h>
35
+
36
+ VALUE text_class;
37
+
38
+ static void _text_clear(Text *text)
39
+ {
40
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
41
+ @try {
42
+ [text->storage removeLayoutManager:text->layoutManager];
43
+ [text->storage release];
44
+ text->storage = nil;
45
+
46
+ [text->container release];
47
+ text->container = nil;
48
+
49
+ [text->layoutManager release];
50
+ text->layoutManager = nil;
51
+ } @catch (NSException *exc) {
52
+ NSLog(@"%s -- %@", __PRETTY_FUNCTION__, exc);
53
+ } @finally {
54
+ [pool release];
55
+ }
56
+ }
57
+
58
+ Text *text_get(VALUE self)
59
+ {
60
+ // TODO: Subclassability?
61
+ if (CLASS_OF(self) != text_class)
62
+ rb_raise(rb_eArgError, "Argument must be a Text");
63
+
64
+ Text *text;
65
+ Data_Get_Struct(self, Text, text);
66
+
67
+ if (!text)
68
+ rb_raise(rb_eArgError, "No data specified for Text!");
69
+
70
+ return text;
71
+ }
72
+
73
+ static void _text_free(Text *text)
74
+ {
75
+ if (text) {
76
+ _text_clear(text);
77
+ free(text);
78
+ }
79
+ }
80
+
81
+ static VALUE _text_alloc(VALUE klass)
82
+ {
83
+ Text *text = calloc(1, sizeof(*text));
84
+ return Data_Wrap_Struct(klass, NULL, _text_free, text);
85
+ }
86
+
87
+ VALUE text_initialize(VALUE self, VALUE string, VALUE font, VALUE color, VALUE alignment)
88
+ {
89
+ Text *text = text_get(self);
90
+ NSFont *f = NIL_P(font) ? nil : font_get(font);
91
+ CGColorRef c = NIL_P(color) ? nil : color_get(color);
92
+ CFStringRef str = _copy_string_for_str(string);
93
+ NSTextAlignment align = NUM2UINT(alignment);
94
+
95
+ // Should already be clear...
96
+ _text_clear(text);
97
+
98
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
99
+ @try {
100
+ NSMutableDictionary *attributes = [[NSMutableDictionary alloc] init];
101
+ if (f)
102
+ [attributes setObject:f forKey:NSFontAttributeName];
103
+ if (c) {
104
+ NSColor *wrapper = color_create_wrapper(c);
105
+ [attributes setObject:wrapper forKey:NSForegroundColorAttributeName]; // TODO: Are CGColorRef and NSColor bridged?
106
+ [wrapper release];
107
+ }
108
+
109
+ NSMutableParagraphStyle *pgStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
110
+ [pgStyle setAlignment:align];
111
+ [attributes setObject:pgStyle forKey:NSParagraphStyleAttributeName];
112
+ [pgStyle release];
113
+
114
+ text->layoutManager = [[NSLayoutManager alloc] init];
115
+ [text->layoutManager setBackgroundLayoutEnabled:NO];
116
+
117
+ text->container = [[NSTextContainer alloc] initWithContainerSize:NSMakeSize(1e9, 1e9)]; // TODO: Warn if you try to draw with an 'infinite' width using center or right alignment?
118
+ [text->container setLineFragmentPadding:0.0f];
119
+
120
+ [text->layoutManager addTextContainer:text->container];
121
+
122
+ text->storage = [[NSTextStorage alloc] initWithString:(NSString *)str attributes:attributes];
123
+ [attributes release];
124
+
125
+ [text->storage addLayoutManager:text->layoutManager];
126
+
127
+ return self;
128
+ } @catch (NSException *exc) {
129
+ NSLog(@"%s -- %@", __PRETTY_FUNCTION__, exc);
130
+ } @finally {
131
+ [pool release];
132
+ }
133
+ rb_raise(rb_eArgError, "Unable to create Text");
134
+ }
135
+
136
+ static VALUE text_layout_width(VALUE self)
137
+ {
138
+ Text *text = text_get(self);
139
+ return rb_float_new([text->container containerSize].width);
140
+ }
141
+
142
+ static VALUE text_set_layout_width(VALUE self, VALUE width)
143
+ {
144
+ Text *text = text_get(self);
145
+ NSSize size = [text->container containerSize];
146
+ size.width = NUM2DBL(width);
147
+ [text->container setContainerSize:size];
148
+ return self;
149
+ }
150
+
151
+ static VALUE text_height_used(VALUE self)
152
+ {
153
+ Text *text = text_get(self);
154
+
155
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
156
+ @try {
157
+ NSLayoutManager *layoutManager = text->layoutManager;
158
+
159
+ float totalHeight = 0.0;
160
+ unsigned int glyphCount = [layoutManager numberOfGlyphs];
161
+ if (glyphCount > 0) {
162
+ // forces layout
163
+ [layoutManager lineFragmentRectForGlyphAtIndex:glyphCount-1 effectiveRange:NULL];
164
+
165
+ NSTextContainer *textContainer;
166
+ NSArray *textContainers = [layoutManager textContainers];
167
+ unsigned int tcIndex, tcCount = [textContainers count];
168
+ for (tcIndex = 0; tcIndex < tcCount - 1; tcIndex++) {
169
+ textContainer = [textContainers objectAtIndex:tcIndex];
170
+ NSSize containerSize = [textContainer containerSize];
171
+ totalHeight += containerSize.height;
172
+ }
173
+
174
+ textContainer = [textContainers lastObject];
175
+ NSRect usedRect = [layoutManager usedRectForTextContainer:textContainer];
176
+ totalHeight += usedRect.size.height;
177
+ }
178
+ return rb_float_new(totalHeight);
179
+ } @catch (NSException *exc) {
180
+ NSLog(@"%s -- %@", __PRETTY_FUNCTION__, exc);
181
+ } @finally {
182
+ [pool release];
183
+ }
184
+ rb_raise(rb_eException, "Unable to determine text height");
185
+ return self;
186
+ }
187
+
188
+ static VALUE text_width_used(VALUE self)
189
+ {
190
+ Text *text = text_get(self);
191
+ NSTextStorage *textStorage = text->storage;
192
+ NSLayoutManager *layoutManager = text->layoutManager;
193
+
194
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
195
+ @try {
196
+ float maximumLineLength = 0.0f;
197
+ unsigned int characterCount = [textStorage length];
198
+ if (characterCount > 0) {
199
+ NSRange glyphRange = [layoutManager glyphRangeForCharacterRange:(NSRange){0, characterCount} actualCharacterRange:NULL];
200
+ if (glyphRange.length > 0) {
201
+ unsigned int glyphLocation = glyphRange.location;
202
+ unsigned int glyphEnd = glyphRange.location + glyphRange.length;
203
+
204
+ while (glyphLocation < glyphEnd) {
205
+ // The line fragment rect isn't what we want (if text is right aligned, it will span the width of the line from the left edge of the text container). We want the glyph bounds...
206
+ NSRange lineGlyphRange;
207
+ [layoutManager lineFragmentRectForGlyphAtIndex:glyphLocation effectiveRange:&lineGlyphRange];
208
+
209
+ // Look at the last character of the given line. If it is a line breaking character, don't include it in the measurements. Otherwise, the glyph bounds will extend to the end of the text container.
210
+ NSRange lineCharRange = [layoutManager characterRangeForGlyphRange:lineGlyphRange actualGlyphRange:NULL];
211
+ NSRange clippedGlyphRange = lineGlyphRange;
212
+ if (lineCharRange.length) {
213
+ unichar c = [[textStorage string] characterAtIndex:lineCharRange.location + lineCharRange.length - 1];
214
+ if (c == '\n' || c == '\r') { // Other Unicode newline characters?
215
+ // Shorten the character range and get the new glyph range
216
+ lineCharRange.length--;
217
+ clippedGlyphRange = [layoutManager glyphRangeForCharacterRange:lineCharRange actualCharacterRange:NULL];
218
+ }
219
+ }
220
+ if (!clippedGlyphRange.length) {
221
+ // Only a newline in this line; still need the update to glyphLocation below, though or we hang as in #20274
222
+ } else {
223
+ NSTextContainer *container = [layoutManager textContainerForGlyphAtIndex:glyphLocation effectiveRange:NULL];
224
+
225
+ NSRect glyphBounds = [layoutManager boundingRectForGlyphRange:clippedGlyphRange inTextContainer:container];
226
+
227
+ //NSLog(@"glyphRange = %@, lineFrag = %@, glyphBounds = %@", NSStringFromRange(clippedGlyphRange), NSStringFromRect(lineFrag), NSStringFromRect(glyphBounds));
228
+
229
+ maximumLineLength = MAX(glyphBounds.size.width, maximumLineLength);
230
+ }
231
+
232
+ // Step by the unclipped glyph range or we'll go into an infinite loop when we chop off a newline
233
+ glyphLocation = lineGlyphRange.location + lineGlyphRange.length;
234
+ }
235
+ }
236
+ }
237
+
238
+ return rb_float_new(maximumLineLength);
239
+ } @catch (NSException *exc) {
240
+ NSLog(@"%s -- %@", __PRETTY_FUNCTION__, exc);
241
+ } @finally {
242
+ [pool release];
243
+ }
244
+ rb_raise(rb_eException, "Unable to determine text width");
245
+ return self;
246
+ }
247
+
248
+ void Init_text(void)
249
+ {
250
+ text_class = rb_define_class_under(module, "Text", rb_cObject);
251
+ rb_define_alloc_func(text_class, _text_alloc);
252
+
253
+ rb_define_private_method(text_class, "_initialize", text_initialize, 4);
254
+ rb_define_method(text_class, "layout_width", text_layout_width, 0);
255
+ rb_define_method(text_class, "layout_width=", text_set_layout_width, 1);
256
+ rb_define_method(text_class, "height_used", text_height_used, 0);
257
+ rb_define_method(text_class, "width_used", text_width_used, 0);
258
+ }
data/ext/text.h ADDED
@@ -0,0 +1,39 @@
1
+ /*
2
+ Copyright (c) 2006, The Omni Group, Inc. All rights reserved.
3
+
4
+ OPEN PERMISSION TO USE AND REPRODUCE OMNI SOURCE CODE SOFTWARE
5
+
6
+ Omni Source Code software is available from The Omni Group on their web
7
+ site at www.omnigroup.com.
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a
10
+ copy of this software and associated documentation files (the "Software"),
11
+ to deal in the Software without restriction, including without limitation
12
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
13
+ and/or sell copies of the Software, and to permit persons to whom the
14
+ Software is furnished to do so, subject to the following conditions:
15
+
16
+ Any original copyright notices and this permission notice shall be included
17
+ in all copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25
+ DEALINGS IN THE SOFTWARE.
26
+ */
27
+
28
+
29
+ @class NSTextStorage, NSTextContainer, NSLayoutManager;
30
+
31
+ typedef struct {
32
+ NSTextStorage *storage;
33
+ NSTextContainer *container;
34
+ NSLayoutManager *layoutManager;
35
+ } Text;
36
+
37
+ extern void Init_text(void);
38
+ extern VALUE text_class;
39
+ extern Text *text_get(VALUE self);
data/ext/utilities.c ADDED
@@ -0,0 +1,181 @@
1
+ /*
2
+ Copyright (c) 2006, The Omni Group, Inc. All rights reserved.
3
+
4
+ OPEN PERMISSION TO USE AND REPRODUCE OMNI SOURCE CODE SOFTWARE
5
+
6
+ Omni Source Code software is available from The Omni Group on their web
7
+ site at www.omnigroup.com.
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a
10
+ copy of this software and associated documentation files (the "Software"),
11
+ to deal in the Software without restriction, including without limitation
12
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
13
+ and/or sell copies of the Software, and to permit persons to whom the
14
+ Software is furnished to do so, subject to the following conditions:
15
+
16
+ Any original copyright notices and this permission notice shall be included
17
+ in all copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25
+ DEALINGS IN THE SOFTWARE.
26
+ */
27
+
28
+
29
+ #include "utilities.h"
30
+
31
+ #import <Foundation/NSObject.h>
32
+ #import <objc/objc-runtime.h>
33
+
34
+ VALUE _symbol_for_string(CFStringRef str)
35
+ {
36
+ CFDataRef utf8 = CFStringCreateExternalRepresentation(kCFAllocatorDefault, str, kCFStringEncodingUTF8, '?');
37
+ CFIndex utf8Length = CFDataGetLength(utf8);
38
+ char *utf8Bytes = malloc(utf8Length + 1);
39
+ memcpy(utf8Bytes, CFDataGetBytePtr(utf8) , utf8Length);
40
+ utf8Bytes[utf8Length] = '\0';
41
+ CFRelease(utf8);
42
+
43
+ VALUE symbol = ID2SYM(rb_intern(utf8Bytes));
44
+ free(utf8Bytes);
45
+
46
+ return symbol;
47
+ }
48
+
49
+ CFStringRef _copy_string_for_str(VALUE str)
50
+ {
51
+ // TODO: Unicode?
52
+ const unsigned char *s = (const unsigned char *)StringValueCStr(str);
53
+ return CFStringCreateWithBytes(kCFAllocatorDefault, s, strlen((const char *)s), kCFStringEncodingUTF8, false/*isExternalRepresentation*/);
54
+ }
55
+
56
+ VALUE _value_for_string(CFStringRef str)
57
+ {
58
+ // TODO: Unicode?
59
+ // TODO: Check for conversion failure and raise
60
+ CFDataRef data = CFStringCreateExternalRepresentation(kCFAllocatorDefault, str, kCFStringEncodingUTF8, 0);
61
+
62
+ VALUE value = rb_str_new((char *)CFDataGetBytePtr(data), CFDataGetLength(data));
63
+
64
+ if (data)
65
+ CFRelease(data);
66
+
67
+ return value;
68
+ }
69
+
70
+ CFURLRef _create_url_for_path(VALUE path)
71
+ {
72
+ const char *pathCString = StringValueCStr(path); // checks type
73
+
74
+ // TODO: Test non-ASCII path
75
+ CFStringRef pathString = CFStringCreateWithCString(kCFAllocatorDefault, pathCString, kCFStringEncodingUTF8);
76
+ CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, pathString, kCFURLPOSIXPathStyle, false/*isDirectory*/);
77
+ CFRelease(pathString);
78
+
79
+ if (!url)
80
+ rb_raise(rb_eException, "Unable to create URL from given path");
81
+ return url;
82
+ }
83
+
84
+ CFDataRef _create_data_from_string(VALUE value, Boolean copy)
85
+ {
86
+ value = rb_str_to_str(value);
87
+ struct RString *str = RSTRING(value);
88
+
89
+ if (copy)
90
+ return CFDataCreate(kCFAllocatorDefault, (const UInt8 *)str->ptr, str->len);
91
+ else
92
+ return CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)str->ptr, str->len, NULL);
93
+ }
94
+
95
+ // Common alloc/free handlers for CFType-wrapping classes
96
+ static void _cftype_free(CFTypeRef *cf)
97
+ {
98
+ if (cf) {
99
+ if (*cf)
100
+ CFRelease(*cf);
101
+ free(cf);
102
+ }
103
+ }
104
+
105
+ VALUE _cftype_alloc(VALUE klass)
106
+ {
107
+ CFTypeRef *cf = calloc(1, sizeof(*cf));
108
+ return Data_Wrap_Struct(klass, NULL, _cftype_free, cf);
109
+ }
110
+
111
+ // Doesn't allow NULL to be returned since callers depend on this for ease of use
112
+ CFTypeRef _cftype_get(VALUE self, CFTypeID typeID, const char *typeName)
113
+ {
114
+ CFTypeRef *cf;
115
+ Data_Get_Struct(self, CFTypeRef, cf);
116
+
117
+ if (!cf)
118
+ rb_raise(rb_eArgError, "No data specified for CFType holder!");
119
+
120
+ CFTypeRef result = *cf;
121
+ if (!result)
122
+ rb_raise(rb_eArgError, "No %s wrapped in %s", typeName, rb_obj_classname(self));
123
+
124
+ if (CFGetTypeID(result) != typeID)
125
+ rb_raise(rb_eArgError, "%s is wrapping something other than a %s, type id is %d but should be %d", rb_obj_classname(self), typeName, CFGetTypeID(result), typeID);
126
+ return result;
127
+ }
128
+
129
+ void _cftype_set(VALUE self, CFTypeID typeID, const char *typeName, CFTypeRef value)
130
+ {
131
+ if (value && (CFGetTypeID(value) != typeID))
132
+ rb_raise(rb_eArgError, "Attempt to set a non-%s value on a %s, type id is %d but should be %d", typeName, rb_obj_classname(self), CFGetTypeID(value), typeID);
133
+
134
+ CFTypeRef *cf;
135
+ Data_Get_Struct(self, CFTypeRef, cf);
136
+
137
+ if (!cf)
138
+ rb_raise(rb_eArgError, "No data specified for CFType holder!");
139
+
140
+ if (*cf)
141
+ CFRelease(*cf);
142
+ *cf = value;
143
+ if (value)
144
+ CFRetain(value);
145
+ }
146
+
147
+ // Doesn't allow nil to be returned since callers depend on this for ease of use
148
+ id _objc_type_get(VALUE self, Class cls)
149
+ {
150
+ id *obj;
151
+ Data_Get_Struct(self, id, obj);
152
+
153
+ if (!obj)
154
+ rb_raise(rb_eArgError, "No data specified for object holder!");
155
+
156
+ id result = *obj;
157
+ if (!result)
158
+ rb_raise(rb_eArgError, "No %s wrapped in %s", cls->name, rb_obj_classname(self));
159
+
160
+ if (![result isKindOfClass:cls])
161
+ rb_raise(rb_eArgError, "%s is wrapping something other than a %s", rb_obj_classname(self), cls->name);
162
+ return result;
163
+ }
164
+
165
+ void _objc_type_set(VALUE self, Class cls, id value)
166
+ {
167
+ if (value && ![value isKindOfClass:cls])
168
+ rb_raise(rb_eArgError, "Attempt to set a non-%s value on a %s", cls->name, rb_obj_classname(self));
169
+
170
+ id *obj;
171
+ Data_Get_Struct(self, id, obj);
172
+
173
+ if (!obj)
174
+ rb_raise(rb_eArgError, "No data specified for object holder!");
175
+
176
+ if (*obj)
177
+ [*obj release];
178
+ *obj = value;
179
+ if (value)
180
+ [value retain];
181
+ }