52 if(touched || !create)
return touched;
54 if(cairo_surface_set_user_data(surface, &
_touched_key, touched, g_free) != CAIRO_STATUS_SUCCESS)
62static void _touched_add(cairo_surface_t *surface,
const int x0,
const int y0,
const int x1,
const int y1)
64 if(x1 <= x0 || y1 <= y0)
return;
76 touched->
x0 =
MIN(touched->
x0, x0);
77 touched->
y0 =
MIN(touched->
y0, y0);
78 touched->
x1 =
MAX(touched->
x1, x1);
79 touched->
y1 =
MAX(touched->
y1, y1);
84 if(!surface || !touched)
return FALSE;
86 if(!record || !record->
any)
return FALSE;
87 touched->x = record->
x0;
88 touched->y = record->
y0;
89 touched->width = record->
x1 - record->
x0;
90 touched->height = record->
y1 - record->
y0;
103 return surface && cairo_surface_status(surface) == CAIRO_STATUS_SUCCESS
104 && cairo_surface_get_type(surface) == CAIRO_SURFACE_TYPE_IMAGE
105 && cairo_image_surface_get_format(surface) == CAIRO_FORMAT_ARGB32;
138 g_free(scratch->
value);
147 if(scratch)
return scratch;
174 if(!scratch)
return FALSE;
175 const size_t count = (size_t)
width * (
size_t)
height;
176 if(count > scratch->
count)
178 float *grown = g_try_malloc0(count *
sizeof(
float));
179 if(!grown)
return FALSE;
180 g_free(scratch->
value);
181 scratch->
value = grown;
182 scratch->
count = count;
186 int *min_grown = g_try_malloc(
sizeof(
int) * (
size_t)
height);
187 int *max_grown = g_try_malloc(
sizeof(
int) * (
size_t)
height);
188 if(!min_grown || !max_grown)
200 for(
int y = 0; y <
height; y++)
234 const _segment_t *
const seg,
const double reach2)
236 const double dx = seg->
bx - seg->
ax;
237 const double dy = seg->
by - seg->
ay;
238 const double len2 = dx * dx + dy * dy;
239 const double py = (
double)(y + plane->
y0) + 0.5;
241 gboolean wrote =
FALSE;
242 for(
int x = x_first;
x <= x_last;
x++)
244 const double px = (
double)(
x + plane->
x0) + 0.5;
245 double t = (len2 > 0.0) ? ((px - seg->
ax) * dx + (py - seg->
ay) * dy) / len2 : 0.0;
246 if(t < 0.0 && !seg->cap_a)
continue;
247 if(
t > 1.0 && !seg->
cap_b)
continue;
248 t = CLAMP(
t, 0.0, 1.0);
249 const double ex = seg->
ax +
t * dx - px;
250 const double ey = seg->
ay +
t * dy - py;
251 const double d2 = ex * ex + ey * ey;
252 if(d2 >= reach2)
continue;
253 const float inside = (float)(reach2 - d2);
254 if(inside <=
row[
x])
continue;
264 const double reach2 = reach * reach;
265 const int x_first =
MAX((
int)floor(
MIN(seg->
ax, seg->
bx) - reach) - plane->
x0, 0);
266 const int x_last =
MIN((
int)ceil(
MAX(seg->
ax, seg->
bx) + reach) - plane->
x0, plane->
width - 1);
267 const int y_first =
MAX((
int)floor(
MIN(seg->
ay, seg->
by) - reach) - plane->
y0, 0);
268 const int y_last =
MIN((
int)ceil(
MAX(seg->
ay, seg->
by) + reach) - plane->
y0, plane->
height - 1);
269 if(x_first > x_last || y_first > y_last)
return;
271 for(
int y = y_first; y <= y_last; y++)
294 const double reach,
_dash_t *
const dash)
296 const double length = hypot(seg->
bx - seg->
ax, seg->
by - seg->
ay);
299 gboolean piece_starts_at_cut = dash->
fresh;
302 const double run =
MIN(dash->
left, length - pos);
303 const double end = pos + run;
306 const double t0 = pos / length;
307 const double t1 = end / length;
308 const gboolean ends_at_cut = (end < length) || seg->
cap_b ==
FALSE;
310 .ay = seg->
ay + t0 * (seg->
by - seg->
ay),
311 .bx = seg->
ax + t1 * (seg->
bx - seg->
ax),
312 .by = seg->
ay + t1 * (seg->
by - seg->
ay),
313 .cap_a = caps || !(piece_starts_at_cut || (pos == 0.0 && !seg->
cap_a)),
314 .cap_b = caps || !ends_at_cut };
319 if(dash->
left <= 0.0)
321 dash->
on = !dash->
on;
323 piece_starts_at_cut =
TRUE;
326 piece_starts_at_cut =
FALSE;
329 dash->
fresh = piece_starts_at_cut;
333 const double reach,
const gboolean closed,
_dash_t *
const dash)
344 const int last = count - 1;
345 for(
int i = 0;
i < last;
i++)
348 const gboolean starts_line = (
i == 0) && !closed;
349 const gboolean ends_line = (
i == last - 1) && !closed;
354 .cap_a = caps || !starts_line,
355 .cap_b = caps || !ends_line };
390static inline uint32_t
_pixel_pack(
const double a,
const double r,
const double g,
const double b)
392 const uint32_t ia = (uint32_t)(a * 255.0 + 0.5);
393 const uint32_t ir = (uint32_t)(
r * 255.0 + 0.5);
394 const uint32_t ig = (uint32_t)(
g * 255.0 + 0.5);
395 const uint32_t ib = (uint32_t)(b * 255.0 + 0.5);
396 return (ia << 24) | (ir << 16) | (ig << 8) | ib;
401 const double src_a = pass->
alpha * coverage;
402 if(src_a <= 0.0)
return;
403 const uint32_t dst = *pixel;
404 const double keep = 1.0 - src_a;
405 const double a = src_a + ((dst >> 24) & 0xff) / 255.0 * keep;
406 const double r = pass->
red * src_a + ((dst >> 16) & 0xff) / 255.0 * keep;
407 const double g = pass->
green * src_a + ((dst >> 8) & 0xff) / 255.0 * keep;
408 const double b = pass->
blue * src_a + (dst & 0xff) / 255.0 * keep;
415 int *
const tx0,
int *
const tx1)
417 const int sy = y + plane->
y0;
418 if(sy < 0 || sy >= c->surface_height)
return FALSE;
419 const float *
const row = plane->
value + (size_t)y * plane->
width;
420 uint32_t *
const pixels = (uint32_t *)(c->data + (
size_t)sy * c->stride);
421 gboolean painted =
FALSE;
424 const float inside =
row[
x];
425 if(inside <= 0.0f)
continue;
426 const int sx =
x + plane->
x0;
427 if(sx < 0 || sx >= c->surface_width)
continue;
428 const double d = sqrt(
MAX(c->reach2 - (
double)inside, 0.0));
429 if(c->dark)
_pixel_over(&pixels[sx], c->dark, CLAMP(c->half_dark + 0.5 -
d, 0.0, 1.0));
430 if(c->bright)
_pixel_over(&pixels[sx], c->bright, CLAMP(c->half_bright + 0.5 -
d, 0.0, 1.0));
431 *tx0 =
MIN(*tx0, sx);
432 *tx1 =
MAX(*tx1, sx + 1);
441 cairo_surface_flush(surface);
445 .bright = with_bright ? &style->
bright : NULL,
446 .reach2 = reach * reach,
449 .data = cairo_image_surface_get_data(surface),
450 .stride = cairo_image_surface_get_stride(surface),
451 .surface_width = cairo_image_surface_get_width(surface),
452 .surface_height = cairo_image_surface_get_height(surface) };
458 for(
int y = 0; y < plane->
height; y++)
463 ty0 =
MIN(ty0, y + plane->
y0);
464 ty1 =
MAX(ty1, y + plane->
y0 + 1);
471 if(tx1 > tx0 && ty1 > ty0)
473 cairo_surface_mark_dirty_rectangle(surface, tx0, ty0, tx1 - tx0, ty1 - ty0);
486static gboolean
_stroke_polyline(cairo_surface_t *surface,
const double *xy,
const int count,
489 if(count < 1)
return FALSE;
491 if(widest <= 0.0)
return FALSE;
492 const double reach = 0.5 * widest + 1.0;
494 double x_min = DBL_MAX;
495 double y_min = DBL_MAX;
496 double x_max = -DBL_MAX;
497 double y_max = -DBL_MAX;
498 for(
int i = 0;
i < count;
i++)
500 x_min =
MIN(x_min, xy[2 *
i]);
501 x_max =
MAX(x_max, xy[2 *
i]);
502 y_min =
MIN(y_min, xy[2 *
i + 1]);
503 y_max =
MAX(y_max, xy[2 *
i + 1]);
505 if(!isfinite(x_min) || !isfinite(x_max) || !isfinite(y_min) || !isfinite(y_max))
return FALSE;
508 const int surface_width = cairo_image_surface_get_width(surface);
509 const int surface_height = cairo_image_surface_get_height(surface);
510 const int x0 =
MAX((
int)floor(x_min - reach) - 1, 0);
511 const int y0 =
MAX((
int)floor(y_min - reach) - 1, 0);
512 const int x1 =
MIN((
int)ceil(x_max + reach) + 1, surface_width - 1);
513 const int y1 =
MIN((
int)ceil(y_max + reach) + 1, surface_height - 1);
514 if(x1 < x0 || y1 < y0)
return FALSE;
539 cairo_user_to_device_distance(cr, &ax, &ay);
540 cairo_user_to_device_distance(cr, &bx, &by);
541 const double scale = sqrt(hypot(ax, ay) * hypot(bx, by));
542 return isfinite(scale) ? scale : 1.0;
570 if(
g->vertices->len >= 2)
571 _stroke_polyline(surface, (
const double *)
g->vertices->data, (
int)(
g->vertices->len / 2), style,
g->closed, dash);
572 g_array_set_size(
g->vertices, 0);
579 double y =
point->point.
y;
580 cairo_user_to_device(cr, &
x, &y);
581 x =
x *
g->scale_x +
g->offset_x;
582 y = y *
g->scale_y +
g->offset_y;
583 if(
g->vertices->len == 0)
588 g_array_append_val(
g->vertices,
x);
589 g_array_append_val(
g->vertices, y);
594 if(!cr || !style)
return FALSE;
595 cairo_surface_t *surface = cairo_get_group_target(cr);
598 cairo_path_t *path = cairo_copy_path_flat(cr);
599 if(!path || path->status != CAIRO_STATUS_SUCCESS)
601 if(path) cairo_path_destroy(path);
610 cairo_surface_get_device_scale(surface, &gather.
scale_x, &gather.
scale_y);
611 cairo_surface_get_device_offset(surface, &gather.
offset_x, &gather.
offset_y);
623 for(
int i = 0;
i < path->num_data;
i += path->data[
i].header.length)
625 const cairo_path_data_t *
const element = &path->data[
i];
626 switch(element->header.type)
628 case CAIRO_PATH_MOVE_TO:
632 case CAIRO_PATH_LINE_TO:
635 case CAIRO_PATH_CLOSE_PATH:
650 cairo_path_destroy(path);
static _dash_t _dash_start(const dt_stroke_style_t *const style)
static void _plane_composite_and_clear(_plane_t *const plane, cairo_surface_t *surface, const dt_stroke_style_t *style, const double reach)
static void _pixel_over(uint32_t *const pixel, const dt_stroke_pass_t *const pass, const double coverage)
static gboolean _plane_acquire(cairo_surface_t *surface, _plane_t *plane, const int x0, const int y0, const int width, const int height)
static void _polyline_stamp(_plane_t *const plane, const double *xy, const int count, const dt_stroke_style_t *style, const double reach, const gboolean closed, _dash_t *const dash)
static void _plane_stamp_dashed(_plane_t *const plane, const _segment_t *const seg, const dt_stroke_style_t *style, const double reach, _dash_t *const dash)
static void _touched_add(cairo_surface_t *surface, const int x0, const int y0, const int x1, const int y1)
void dt_stroke_raster_touched_reset(cairo_surface_t *surface)
static _scratch_t * _scratch_of(cairo_surface_t *surface)
static double _matrix_scale(cairo_t *cr)
gboolean dt_stroke_raster_polyline(cairo_surface_t *surface, const double *xy, int count, const dt_stroke_style_t *style)
static void _scratch_free(void *data)
static gboolean _stroke_polyline(cairo_surface_t *surface, const double *xy, const int count, const dt_stroke_style_t *style, const gboolean closed, _dash_t *const dash)
static _touched_t * _touched_of(cairo_surface_t *surface, const gboolean create)
static const cairo_user_data_key_t _touched_key
gboolean dt_stroke_raster_path(cairo_t *cr, const dt_stroke_style_t *style)
static void _plane_stamp_capsule(_plane_t *const plane, const _segment_t *const seg, const double reach)
static const cairo_user_data_key_t _scratch_key
static uint32_t _pixel_pack(const double a, const double r, const double g, const double b)
gboolean dt_stroke_raster_can_paint(cairo_surface_t *surface)
gboolean dt_stroke_raster_touched(cairo_surface_t *surface, cairo_rectangle_int_t *touched)
static gboolean _plane_stamp_row(_plane_t *const plane, const int y, const int x_first, const int x_last, const _segment_t *const seg, const double reach2)
static void _gather_flush(_gather_t *const g, cairo_surface_t *surface, const dt_stroke_style_t *style, _dash_t *const dash)
static void _gather_point(_gather_t *const g, cairo_t *cr, const cairo_path_data_t *const point)
static gboolean _composite_row(const _plane_t *const plane, const int y, const _composite_t *const c, int *const tx0, int *const tx1)
const dt_stroke_pass_t * bright
const dt_stroke_pass_t * dark
typedef double((*spd)(unsigned long int wavelength, double TempK))