#include "evas_common.h" #include "evas_blend_private.h" static void _evas_draw_point(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y); static void _evas_draw_simple_line(RGBA_Image *dst, RGBA_Draw_Context *dc, int x0, int y0, int x1, int y1); static void _evas_draw_line(RGBA_Image *dst, RGBA_Draw_Context *dc, int x0, int y0, int x1, int y1); static void _evas_draw_line_aa(RGBA_Image *dst, RGBA_Draw_Context *dc, int x0, int y0, int x1, int y1); #define IN_RANGE(x, y, w, h) \ ( x > 0 && y > 0 &&((unsigned)(x) < (unsigned)(w)) && ((unsigned)(y) < (unsigned)(h)) ) #define IN_RECT(x, y, rx, ry, rw, rh) \ ( ((unsigned)((x) - (rx)) < (unsigned)(rw)) && \ ((unsigned)((y) - (ry)) < (unsigned)(rh)) ) #define EXCHANGE_POINTS(x0, y0, x1, y1) \ { \ int _tmp = y0; \ \ y0 = y1; \ y1 = _tmp; \ \ _tmp = x0; \ x0 = x1; \ x1 = _tmp; \ } EAPI void evas_common_line_init(void) { } EAPI void evas_common_line_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, int x0, int y0, int x1, int y1) { int x, y, w, h; int clx, cly, clw, clh; int cuse, cx, cy, cw, ch; if ((x0 == x1) && (y0 == y1)) { _evas_draw_point(dst, dc, x0, y0); return; } clx = cly = 0; clw = dst->cache_entry.w; clh = dst->cache_entry.h; /* save out clip info */ cuse = dc->clip.use; cx = dc->clip.x; cy = dc->clip.y; cw = dc->clip.w; ch = dc->clip.h; if (cuse) { RECTS_CLIP_TO_RECT(clx, cly, clw, clh, cx, cy, cw, ch); if ((clw < 1) || (clh < 1)) return; } x = MIN(x0, x1); y = MIN(y0, y1); w = MAX(x0, x1) - x + 1; h = MAX(y0, y1) - y + 1; RECTS_CLIP_TO_RECT(clx, cly, clw, clh, x, y, w, h); if ((clw < 1) || (clh < 1)) return; dc->clip.use = 1; dc->clip.x = clx; dc->clip.y = cly; dc->clip.w = clw; dc->clip.h = clh; if (dc->anti_alias) _evas_draw_line_aa(dst, dc, x0, y0, x1, y1); else _evas_draw_line(dst, dc, x0, y0, x1, y1); /* restore clip info */ dc->clip.use = cuse; dc->clip.x = cx; dc->clip.y = cy; dc->clip.w = cw; dc->clip.h = ch; } static void _evas_draw_point(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y) { RGBA_Gfx_Pt_Func pfunc; if (!IN_RANGE(x, y, dst->cache_entry.w, dst->cache_entry.h)) return; if ((dc->clip.use) && (!IN_RECT(x, y, dc->clip.x, dc->clip.y, dc->clip.w, dc->clip.h))) return; pfunc = evas_common_gfx_func_composite_color_pt_get(dc->col.col, dst, dc->render_op); if (pfunc) pfunc(0, 255, dc->col.col, dst->image.data + (dst->cache_entry.w * y) + x); } /* these functions use the dc->clip data as bounding data. they assume that such data has already been cut back to lie in the dst image rect and the object's (line) bounding rect. */ static void _evas_draw_simple_line(RGBA_Image *dst, RGBA_Draw_Context *dc, int x0, int y0, int x1, int y1) { int dx, dy, len, lx, ty, rx, by; int clx, cly, clw, clh; int dstw; DATA32 *p, color; RGBA_Gfx_Pt_Func pfunc; RGBA_Gfx_Func sfunc; dstw = dst->cache_entry.w; color = dc->col.col; if (y0 > y1) EXCHANGE_POINTS(x0, y0, x1, y1) if (x0 > x1) EXCHANGE_POINTS(x0, y0, x1, y1) dx = x1 - x0; dy = y1 - y0; clx = dc->clip.x; cly = dc->clip.y; clw = dc->clip.w; clh = dc->clip.h; lx = clx; rx = clx + clw - 1; ty = cly; by = cly + clh - 1; if (dy == 0) { #ifdef EVAS_SLI if (((y0) % dc->sli.h) == dc->sli.y) #endif { if ((y0 >= ty) && (y0 <= by)) { if (dx < 0) { int tmp = x1; x1 = x0; x0 = tmp; } if (x0 < lx) x0 = lx; if (x1 > rx) x1 = rx; len = x1 - x0 + 1; p = dst->image.data + (dstw * y0) + x0; sfunc = evas_common_gfx_func_composite_color_span_get(color, dst, len, dc->render_op); if (sfunc) sfunc(NULL, NULL, color, p, len); } } return; } pfunc = evas_common_gfx_func_composite_color_pt_get(color, dst, dc->render_op); if (!pfunc) return; if (dx == 0) { if ((x0 >= lx) && (x0 <= rx)) { if (y0 < ty) y0 = ty; if (y1 > by) y1 = by; len = y1 - y0 + 1; p = dst->image.data + (dstw * y0) + x0; while (len--) { #ifdef EVAS_SLI if (((y1 + 1 - len) % dc->sli.h) == dc->sli.y) #endif { pfunc(0, 255, color, p); } p += dstw; } } return; } if ((dy == dx) || (dy == -dx)) { int p0_in, p1_in; p0_in = (IN_RECT(x0, y0, clx, cly, clw, clh) ? 1 : 0); p1_in = (IN_RECT(x1, y1, clx, cly, clw, clh) ? 1 : 0); if (dy > 0) { if (!p0_in) { x0 = x0 + (ty - y0); y0 = ty; if (x0 > rx) return; if (x0 < lx) { y0 = y0 + (lx - x0); x0 = lx; if ((y0 < ty) || (y0 > by)) return; } } if (!p1_in) { x1 = x0 + (by - y0); y1 = by; if (x1 < lx) return; if (x1 > rx) { y1 = y0 + (rx - x0); x1 = rx; if ((y1 < ty) || (y1 > by)) return; } } } else { if (!p0_in) { x0 = x0 - (by - y0); y0 = by; if (x0 > rx) return; if (x0 < lx) { y0 = y0 - (lx - x0); x0 = lx; if ((y0 < ty) || (y0 > by)) return; } } if (!p1_in) { x1 = x0 - (ty - y0); y1 = ty; if (x1 < lx) return; if (x1 > rx) { y1 = y0 - (rx - x0); x1 = rx; if ((y1 < ty) || (y1 > by)) return; } } } if (y1 > y0) { p = dst->image.data + (dstw * y0) + x0; len = y1 - y0 + 1; if (dx > 0) dstw++; else dstw--; } else { len = y0 - y1 + 1; p = dst->image.data + (dstw * y1) + x1; if (dx > 0) dstw--; else dstw++; } while (len--) { #ifdef EVAS_SLI if (((y1 + 1 - len) % dc->sli.h) == dc->sli.y) #endif { pfunc(0, 255, color, p); } p += dstw; } } } #define SETUP_LINE_SHALLOW \ if (x0 > x1) \ { \ EXCHANGE_POINTS(x0, y0, x1, y1); \ dx = -dx; \ dy = -dy; \ } \ \ px = x0; \ py = y0; \ \ p0_in = (IN_RANGE(x0 , y0 , clw, clh) ? 1 : 0); \ p1_in = (IN_RANGE(x1 , y1 , clw, clh) ? 1 : 0); \ \ dely = 1; \ dh = dstw; \ if (dy < 0) \ { \ dely = -1; \ dh = -dstw; \ } \ \ dyy = ((dy) << 16) / (dx); \ \ if (!p0_in) \ { \ dxx = ((dx) << 16) / (dy); \ if (px < 0) \ { \ x = -px; px = 0; \ yy = x * dyy; \ y = yy >> 16; \ if (!a_a) \ y += (yy - (y << 16)) >> 15; \ py += y; \ if ((dely > 0) && (py >= clh)) \ return; \ else if ((dely < 0) && (py < -1)) \ return; \ } \ \ y = 0; \ if ((dely > 0) && (py < 0)) \ y = (-1 - py); \ else if ((dely < 0) && (py >= clh)) \ y = (clh - 1 - py); \ \ xx = y * dxx; \ x = xx >> 16; \ if (!a_a) \ x += (xx - (x << 16)) >> 15; \ px += x; \ if (px >= clw) return; \ \ yy = x * dyy; \ y = yy >> 16; \ if (!a_a) \ y += (yy - (y << 16)) >> 15; \ py += y; \ if ((dely > 0) && (py >= clh)) \ return; \ else if ((dely < 0) && (py < -1)) \ return; \ } \ \ p = data + (dstw * py) + px; \ \ x = px - x0; \ yy = x * dyy; \ prev_y = (yy >> 16); \ \ rx = MIN(x1 + 1, clw); \ by = clh - 1; #define SETUP_LINE_STEEP \ if (y0 > y1) \ { \ EXCHANGE_POINTS(x0, y0, x1, y1); \ dx = -dx; \ dy = -dy; \ } \ \ px = x0; \ py = y0; \ \ p0_in = (IN_RANGE(x0 , y0 , clw, clh) ? 1 : 0); \ p1_in = (IN_RANGE(x1 , y1 , clw, clh) ? 1 : 0); \ \ delx = 1; \ if (dx < 0) \ delx = -1; \ \ dxx = ((dx) << 16) / (dy); \ \ if (!p0_in) \ { \ dyy = ((dy) << 16) / (dx); \ \ if (py < 0) \ { \ y = -py; py = 0; \ xx = y * dxx; \ x = xx >> 16; \ if (!a_a) \ x += (xx - (x << 16)) >> 15; \ px += x; \ if ((delx > 0) && (px >= clw)) \ return; \ else if ((delx < 0) && (px < -1)) \ return; \ } \ \ x = 0; \ if ((delx > 0) && (px < -1)) \ x = (-1 - px); \ else if ((delx < 0) && (px >= clw)) \ x = (clw - 1 - px); \ \ yy = x * dyy; \ y = yy >> 16; \ if (!a_a) \ y += (yy - (y << 16)) >> 15; \ py += y; \ if (py >= clh) return; \ \ xx = y * dxx; \ x = xx >> 16; \ if (!a_a) \ x += (xx - (x << 16)) >> 15; \ px += x; \ if ((delx > 0) && (px >= clw)) \ return; \ else if ((delx < 0) && (px < -1)) \ return; \ } \ \ p = data + (dstw * py) + px; \ \ y = py - y0; \ xx = y * dxx; \ prev_x = (xx >> 16); \ \ by = MIN(y1 + 1, clh); \ rx = clw - 1; static void _evas_draw_line(RGBA_Image *dst, RGBA_Draw_Context *dc, int x0, int y0, int x1, int y1) { int px, py, x, y, prev_x, prev_y; int dx, dy, rx, by, p0_in, p1_in, dh, a_a = 0; int delx, dely, xx, yy, dxx, dyy; int clx, cly, clw, clh; int dstw; DATA32 *p, *data, color; RGBA_Gfx_Pt_Func pfunc; dx = x1 - x0; dy = y1 - y0; if ( (dx == 0) || (dy == 0) || (dx == dy) || (dx == -dy) ) { _evas_draw_simple_line(dst, dc, x0, y0, x1, y1); return; } color = dc->col.col; pfunc = evas_common_gfx_func_composite_color_pt_get(color, dst, dc->render_op); if (!pfunc) return; clx = dc->clip.x; cly = dc->clip.y; clw = dc->clip.w; clh = dc->clip.h; data = dst->image.data; dstw = dst->cache_entry.w; data += (dstw * cly) + clx; x0 -= clx; y0 -= cly; x1 -= clx; y1 -= cly; /* shallow: x-parametric */ if ((dy < dx) || (dy < -dx)) { SETUP_LINE_SHALLOW; while (px < rx) { y = (yy >> 16); y += ((yy - (y << 16)) >> 15); if (prev_y != y) { prev_y = y; p += dh; py += dely; } if (!p1_in) { if ((py < 0) && (dely < 0)) return; if ((py > by) && (dely > 0)) return; } if (!p0_in) { if (py < 0) goto next_x; } #ifdef EVAS_SLI if (((py) % dc->sli.h) == dc->sli.y) #endif { if (IN_RANGE(px, py, clw, clh)) pfunc(0, 255, color, p); } next_x: yy += dyy; px++; p++; } return; } /* steep: y-parametric */ SETUP_LINE_STEEP; while (py < by) { x = (xx >> 16); x += ((xx - (x << 16)) >> 15); if (prev_x != x) { prev_x = x; px += delx; p += delx; } if (!p1_in) { if ((px < 0) && (delx < 0)) return; if ((px > rx) && (delx > 0)) return; } if (!p0_in) { if (px < 0) goto next_y; } #ifdef EVAS_SLI if (((py) % dc->sli.h) == dc->sli.y) #endif { if (IN_RANGE(px, py, clw, clh)) pfunc(0, 255, color, p); } next_y: xx += dxx; py++; p += dstw; } } static void _evas_draw_line_aa(RGBA_Image *dst, RGBA_Draw_Context *dc, int x0, int y0, int x1, int y1) { int px, py, x, y, prev_x, prev_y; int dx, dy, rx, by, p0_in, p1_in, dh, a_a = 1; int delx, dely, xx, yy, dxx, dyy; int clx, cly, clw, clh; int dstw; DATA32 *p, *data, color; RGBA_Gfx_Pt_Func pfunc; if (y0 > y1) EXCHANGE_POINTS(x0, y0, x1, y1); dx = x1 - x0; dy = y1 - y0; if ( (dx == 0) || (dy == 0) || (dx == dy) || (dx == -dy) ) { _evas_draw_simple_line(dst, dc, x0, y0, x1, y1); return; } color = dc->col.col; pfunc = evas_common_gfx_func_composite_mask_color_pt_get(color, dst, dc->render_op); if (!pfunc) return; clx = dc->clip.x; cly = dc->clip.y; clw = dc->clip.w; clh = dc->clip.h; data = evas_cache_image_pixels(&dst->cache_entry); dstw = dst->cache_entry.w; data += (dstw * cly) + clx; x0 -= clx; y0 -= cly; x1 -= clx; y1 -= cly; /* shallow: x-parametric */ if ((dy < dx) || (dy < -dx)) { SETUP_LINE_SHALLOW; while (px < rx) { DATA8 aa; y = (yy >> 16); if (prev_y != y) { prev_y = y; p += dh; py += dely; } if (!p1_in) { if ((py < 0) && (dely < 0)) return; if ((py > by) && (dely > 0)) return; } if (!p0_in) { if (py < 0) goto next_x; } if (px < clw) { aa = ((yy - (y << 16)) >> 8); if ((py) < clh) pfunc(0, 255 - aa, color, p); if ((py + 1) < clh) pfunc(0, aa, color, p + dstw); } next_x: yy += dyy; px++; p++; } return; } /* steep: y-parametric */ SETUP_LINE_STEEP; while (py < by) { DATA8 aa; x = (xx >> 16); if (prev_x != x) { prev_x = x; px += delx; p += delx; } if (!p1_in) { if ((px < 0) && (delx < 0)) return; if ((px > rx) && (delx > 0)) return; } if (!p0_in) { if (px < 0) goto next_y; } if (py < clh) { aa = ((xx - (x << 16)) >> 8); if ((px) < clw) pfunc(0, 255 - aa, color, p); if ((px + 1) < clw) pfunc(0, aa, color, p + 1); } next_y: xx += dxx; py++; p += dstw; } }