static int sBezierNumSegments(cdCanvas* canvas, cdPoint start, const cdPoint* p) { int i, K, dx, dy, d, xmax = start.x, ymax = start.y, xmin = start.x, ymin = start.y; for (i = 1; i < 4; i++) { if (p[i].x > xmax) xmax = p[i].x; if (p[i].y > ymax) ymax = p[i].y; if (p[i].x < xmin) xmin = p[i].x; if (p[i].y < ymin) ymin = p[i].y; } if (canvas->use_matrix) { cdMatrixTransformPoint(canvas->matrix, xmin, ymin, &xmin, &ymin); cdMatrixTransformPoint(canvas->matrix, xmax, ymax, &xmax, &ymax); } /* diagonal of the bounding box */ dx = (xmax-xmin); dy = (ymax-ymin); d = (int)(sqrt(dx*dx + dy*dy)); K = d / 8; if (K < 8) K = 8; return K; }
static void cdline(cdCtxCanvas *ctxcanvas, int x1, int y1, int x2, int y2) { if (ctxcanvas->canvas->use_matrix) { cdMatrixTransformPoint(ctxcanvas->xmatrix, x1, y1, &x1, &y1); cdMatrixTransformPoint(ctxcanvas->xmatrix, x2, y2, &x2, &y2); } cdgdkCheckSolidStyle(ctxcanvas, 1); gdk_draw_line(ctxcanvas->wnd, ctxcanvas->gc, x1, y1, x2, y2); cdgdkCheckSolidStyle(ctxcanvas, 0); }
void cdImageRGBCalcDstLimits(cdCanvas* canvas, int x, int y, int w, int h, int *xmin, int *xmax, int *ymin, int *ymax, int* rect) { int t_xmin, t_xmax, t_ymin, t_ymax, t_x, t_y, t_w, t_h; /* calculate the bounding box of the transformed rectangle */ cdMatrixTransformPoint(canvas->matrix, x, y, &t_x, &t_y); if (rect) { rect[0] = t_x; rect[1] = t_y; } t_xmax = t_xmin = t_x; t_ymax = t_ymin = t_y; cdMatrixTransformPoint(canvas->matrix, x+w-1, y, &t_x, &t_y); if (rect) { rect[2] = t_x; rect[3] = t_y; } if (t_x > t_xmax) t_xmax = t_x; if (t_x < t_xmin) t_xmin = t_x; if (t_y > t_ymax) t_ymax = t_y; if (t_y < t_ymin) t_ymin = t_y; cdMatrixTransformPoint(canvas->matrix, x+w-1, y+h-1, &t_x, &t_y); if (rect) { rect[4] = t_x; rect[5] = t_y; } if (t_x > t_xmax) t_xmax = t_x; if (t_x < t_xmin) t_xmin = t_x; if (t_y > t_ymax) t_ymax = t_y; if (t_y < t_ymin) t_ymin = t_y; cdMatrixTransformPoint(canvas->matrix, x, y+h-1, &t_x, &t_y); if (rect) { rect[6] = t_x; rect[7] = t_y; } if (t_x > t_xmax) t_xmax = t_x; if (t_x < t_xmin) t_xmin = t_x; if (t_y > t_ymax) t_ymax = t_y; if (t_y < t_ymin) t_ymin = t_y; t_x = t_xmin; t_y = t_ymin; t_w = t_xmax-t_xmin+1; t_h = t_ymax-t_ymin+1; /* check if inside the canvas */ if (t_x > (canvas->w-1) || t_y > (canvas->h-1) || (t_x+t_w) < 0 || (t_y+t_h) < 0) return; /* fit to canvas area */ if (t_x < 0) t_x = 0; if (t_y < 0) t_y = 0; if ((t_x+t_w) > (canvas->w-1)) t_w = (canvas->w-1)-t_x; if ((t_y+t_h) > (canvas->h-1)) t_h = (canvas->h-1)-t_y; /* define the destiny limits */ *xmin = t_x; *ymin = t_y; *xmax = t_x+t_w-1; *ymax = t_y+t_h-1; }
static int sCalcEllipseNumSegments(cdCanvas* canvas, int xc, int yc, int width, int height, double angle1, double angle2) { int K, dx, dy, hd; int w2 = width/2; int h2 = height/2; int x1 = xc-w2, y1 = yc-h2, x2 = xc+w2, y2 = yc+h2; if (canvas->use_matrix) { cdMatrixTransformPoint(canvas->matrix, x1, y1, &x1, &y1); cdMatrixTransformPoint(canvas->matrix, x2, y2, &x2, &y2); } /* first calculate the number of segments of equivalent poligonal for a full ellipse */ dx = (x1-x2); dy = (y1-y2); hd = (int)(sqrt(dx*dx + dy*dy)/2); /* Estimation Heuristic: use half diagonal to estimate the number of segments for 360 degrees. Use the difference of the half diagonal and its projection to calculate the minimum angle: cos(min_angle) = hd / (hd + 1) or min_angle = acos(hd / (hd + 1)) The number of segments will be 360 / min_angle. */ K = (int)((360.0*CD_DEG2RAD) / acos((double)hd / (hd + 1.0)) + 0.5); /* round up */ /* multiple of 4 */ K = ((K + 3)/4)*4; /* minimum number is 4 */ if (K < 4) K = 4; /* finally, calculate the number of segments for the arc */ K = cdRound((fabs(angle2-angle1)*K)/(360*CD_DEG2RAD)); if (K < 1) K = 1; return K; }
void cdlineSIM(cdCtxCanvas* ctxcanvas, int x1, int y1, int x2, int y2) { cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; int old_use_matrix = canvas->use_matrix; if (canvas->use_matrix && !canvas->invert_yaxis) { cdMatrixTransformPoint(canvas->matrix, x1, y1, &x1, &y1); cdMatrixTransformPoint(canvas->matrix, x2, y2, &x2, &y2); } /* must disable transformation here, because line simulation use cxPixel */ canvas->use_matrix = 0; if(canvas->line_width > 1) simLineThick(canvas, x1, y1, x2, y2); else simLineThin(canvas, x1, y1, x2, y2); canvas->use_matrix = old_use_matrix; }
static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n) { int i; if (mode != CD_BEZIER && mode != CD_PATH) { for (i = 0; i < n; i++) { if (ctxcanvas->canvas->use_matrix) cdMatrixTransformPoint(ctxcanvas->xmatrix, poly[i].x, poly[i].y, &(poly[i].x), &(poly[i].y)); } } switch( mode ) { case CD_FILL: if (ctxcanvas->canvas->new_region) { GdkRegion* rgn = gdk_region_polygon((GdkPoint*)poly, n, ctxcanvas->canvas->fill_mode == CD_EVENODD ? GDK_EVEN_ODD_RULE : GDK_WINDING_RULE); sCombineRegion(ctxcanvas, rgn); } else gdk_draw_polygon(ctxcanvas->wnd, ctxcanvas->gc, TRUE, (GdkPoint*)poly, n); break; case CD_CLOSED_LINES: cdgdkCheckSolidStyle(ctxcanvas, 1); gdk_draw_polygon(ctxcanvas->wnd, ctxcanvas->gc, FALSE, (GdkPoint*)poly, n); cdgdkCheckSolidStyle(ctxcanvas, 0); break; case CD_OPEN_LINES: cdgdkCheckSolidStyle(ctxcanvas, 1); gdk_draw_lines(ctxcanvas->wnd, ctxcanvas->gc, (GdkPoint*)poly, n); cdgdkCheckSolidStyle(ctxcanvas, 0); break; case CD_CLIP: ctxcanvas->clip_rgn = gdk_region_polygon((GdkPoint*)poly, n, ctxcanvas->canvas->fill_mode == CD_EVENODD ? GDK_EVEN_ODD_RULE : GDK_WINDING_RULE); if (ctxcanvas->canvas->clip_mode == CD_CLIPPOLYGON) cdclip(ctxcanvas, CD_CLIPPOLYGON); break; case CD_BEZIER: cdSimPolyBezier(ctxcanvas->canvas, poly, n); break; case CD_PATH: cdSimPolyPath(ctxcanvas->canvas, poly, n); break; } }
void cdpolySIM(cdCtxCanvas* ctxcanvas, int mode, cdPoint* poly, int n) { cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas; int i, reset = 1; switch(mode) { case CD_CLOSED_LINES: poly[n] = poly[0]; n++; /* continue */ case CD_OPEN_LINES: if (simLineStyleNoReset) /* Bezier simulation use several poly */ { reset = 0; simLineStyleNoReset = 1; } for (i = 0; i< n - 1; i++) canvas->cxLine(canvas->ctxcanvas, poly[i].x, poly[i].y, poly[i+1].x, poly[i+1].y); if (reset) simLineStyleNoReset = 0; break; case CD_BEZIER: simLineStyleNoReset = 1; cdSimPolyBezier(canvas, poly, n); simLineStyleNoReset = 0; break; case CD_FILL: { /* must set line attributes here, because fill simulation use cxLine */ int oldwidth = cdCanvasLineWidth(canvas, 1); int oldstyle = cdCanvasLineStyle(canvas, CD_CONTINUOUS); int old_use_matrix = canvas->use_matrix; if (canvas->use_matrix && !canvas->invert_yaxis) { for(i = 0; i < n; i++) cdMatrixTransformPoint(canvas->matrix, poly[i].x, poly[i].y, &poly[i].x, &poly[i].y); } /* must disable transformation here, because line simulation use cxPixel */ canvas->use_matrix = 0; simPolyFill(canvas->simulation, poly, n); canvas->use_matrix = old_use_matrix; cdCanvasLineStyle(canvas, oldstyle); cdCanvasLineWidth(canvas, oldwidth); } break; } }
int simCalcEllipseNumSegments(cdCanvas* canvas, int xc, int yc, int width, int height) { int n, dx, dy, hd; int w2 = width/2; int h2 = height/2; int x1 = xc-w2, y1 = yc-h2, x2 = xc+w2, y2 = yc+h2; if (canvas->use_matrix) { cdMatrixTransformPoint(canvas->matrix, x1, y1, &x1, &y1); cdMatrixTransformPoint(canvas->matrix, x2, y2, &x2, &y2); } dx = (x1-x2); dy = (y1-y2); hd = (int)(sqrt(dx*dx + dy*dy)/2); /* Estimation Heuristic: use half diagonal to estimate the number of segments for 360 degrees. Use the difference of the half diagonal and its projection to calculate the minimum angle: cos(min_angle) = hd / (hd + 1) or min_angle = acos(hd / (hd + 1)) The number of segments will be 360 / min_angle. */ n = (int)((360.0*CD_DEG2RAD) / acos((double)hd / (hd + 1.0)) + 0.5); /* round up */ /* multiple of 4 */ n = ((n + 3)/4)*4; /* minimum number is 4 */ if (n < 4) n = 4; return n; }
static void cdpixel(cdCtxCanvas *ctxcanvas, int x, int y, long int color) { if (ctxcanvas->canvas->foreground != color) { GdkColor clr = cdColorToGdk(color); gdk_gc_set_rgb_fg_color(ctxcanvas->gc, &clr); } if (ctxcanvas->canvas->use_matrix) cdMatrixTransformPoint(ctxcanvas->xmatrix, x, y, &x, &y); /* Draw pixel */ gdk_draw_point(ctxcanvas->wnd, ctxcanvas->gc, x, y); if (ctxcanvas->canvas->foreground != color) gdk_gc_set_rgb_fg_color(ctxcanvas->gc, &ctxcanvas->fg); }
void simGetPenPos(cdCanvas* canvas, int x, int y, const char* s, int len, FT_Matrix *matrix, FT_Vector *pen) { int ox = x, oy = y; int old_invert_yaxis = canvas->invert_yaxis; int w, h, ascent, height, baseline; cdSimGetTextSizeFT(canvas->ctxcanvas, s, len, &w, &h); cdSimGetFontDimFT(canvas->ctxcanvas, NULL, &height, &ascent, NULL); baseline = height - ascent; /* in this case we are always upwards */ /* move to bottom left */ canvas->invert_yaxis = 0; cdTextTranslatePoint(canvas, x, y, w, h, baseline, &x, &y); canvas->invert_yaxis = old_invert_yaxis; /* move to the base line */ y += baseline; /* set up matrix */ matrix->xx = (FT_Fixed)0x10000L; matrix->xy = (FT_Fixed)0; matrix->yx = (FT_Fixed)0; matrix->yy = (FT_Fixed)0x10000L; if (canvas->text_orientation) { FT_Matrix text_matrix; double cos_theta = cos(canvas->text_orientation*CD_DEG2RAD); double sin_theta = sin(canvas->text_orientation*CD_DEG2RAD); /* manually rotate the initial point */ canvas->invert_yaxis = 0; cdRotatePoint(canvas, x, y, ox, oy, &x, &y, sin_theta, cos_theta); canvas->invert_yaxis = old_invert_yaxis; text_matrix.xx = (FT_Fixed)( cos_theta*0x10000L); text_matrix.xy = (FT_Fixed)(-sin_theta*0x10000L); text_matrix.yx = (FT_Fixed)( sin_theta*0x10000L); text_matrix.yy = (FT_Fixed)( cos_theta*0x10000L); FT_Matrix_Multiply(&text_matrix, matrix); } if (canvas->use_matrix) { FT_Matrix trans_matrix; trans_matrix.xx = (FT_Fixed)(canvas->matrix[0]*0x10000L); trans_matrix.yx = (FT_Fixed)(canvas->matrix[1]*0x10000L); trans_matrix.xy = (FT_Fixed)(canvas->matrix[2]*0x10000L); trans_matrix.yy = (FT_Fixed)(canvas->matrix[3]*0x10000L); FT_Matrix_Multiply(&trans_matrix, matrix); /* manually transform the initial point */ cdMatrixTransformPoint(canvas->matrix, x, y, &x, &y); } /* the pen position in 26.6 scale */ pen->x = x * 64; pen->y = y * 64; }
static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *s, int len) { PangoFontMetrics* metrics; int w, h, desc, dir = -1; int ox = x, oy = y; pango_layout_set_text(ctxcanvas->fontlayout, sStrConvertToUTF8(ctxcanvas, s, len), -1); pango_layout_get_pixel_size(ctxcanvas->fontlayout, &w, &h); metrics = pango_context_get_metrics(ctxcanvas->fontcontext, ctxcanvas->fontdesc, pango_context_get_language(ctxcanvas->fontcontext)); desc = (((pango_font_metrics_get_descent(metrics)) + PANGO_SCALE/2) / PANGO_SCALE); switch (ctxcanvas->canvas->text_alignment) { case CD_BASE_RIGHT: case CD_NORTH_EAST: case CD_EAST: case CD_SOUTH_EAST: x = x - w; break; case CD_BASE_CENTER: case CD_CENTER: case CD_NORTH: case CD_SOUTH: x = x - w/2; break; case CD_BASE_LEFT: case CD_NORTH_WEST: case CD_WEST: case CD_SOUTH_WEST: x = x; break; } if (ctxcanvas->canvas->invert_yaxis) dir = 1; switch (ctxcanvas->canvas->text_alignment) { case CD_BASE_LEFT: case CD_BASE_CENTER: case CD_BASE_RIGHT: y = y - (dir*h - desc); break; case CD_SOUTH_EAST: case CD_SOUTH_WEST: case CD_SOUTH: y = y - (dir*h); break; case CD_NORTH_EAST: case CD_NORTH: case CD_NORTH_WEST: y = y; break; case CD_CENTER: case CD_EAST: case CD_WEST: y = y - (dir*(h/2)); break; } if(!ctxcanvas->canvas->use_matrix) { ctxcanvas->fontmatrix.xx = 1; ctxcanvas->fontmatrix.xy = 0; ctxcanvas->fontmatrix.yx = 0; ctxcanvas->fontmatrix.yy = 1; ctxcanvas->fontmatrix.x0 = 0; ctxcanvas->fontmatrix.y0 = 0; } if (ctxcanvas->canvas->use_matrix || ctxcanvas->canvas->text_orientation) { PangoRectangle rect; double angle = ctxcanvas->canvas->text_orientation; if (ctxcanvas->canvas->text_orientation) pango_matrix_rotate(&ctxcanvas->fontmatrix, angle); pango_context_set_matrix (ctxcanvas->fontcontext, &ctxcanvas->fontmatrix); pango_layout_context_changed (ctxcanvas->fontlayout); pango_layout_get_pixel_extents(ctxcanvas->fontlayout, NULL, &rect); #if PANGO_VERSION_CHECK(1,16,0) pango_matrix_transform_pixel_rectangle(&ctxcanvas->fontmatrix, &rect); #endif if (ctxcanvas->canvas->text_orientation) { double cos_angle = cos(angle*CD_DEG2RAD); double sin_angle = sin(angle*CD_DEG2RAD); cdRotatePoint(ctxcanvas->canvas, x, y, ox, oy, &x, &y, sin_angle, cos_angle); } if (ctxcanvas->canvas->use_matrix) cdMatrixTransformPoint(ctxcanvas->xmatrix, x, y, &x, &y); /* Defines the new position (X,Y), considering the Pango rectangle transformed */ x += (int)rect.x; y += (int)rect.y; } cdgdkCheckSolidStyle(ctxcanvas, 1); if (ctxcanvas->canvas->new_region) { GdkRegion *rgn; gint *idx; gint range; pango_layout_line_get_x_ranges(pango_layout_get_line(ctxcanvas->fontlayout, 0), 0, len, &idx, &range); /* TODO: this is only the bounding box of the layout, not the text itself, must transform the text into a polygon. */ rgn = gdk_pango_layout_get_clip_region(ctxcanvas->fontlayout, x, y, idx, range); sCombineRegion(ctxcanvas, rgn); } else gdk_draw_layout(ctxcanvas->wnd, ctxcanvas->gc, x, y, ctxcanvas->fontlayout); pango_context_set_matrix(ctxcanvas->fontcontext, NULL); cdgdkCheckSolidStyle(ctxcanvas, 0); pango_font_metrics_unref(metrics); }