skia 1.0.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +12 -0
- data/LICENSE +21 -0
- data/README.md +205 -0
- data/Rakefile +8 -0
- data/examples/advanced_features.rb +50 -0
- data/examples/avatar_generator.rb +74 -0
- data/examples/bar_chart.rb +89 -0
- data/examples/basic_drawing.rb +43 -0
- data/examples/gradient.rb +32 -0
- data/examples/pdf_output.rb +48 -0
- data/examples/pdf_stream.rb +23 -0
- data/examples/picture_recording.rb +62 -0
- data/examples/progress_gauge.rb +103 -0
- data/examples/runtime_effect.rb +26 -0
- data/examples/social_card.rb +121 -0
- data/examples/text_drawing.rb +40 -0
- data/lib/skia/base.rb +40 -0
- data/lib/skia/bitmap.rb +140 -0
- data/lib/skia/canvas.rb +239 -0
- data/lib/skia/color.rb +82 -0
- data/lib/skia/color_filter.rb +23 -0
- data/lib/skia/color_space.rb +44 -0
- data/lib/skia/data.rb +47 -0
- data/lib/skia/document.rb +222 -0
- data/lib/skia/font.rb +118 -0
- data/lib/skia/image.rb +216 -0
- data/lib/skia/image_filter.rb +29 -0
- data/lib/skia/image_info.rb +59 -0
- data/lib/skia/mask_filter.rb +26 -0
- data/lib/skia/matrix.rb +163 -0
- data/lib/skia/native/callbacks.rb +6 -0
- data/lib/skia/native/functions.rb +384 -0
- data/lib/skia/native/types.rb +400 -0
- data/lib/skia/native.rb +67 -0
- data/lib/skia/paint.rb +144 -0
- data/lib/skia/path.rb +166 -0
- data/lib/skia/path_effect.rb +30 -0
- data/lib/skia/picture.rb +120 -0
- data/lib/skia/pixmap.rb +109 -0
- data/lib/skia/point.rb +94 -0
- data/lib/skia/rect.rb +179 -0
- data/lib/skia/rrect.rb +139 -0
- data/lib/skia/runtime_effect.rb +88 -0
- data/lib/skia/shader.rb +145 -0
- data/lib/skia/surface.rb +272 -0
- data/lib/skia/text_blob.rb +47 -0
- data/lib/skia/typeface.rb +175 -0
- data/lib/skia/version.rb +5 -0
- data/lib/skia.rb +42 -0
- data/skia-ruby.gemspec +30 -0
- metadata +107 -0
data/lib/skia/path.rb
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Skia
|
|
4
|
+
class Path < Base
|
|
5
|
+
def initialize(ptr = nil)
|
|
6
|
+
super(ptr || Native.sk_path_new, :sk_path_delete)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def self.build(&block)
|
|
10
|
+
path = new
|
|
11
|
+
path.instance_eval(&block) if block
|
|
12
|
+
path
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def move_to(x, y)
|
|
16
|
+
Native.sk_path_move_to(@ptr, x.to_f, y.to_f)
|
|
17
|
+
self
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def line_to(x, y)
|
|
21
|
+
Native.sk_path_line_to(@ptr, x.to_f, y.to_f)
|
|
22
|
+
self
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def quad_to(x1, y1, x2, y2)
|
|
26
|
+
Native.sk_path_quad_to(@ptr, x1.to_f, y1.to_f, x2.to_f, y2.to_f)
|
|
27
|
+
self
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def conic_to(x1, y1, x2, y2, weight)
|
|
31
|
+
Native.sk_path_conic_to(@ptr, x1.to_f, y1.to_f, x2.to_f, y2.to_f, weight.to_f)
|
|
32
|
+
self
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def cubic_to(x1, y1, x2, y2, x3, y3)
|
|
36
|
+
Native.sk_path_cubic_to(@ptr, x1.to_f, y1.to_f, x2.to_f, y2.to_f, x3.to_f, y3.to_f)
|
|
37
|
+
self
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def arc_to(rx, ry, x_axis_rotate, x, y)
|
|
41
|
+
Native.sk_path_arc_to(@ptr, rx.to_f, ry.to_f, x_axis_rotate.to_f, x.to_f, y.to_f)
|
|
42
|
+
self
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def arc_to_with_oval(oval, start_angle, sweep_angle, force_move_to = false)
|
|
46
|
+
rect_struct = oval.to_struct
|
|
47
|
+
Native.sk_path_arc_to_with_oval(@ptr, rect_struct, start_angle.to_f, sweep_angle.to_f, force_move_to)
|
|
48
|
+
self
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def close
|
|
52
|
+
Native.sk_path_close(@ptr)
|
|
53
|
+
self
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def add_rect(rect, direction = :cw)
|
|
57
|
+
rect_struct = rect.to_struct
|
|
58
|
+
Native.sk_path_add_rect(@ptr, rect_struct, direction)
|
|
59
|
+
self
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def add_rrect(rrect, direction = :cw)
|
|
63
|
+
Native.sk_path_add_rrect(@ptr, rrect.ptr, direction)
|
|
64
|
+
self
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def add_oval(rect, direction = :cw)
|
|
68
|
+
rect_struct = rect.to_struct
|
|
69
|
+
Native.sk_path_add_oval(@ptr, rect_struct, direction)
|
|
70
|
+
self
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def add_circle(cx, cy, radius, direction = :cw)
|
|
74
|
+
Native.sk_path_add_circle(@ptr, cx.to_f, cy.to_f, radius.to_f, direction)
|
|
75
|
+
self
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def add_arc(rect, start_angle, sweep_angle)
|
|
79
|
+
rect_struct = rect.to_struct
|
|
80
|
+
Native.sk_path_add_arc(@ptr, rect_struct, start_angle.to_f, sweep_angle.to_f)
|
|
81
|
+
self
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def add_path(other, extend_path: false)
|
|
85
|
+
mode = extend_path ? 1 : 0
|
|
86
|
+
Native.sk_path_add_path(@ptr, other.ptr, mode, 0)
|
|
87
|
+
self
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def add_path_offset(other, dx, dy, extend_path: false)
|
|
91
|
+
mode = extend_path ? 1 : 0
|
|
92
|
+
Native.sk_path_add_path_offset(@ptr, other.ptr, dx.to_f, dy.to_f, mode)
|
|
93
|
+
self
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def add_path_reverse(other)
|
|
97
|
+
Native.sk_path_add_path_reverse(@ptr, other.ptr)
|
|
98
|
+
self
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def add_path_matrix(other, matrix, extend_path: false)
|
|
102
|
+
mode = extend_path ? 1 : 0
|
|
103
|
+
matrix_struct = matrix.to_struct
|
|
104
|
+
Native.sk_path_add_path_matrix(@ptr, other.ptr, matrix_struct, mode)
|
|
105
|
+
self
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def fill_type
|
|
109
|
+
Native.sk_path_get_filltype(@ptr)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def fill_type=(value)
|
|
113
|
+
Native.sk_path_set_filltype(@ptr, value)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def bounds
|
|
117
|
+
rect_struct = Native::SKRect.new
|
|
118
|
+
Native.sk_path_get_bounds(@ptr, rect_struct)
|
|
119
|
+
Rect.from_struct(rect_struct)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def empty?
|
|
123
|
+
Native.sk_path_count_verbs(@ptr) == 0
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def count_points
|
|
127
|
+
Native.sk_path_count_points(@ptr)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def approximate_length(force_closed: false, res_scale: 1.0)
|
|
131
|
+
measure = Native.sk_pathmeasure_new_with_path(@ptr, force_closed, res_scale.to_f)
|
|
132
|
+
raise Error, 'Failed to create path measure' if measure.nil? || measure.null?
|
|
133
|
+
|
|
134
|
+
begin
|
|
135
|
+
Native.sk_pathmeasure_get_length(measure)
|
|
136
|
+
ensure
|
|
137
|
+
Native.sk_pathmeasure_destroy(measure)
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def contains?(x, y)
|
|
142
|
+
Native.sk_path_contains(@ptr, x.to_f, y.to_f)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def transform(matrix)
|
|
146
|
+
matrix_struct = matrix.to_struct
|
|
147
|
+
Native.sk_path_transform(@ptr, matrix_struct)
|
|
148
|
+
self
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def clone
|
|
152
|
+
self.class.new(Native.sk_path_clone(@ptr))
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def reverse
|
|
156
|
+
reversed = self.class.new
|
|
157
|
+
Native.sk_path_add_path_reverse(reversed.ptr, @ptr)
|
|
158
|
+
reversed
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def reset
|
|
162
|
+
Native.sk_path_reset(@ptr)
|
|
163
|
+
self
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Skia
|
|
4
|
+
class PathEffect < Base
|
|
5
|
+
def initialize(ptr)
|
|
6
|
+
super(ptr, :sk_path_effect_unref)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def self.wrap(ptr)
|
|
10
|
+
return nil if ptr.nil? || ptr.null?
|
|
11
|
+
|
|
12
|
+
new(ptr)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.dash(intervals, phase: 0.0)
|
|
16
|
+
unless intervals.is_a?(Array) && intervals.length >= 2
|
|
17
|
+
raise ArgumentError, 'intervals must be an array with at least 2 elements'
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
interval_values = intervals.map(&:to_f)
|
|
21
|
+
intervals_ptr = FFI::MemoryPointer.new(:float, interval_values.length)
|
|
22
|
+
intervals_ptr.write_array_of_float(interval_values)
|
|
23
|
+
|
|
24
|
+
ptr = Native.sk_path_effect_create_dash(intervals_ptr, interval_values.length, phase.to_f)
|
|
25
|
+
raise Error, 'Failed to create dash path effect' if ptr.nil? || ptr.null?
|
|
26
|
+
|
|
27
|
+
new(ptr)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
data/lib/skia/picture.rb
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Skia
|
|
4
|
+
class Picture < Base
|
|
5
|
+
def initialize(ptr)
|
|
6
|
+
super(ptr, :sk_picture_unref)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def self.from_data(data)
|
|
10
|
+
data_obj = data.is_a?(Data) ? data : Data.new(data)
|
|
11
|
+
ptr = Native.sk_picture_deserialize_from_data(data_obj.ptr)
|
|
12
|
+
raise Error, "Failed to deserialize picture" if ptr.nil? || ptr.null?
|
|
13
|
+
|
|
14
|
+
new(ptr)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.record(bounds, &block)
|
|
18
|
+
recorder = PictureRecorder.new
|
|
19
|
+
recorder.begin_recording(bounds, &block)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def unique_id
|
|
23
|
+
Native.sk_picture_get_unique_id(@ptr)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def cull_rect
|
|
27
|
+
rect_struct = Native::SKRect.new
|
|
28
|
+
Native.sk_picture_get_cull_rect(@ptr, rect_struct)
|
|
29
|
+
Rect.from_struct(rect_struct)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def playback(canvas)
|
|
33
|
+
Native.sk_picture_playback(@ptr, canvas.ptr)
|
|
34
|
+
self
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def serialize
|
|
38
|
+
data_ptr = Native.sk_picture_serialize_to_data(@ptr)
|
|
39
|
+
raise Error, "Failed to serialize picture" if data_ptr.nil? || data_ptr.null?
|
|
40
|
+
|
|
41
|
+
Data.new(data_ptr)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def approximate_op_count(nested: true)
|
|
45
|
+
Native.sk_picture_approximate_op_count(@ptr, nested)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def approximate_bytes_used
|
|
49
|
+
Native.sk_picture_approximate_bytes_used(@ptr)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def save(path)
|
|
53
|
+
data = serialize
|
|
54
|
+
File.binwrite(path, data.to_s)
|
|
55
|
+
self
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self.load(path)
|
|
59
|
+
data = Data.from_file(path)
|
|
60
|
+
from_data(data)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
class PictureRecorder
|
|
65
|
+
def initialize
|
|
66
|
+
@ptr = Native.sk_picture_recorder_new
|
|
67
|
+
raise Error, "Failed to create picture recorder" if @ptr.nil? || @ptr.null?
|
|
68
|
+
|
|
69
|
+
@recording = false
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def ptr
|
|
73
|
+
@ptr
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def begin_recording(bounds)
|
|
77
|
+
bounds_struct = bounds.to_struct
|
|
78
|
+
canvas_ptr = Native.sk_picture_recorder_begin_recording(@ptr, bounds_struct)
|
|
79
|
+
raise Error, "Failed to begin recording" if canvas_ptr.nil? || canvas_ptr.null?
|
|
80
|
+
|
|
81
|
+
@recording = true
|
|
82
|
+
canvas = Canvas.new(canvas_ptr)
|
|
83
|
+
|
|
84
|
+
if block_given?
|
|
85
|
+
yield canvas
|
|
86
|
+
end_recording
|
|
87
|
+
else
|
|
88
|
+
canvas
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def recording_canvas
|
|
93
|
+
return nil unless @recording
|
|
94
|
+
|
|
95
|
+
canvas_ptr = Native.sk_picture_get_recording_canvas(@ptr)
|
|
96
|
+
return nil if canvas_ptr.nil? || canvas_ptr.null?
|
|
97
|
+
|
|
98
|
+
Canvas.new(canvas_ptr)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def end_recording
|
|
102
|
+
return nil unless @recording
|
|
103
|
+
|
|
104
|
+
ptr = Native.sk_picture_recorder_end_recording(@ptr)
|
|
105
|
+
@recording = false
|
|
106
|
+
raise Error, "Failed to end recording" if ptr.nil? || ptr.null?
|
|
107
|
+
|
|
108
|
+
Picture.new(ptr)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def recording?
|
|
112
|
+
@recording
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def delete
|
|
116
|
+
Native.sk_picture_recorder_delete(@ptr) if @ptr
|
|
117
|
+
@ptr = nil
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
data/lib/skia/pixmap.rb
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Skia
|
|
4
|
+
class Pixmap < Base
|
|
5
|
+
def initialize(ptr = nil)
|
|
6
|
+
super(ptr || Native.sk_pixmap_new, :sk_pixmap_destructor)
|
|
7
|
+
@pixel_storage = nil
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def self.from_pixels(image_info, pixels, row_bytes: nil)
|
|
11
|
+
info = coerce_image_info(image_info)
|
|
12
|
+
bytes = pixels.is_a?(String) ? pixels.dup : pixels.pack('C*')
|
|
13
|
+
row_bytes ||= info.min_row_bytes
|
|
14
|
+
|
|
15
|
+
if bytes.bytesize < row_bytes * info.height
|
|
16
|
+
raise ArgumentError, "pixel buffer is too small: #{bytes.bytesize} bytes"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
storage = FFI::MemoryPointer.new(:uint8, bytes.bytesize)
|
|
20
|
+
storage.write_bytes(bytes)
|
|
21
|
+
|
|
22
|
+
ptr = Native.sk_pixmap_new_with_params(info.to_struct, storage, row_bytes)
|
|
23
|
+
raise Error, 'Failed to create pixmap from pixels' if ptr.nil? || ptr.null?
|
|
24
|
+
|
|
25
|
+
pixmap = new(ptr)
|
|
26
|
+
pixmap.instance_variable_set(:@pixel_storage, storage)
|
|
27
|
+
pixmap
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def info
|
|
31
|
+
info_struct = Native::SKImageInfo.new
|
|
32
|
+
Native.sk_pixmap_get_info(@ptr, info_struct)
|
|
33
|
+
ImageInfo.from_struct(info_struct)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def row_bytes
|
|
37
|
+
Native.sk_pixmap_get_row_bytes(@ptr)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def color_space
|
|
41
|
+
ColorSpace.wrap(Native.sk_pixmap_get_colorspace(@ptr), retain: true)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def color_space=(value)
|
|
45
|
+
unless value.nil? || value.is_a?(ColorSpace)
|
|
46
|
+
raise ArgumentError, 'color_space must be a Skia::ColorSpace or nil'
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
Native.sk_pixmap_set_colorspace(@ptr, value&.ptr)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def pixel_color(x, y)
|
|
53
|
+
Color.new(Native.sk_pixmap_get_pixel_color(@ptr, x.to_i, y.to_i))
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def opaque?
|
|
57
|
+
Native.sk_pixmap_compute_is_opaque(@ptr)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def writable_addr(x = nil, y = nil)
|
|
61
|
+
if x.nil? || y.nil?
|
|
62
|
+
Native.sk_pixmap_get_writable_addr(@ptr)
|
|
63
|
+
else
|
|
64
|
+
Native.sk_pixmap_get_writeable_addr_with_xy(@ptr, x.to_i, y.to_i)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def read_pixels(dst_info, src_x: 0, src_y: 0, row_bytes: nil)
|
|
69
|
+
info = self.class.coerce_image_info(dst_info)
|
|
70
|
+
row_bytes ||= info.min_row_bytes
|
|
71
|
+
byte_size = row_bytes * info.height
|
|
72
|
+
pixels = FFI::MemoryPointer.new(:uint8, byte_size)
|
|
73
|
+
|
|
74
|
+
ok = Native.sk_pixmap_read_pixels(@ptr, info.to_struct, pixels, row_bytes, src_x.to_i, src_y.to_i)
|
|
75
|
+
raise Error, 'Failed to read pixels from pixmap' unless ok
|
|
76
|
+
|
|
77
|
+
pixels.read_bytes(byte_size)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def extract_subset(rect)
|
|
81
|
+
irect = coerce_irect(rect)
|
|
82
|
+
subset = self.class.new
|
|
83
|
+
success = Native.sk_pixmap_extract_subset(@ptr, subset.ptr, irect.to_struct)
|
|
84
|
+
return nil unless success
|
|
85
|
+
|
|
86
|
+
subset
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def reset
|
|
90
|
+
Native.sk_pixmap_reset(@ptr)
|
|
91
|
+
@pixel_storage = nil
|
|
92
|
+
self
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
private
|
|
96
|
+
|
|
97
|
+
def self.coerce_image_info(image_info)
|
|
98
|
+
return image_info if image_info.is_a?(ImageInfo)
|
|
99
|
+
|
|
100
|
+
raise ArgumentError, 'image_info must be a Skia::ImageInfo'
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def coerce_irect(rect)
|
|
104
|
+
return rect if rect.is_a?(IRect)
|
|
105
|
+
|
|
106
|
+
raise ArgumentError, 'rect must be a Skia::IRect'
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
data/lib/skia/point.rb
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Skia
|
|
4
|
+
class Point
|
|
5
|
+
attr_accessor :x, :y
|
|
6
|
+
|
|
7
|
+
def initialize(x = 0.0, y = 0.0)
|
|
8
|
+
@x = x.to_f
|
|
9
|
+
@y = y.to_f
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.from_struct(struct)
|
|
13
|
+
new(struct[:x], struct[:y])
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def to_struct
|
|
17
|
+
struct = Native::SKPoint.new
|
|
18
|
+
struct[:x] = @x
|
|
19
|
+
struct[:y] = @y
|
|
20
|
+
struct
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def +(other)
|
|
24
|
+
self.class.new(@x + other.x, @y + other.y)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def -(other)
|
|
28
|
+
self.class.new(@x - other.x, @y - other.y)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def *(other)
|
|
32
|
+
self.class.new(@x * other, @y * other)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def /(other)
|
|
36
|
+
self.class.new(@x / other, @y / other)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def -@
|
|
40
|
+
self.class.new(-@x, -@y)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def length
|
|
44
|
+
Math.sqrt(@x * @x + @y * @y)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def normalize
|
|
48
|
+
len = length
|
|
49
|
+
return self.class.new(0, 0) if len.zero?
|
|
50
|
+
|
|
51
|
+
self / len
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def ==(other)
|
|
55
|
+
return false unless other.is_a?(Point)
|
|
56
|
+
|
|
57
|
+
@x == other.x && @y == other.y
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def to_a
|
|
61
|
+
[@x, @y]
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
class IPoint
|
|
66
|
+
attr_accessor :x, :y
|
|
67
|
+
|
|
68
|
+
def initialize(x = 0, y = 0)
|
|
69
|
+
@x = x.to_i
|
|
70
|
+
@y = y.to_i
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def self.from_struct(struct)
|
|
74
|
+
new(struct[:x], struct[:y])
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def to_struct
|
|
78
|
+
struct = Native::SKIPoint.new
|
|
79
|
+
struct[:x] = @x
|
|
80
|
+
struct[:y] = @y
|
|
81
|
+
struct
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def ==(other)
|
|
85
|
+
return false unless other.is_a?(IPoint)
|
|
86
|
+
|
|
87
|
+
@x == other.x && @y == other.y
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def to_a
|
|
91
|
+
[@x, @y]
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
data/lib/skia/rect.rb
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Skia
|
|
4
|
+
class Rect
|
|
5
|
+
attr_accessor :left, :top, :right, :bottom
|
|
6
|
+
|
|
7
|
+
def initialize(left = 0.0, top = 0.0, right = 0.0, bottom = 0.0)
|
|
8
|
+
@left = left.to_f
|
|
9
|
+
@top = top.to_f
|
|
10
|
+
@right = right.to_f
|
|
11
|
+
@bottom = bottom.to_f
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.from_xywh(x, y, width, height)
|
|
15
|
+
new(x, y, x + width, y + height)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.from_wh(width, height)
|
|
19
|
+
new(0, 0, width, height)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.from_struct(struct)
|
|
23
|
+
new(struct[:left], struct[:top], struct[:right], struct[:bottom])
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def to_struct
|
|
27
|
+
struct = Native::SKRect.new
|
|
28
|
+
struct[:left] = @left
|
|
29
|
+
struct[:top] = @top
|
|
30
|
+
struct[:right] = @right
|
|
31
|
+
struct[:bottom] = @bottom
|
|
32
|
+
struct
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def width
|
|
36
|
+
@right - @left
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def height
|
|
40
|
+
@bottom - @top
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def center_x
|
|
44
|
+
(@left + @right) / 2.0
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def center_y
|
|
48
|
+
(@top + @bottom) / 2.0
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def center
|
|
52
|
+
Point.new(center_x, center_y)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def empty?
|
|
56
|
+
@left >= @right || @top >= @bottom
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def contains?(x, y)
|
|
60
|
+
x >= @left && x < @right && y >= @top && y < @bottom
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def contains_rect?(other)
|
|
64
|
+
@left <= other.left && @top <= other.top &&
|
|
65
|
+
@right >= other.right && @bottom >= other.bottom
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def intersects?(other)
|
|
69
|
+
@left < other.right && other.left < @right &&
|
|
70
|
+
@top < other.bottom && other.top < @bottom
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def intersect(other)
|
|
74
|
+
return nil unless intersects?(other)
|
|
75
|
+
|
|
76
|
+
self.class.new(
|
|
77
|
+
[@left, other.left].max,
|
|
78
|
+
[@top, other.top].min,
|
|
79
|
+
[@right, other.right].min,
|
|
80
|
+
[@bottom, other.bottom].max
|
|
81
|
+
)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def union(other)
|
|
85
|
+
self.class.new(
|
|
86
|
+
[@left, other.left].min,
|
|
87
|
+
[@top, other.top].min,
|
|
88
|
+
[@right, other.right].max,
|
|
89
|
+
[@bottom, other.bottom].max
|
|
90
|
+
)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def offset(dx, dy)
|
|
94
|
+
self.class.new(@left + dx, @top + dy, @right + dx, @bottom + dy)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def offset!(dx, dy)
|
|
98
|
+
@left += dx
|
|
99
|
+
@top += dy
|
|
100
|
+
@right += dx
|
|
101
|
+
@bottom += dy
|
|
102
|
+
self
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def inset(dx, dy)
|
|
106
|
+
self.class.new(@left + dx, @top + dy, @right - dx, @bottom - dy)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def ==(other)
|
|
110
|
+
return false unless other.is_a?(Rect)
|
|
111
|
+
|
|
112
|
+
@left == other.left && @top == other.top &&
|
|
113
|
+
@right == other.right && @bottom == other.bottom
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def to_a
|
|
117
|
+
[@left, @top, @right, @bottom]
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
class IRect
|
|
122
|
+
attr_accessor :left, :top, :right, :bottom
|
|
123
|
+
|
|
124
|
+
def initialize(left = 0, top = 0, right = 0, bottom = 0)
|
|
125
|
+
@left = left.to_i
|
|
126
|
+
@top = top.to_i
|
|
127
|
+
@right = right.to_i
|
|
128
|
+
@bottom = bottom.to_i
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def self.from_xywh(x, y, width, height)
|
|
132
|
+
new(x, y, x + width, y + height)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def self.from_wh(width, height)
|
|
136
|
+
new(0, 0, width, height)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def self.from_struct(struct)
|
|
140
|
+
new(struct[:left], struct[:top], struct[:right], struct[:bottom])
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def to_struct
|
|
144
|
+
struct = Native::SKIRect.new
|
|
145
|
+
struct[:left] = @left
|
|
146
|
+
struct[:top] = @top
|
|
147
|
+
struct[:right] = @right
|
|
148
|
+
struct[:bottom] = @bottom
|
|
149
|
+
struct
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def width
|
|
153
|
+
@right - @left
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def height
|
|
157
|
+
@bottom - @top
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def empty?
|
|
161
|
+
@left >= @right || @top >= @bottom
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def ==(other)
|
|
165
|
+
return false unless other.is_a?(IRect)
|
|
166
|
+
|
|
167
|
+
@left == other.left && @top == other.top &&
|
|
168
|
+
@right == other.right && @bottom == other.bottom
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def to_a
|
|
172
|
+
[@left, @top, @right, @bottom]
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def to_rect
|
|
176
|
+
Rect.new(@left.to_f, @top.to_f, @right.to_f, @bottom.to_f)
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|