1
2 #pragma once
3
4 #define SANITY_CHECKS 0
5
6
7
8 #define rounded_rect_top_left(r) (GRAPHENE_RECT_INIT(r->bounds.origin.x, \
9 r->bounds.origin.y, \
10 r->corner[0].width, r->corner[0].height))
11
12 #define rounded_rect_top_right(r) (GRAPHENE_RECT_INIT(r->bounds.origin.x + r->bounds.size.width - r->corner[1].width, \
13 r->bounds.origin.y, \
14 r->corner[1].width, r->corner[1].height))
15
16 #define rounded_rect_bottom_right(r) (GRAPHENE_RECT_INIT(r->bounds.origin.x + r->bounds.size.width - r->corner[2].width, \
17 r->bounds.origin.y + r->bounds.size.height - r->corner[2].height, \
18 r->corner[2].width, r->corner[2].height))
19
20 #define rounded_rect_bottom_left(r) (GRAPHENE_RECT_INIT(r->bounds.origin.x, \
21 r->bounds.origin.y + r->bounds.size.height - r->corner[2].height, \
22 r->corner[3].width, r->corner[3].height))
23
24
25 #define rounded_rect_corner0(r) rounded_rect_top_left(r)
26 #define rounded_rect_corner1(r) rounded_rect_top_right(r)
27 #define rounded_rect_corner2(r) rounded_rect_bottom_right(r)
28 #define rounded_rect_corner3(r) rounded_rect_bottom_left(r)
29
30 #define rounded_rect_corner(r, i) (rounded_rect_corner ##i(r))
31 #define graphene_size_non_zero(s) (s->width > 0 && s->height > 0)
32 #define rounded_rect_has_corner(r, i) (r->corner[i].width > 0 && r->corner[i].height > 0)
33
34 #define rect_contains_point(r, _x, _y) (_x >= (r)->origin.x && _x <= (r)->origin.x + (r)->size.width && \
35 _y >= (r)->origin.y && _y <= (r)->origin.y + (r)->size.height)
36
37 enum {
38 NINE_SLICE_TOP_LEFT = 0,
39 NINE_SLICE_TOP_CENTER = 1,
40 NINE_SLICE_TOP_RIGHT = 2,
41 NINE_SLICE_LEFT_CENTER = 3,
42 NINE_SLICE_CENTER = 4,
43 NINE_SLICE_RIGHT_CENTER = 5,
44 NINE_SLICE_BOTTOM_LEFT = 6,
45 NINE_SLICE_BOTTOM_CENTER = 7,
46 NINE_SLICE_BOTTOM_RIGHT = 8,
47 };
48 #define NINE_SLICE_SIZE 9 /* Hah. */
49
50 typedef struct
51 {
52 int texture_id;
53 float x;
54 float y;
55 float x2;
56 float y2;
57 } TextureRegion;
58
59 static inline bool G_GNUC_PURE
slice_is_visible(const cairo_rectangle_int_t * r)60 slice_is_visible (const cairo_rectangle_int_t *r)
61 {
62 return (r->width > 0 && r->height > 0);
63 }
64
65 static inline void
nine_slice_rounded_rect(const GskRoundedRect * rect,cairo_rectangle_int_t * out_rects)66 nine_slice_rounded_rect (const GskRoundedRect *rect,
67 cairo_rectangle_int_t *out_rects)
68 {
69 const graphene_point_t *origin = &rect->bounds.origin;
70 const graphene_size_t *size = &rect->bounds.size;
71 const int top_height = ceilf (MAX (rect->corner[GSK_CORNER_TOP_LEFT].height,
72 rect->corner[GSK_CORNER_TOP_RIGHT].height));
73 const int bottom_height = ceilf (MAX (rect->corner[GSK_CORNER_BOTTOM_LEFT].height,
74 rect->corner[GSK_CORNER_BOTTOM_RIGHT].height));
75 const int right_width = ceilf (MAX (rect->corner[GSK_CORNER_TOP_RIGHT].width,
76 rect->corner[GSK_CORNER_BOTTOM_RIGHT].width));
77 const int left_width = ceilf (MAX (rect->corner[GSK_CORNER_TOP_LEFT].width,
78 rect->corner[GSK_CORNER_BOTTOM_LEFT].width));
79
80 /* Top left */
81 out_rects[0] = (cairo_rectangle_int_t) {
82 origin->x, origin->y,
83 left_width, top_height,
84 };
85
86 /* Top center */
87 out_rects[1] = (cairo_rectangle_int_t) {
88 origin->x + size->width / 2.0 - 0.5, origin->y,
89 1, top_height,
90 };
91
92 /* Top right */
93 out_rects[2] = (cairo_rectangle_int_t) {
94 origin->x + size->width - right_width, origin->y,
95 right_width, top_height
96 };
97
98 /* Left center */
99 out_rects[3] = (cairo_rectangle_int_t) {
100 origin->x, origin->y + size->height / 2,
101 left_width, 1,
102 };
103
104 /* center */
105 out_rects[4] = (cairo_rectangle_int_t) {
106 origin->x + size->width / 2.0 - 0.5,
107 origin->y + size->height / 2.0 - 0.5,
108 1, 1
109 };
110
111 /* Right center */
112 out_rects[5] = (cairo_rectangle_int_t) {
113 origin->x + size->width - right_width,
114 origin->y + (size->height / 2.0) - 0.5,
115 right_width,
116 1,
117 };
118
119 /* Bottom Left */
120 out_rects[6] = (cairo_rectangle_int_t) {
121 origin->x, origin->y + size->height - bottom_height,
122 left_width, bottom_height,
123 };
124
125 /* Bottom center */
126 out_rects[7] = (cairo_rectangle_int_t) {
127 origin->x + (size->width / 2.0) - 0.5,
128 origin->y + size->height - bottom_height,
129 1, bottom_height,
130 };
131
132 /* Bottom right */
133 out_rects[8] = (cairo_rectangle_int_t) {
134 origin->x + size->width - right_width,
135 origin->y + size->height - bottom_height,
136 right_width, bottom_height,
137 };
138
139 #if SANITY_CHECKS
140 g_assert_cmpfloat (size->width, >=, left_width + right_width);
141 g_assert_cmpfloat (size->height, >=, top_height + bottom_height);
142 #endif
143 }
144
145 static inline void
nine_slice_grow(cairo_rectangle_int_t * slices,const int amount)146 nine_slice_grow (cairo_rectangle_int_t *slices,
147 const int amount)
148 {
149 /* top left */
150 slices[0].x -= amount;
151 slices[0].y -= amount;
152 if (amount > slices[0].width)
153 slices[0].width += amount * 2;
154 else
155 slices[0].width += amount;
156
157 if (amount > slices[0].height)
158 slices[0].height += amount * 2;
159 else
160 slices[0].height += amount;
161
162
163 /* Top center */
164 slices[1].y -= amount;
165 if (amount > slices[1].height)
166 slices[1].height += amount * 2;
167 else
168 slices[1].height += amount;
169
170 /* top right */
171 slices[2].y -= amount;
172 if (amount > slices[2].width)
173 {
174 slices[2].x -= amount;
175 slices[2].width += amount * 2;
176 }
177 else
178 {
179 slices[2].width += amount;
180 }
181
182 if (amount > slices[2].height)
183 slices[2].height += amount * 2;
184 else
185 slices[2].height += amount;
186
187
188
189 slices[3].x -= amount;
190 if (amount > slices[3].width)
191 slices[3].width += amount * 2;
192 else
193 slices[3].width += amount;
194
195 /* Leave Britney^Wcenter alone */
196
197 if (amount > slices[5].width)
198 {
199 slices[5].x -= amount;
200 slices[5].width += amount * 2;
201 }
202 else
203 {
204 slices[5].width += amount;
205 }
206
207
208 /* Bottom left */
209 slices[6].x -= amount;
210 if (amount > slices[6].width)
211 {
212 slices[6].width += amount * 2;
213 }
214 else
215 {
216 slices[6].width += amount;
217 }
218
219 if (amount > slices[6].height)
220 {
221 slices[6].y -= amount;
222 slices[6].height += amount * 2;
223 }
224 else
225 {
226 slices[6].height += amount;
227 }
228
229
230 /* Bottom center */
231 if (amount > slices[7].height)
232 {
233 slices[7].y -= amount;
234 slices[7].height += amount * 2;
235 }
236 else
237 {
238 slices[7].height += amount;
239 }
240
241 if (amount > slices[8].width)
242 {
243 slices[8].x -= amount;
244 slices[8].width += amount * 2;
245 }
246 else
247 {
248 slices[8].width += amount;
249 }
250
251 if (amount > slices[8].height)
252 {
253 slices[8].y -= amount;
254 slices[8].height += amount * 2;
255 }
256 else
257 {
258 slices[8].height += amount;
259 }
260
261 #if SANITY_CHECKS
262 {
263 for (int i = 0; i < 9; i ++)
264 {
265 g_assert_cmpint (slices[i].x, >=, 0);
266 g_assert_cmpint (slices[i].y, >=, 0);
267 g_assert_cmpint (slices[i].width, >=, 0);
268 g_assert_cmpint (slices[i].height, >=, 0);
269 }
270
271 /* Rows don't overlap */
272 for (int i = 0; i < 3; i++)
273 {
274 g_assert_cmpint (slices[i * 3 + 0].x + slices[i * 3 + 0].width, <, slices[i * 3 + 1].x);
275 }
276 }
277 #endif
278
279 }
280
281 static inline void
nine_slice_to_texture_coords(const cairo_rectangle_int_t * slices,const int texture_width,const int texture_height,TextureRegion * out_regions)282 nine_slice_to_texture_coords (const cairo_rectangle_int_t *slices,
283 const int texture_width,
284 const int texture_height,
285 TextureRegion *out_regions)
286 {
287 const float fw = (float)texture_width;
288 const float fh = (float)texture_height;
289 int i;
290
291 for (i = 0; i < 9; i++)
292 {
293 out_regions[i] = (TextureRegion) {
294 0, /* Texture id */
295 slices[i].x / fw,
296 1.0 - ((slices[i].y + slices[i].height) / fh),
297 (slices[i].x + slices[i].width) / fw,
298 1.0 - (slices[i].y / fh),
299 };
300 }
301
302 #if SANITY_CHECKS
303 {
304 for (i = 0; i < 9; i++)
305 {
306 const TextureRegion *r = &out_regions[i];
307 g_assert_cmpfloat (r->x, >=, 0);
308 g_assert_cmpfloat (r->x, <=, 1);
309 g_assert_cmpfloat (r->y, >=, 0);
310 g_assert_cmpfloat (r->y, <=, 1);
311
312 g_assert_cmpfloat (r->x, <, r->x2);
313 g_assert_cmpfloat (r->y, <, r->y2);
314 }
315 }
316 #endif
317 }
318