/* doBorder: * Draw rectangle of width border inside rectangle given * by box. If border is 1, we call use a single call to gvrender_polygon. * (We have set linewidth to 1 below.) Otherwise, we use four separate * filled rectangles. We could use a richer graphics model, as things * can go wrong when cell spacing and borders are small. * We decrement the border value by 1, as typically a filled rectangle * from x to x+border will all pixels from x to x+border, and thus have * width border+1. */ static void doBorder(GVJ_t * job, char *color, int border, box B) { pointf pt; boxf BF; double wd, ht; gvrender_begin_context(job); if (!color) color = "black"; gvrender_set_fillcolor(job, color); gvrender_set_pencolor(job, color); B2BF(B, BF); if (border == 1) { gvrender_box(job, BF, 0); } else { border--; ht = BF.UR.y - BF.LL.y; wd = BF.UR.x - BF.LL.x; doSide(job, BF.LL, border, ht); pt.x = BF.LL.x; pt.y = BF.UR.y; doSide(job, pt, wd, -border); doSide(job, BF.UR, -border, -ht); pt.x = BF.UR.x; pt.y = BF.LL.y; doSide(job, pt, -wd, border); } gvrender_end_context(job); }
/* doBorder: * Draw rectangle of width border inside rectangle given * by box. If border is 1, we call use a single call to gvrender_polygon. * (We have set linewidth to 1 below.) Otherwise, we use four separate * filled rectangles. We could use a richer graphics model, as things * can go wrong when cell spacing and borders are small. * We decrement the border value by 1, as typically a filled rectangle * from x to x+border will all pixels from x to x+border, and thus have * width border+1. */ static void doBorder(GVJ_t * job, char *color, int border, boxf BF) { pointf pt; double wd, ht; if (!color) color = DEFAULT_COLOR; gvrender_set_fillcolor(job, color); gvrender_set_pencolor(job, color); if (border == 1) { gvrender_box(job, BF, 0); } else { border--; ht = BF.UR.y - BF.LL.y; wd = BF.UR.x - BF.LL.x; doSide(job, BF.LL, border, ht); pt.x = BF.LL.x; pt.y = BF.UR.y; doSide(job, pt, wd, -border); doSide(job, BF.UR, -border, -ht); pt.x = BF.UR.x; pt.y = BF.LL.y; doSide(job, pt, -wd, border); } }
static void doFill(GVJ_t * job, char *color, box B) { boxf BF; gvrender_set_fillcolor(job, color); gvrender_set_pencolor(job, color); B2BF(B, BF); gvrender_box(job, BF, 1); }
static void doSide(GVJ_t * job, pointf p, double wd, double ht) { boxf BF; BF.LL = p; BF.UR.x = p.x + wd; BF.UR.y = p.y + ht; gvrender_box(job, BF, 1); }
static void emit_html_cell(GVJ_t * job, htmlcell_t * cp, htmlenv_t * env) { htmlmap_data_t saved; boxf pts = cp->data.box; pointf pos = env->pos; int inAnchor, doAnchor = (cp->data.href || cp->data.target); pts.LL.x += pos.x; pts.UR.x += pos.x; pts.LL.y += pos.y; pts.UR.y += pos.y; if (doAnchor && !(job->flags & EMIT_CLUSTERS_LAST)) inAnchor = initAnchor(job, env, &cp->data, pts, &saved, 1); else inAnchor = 0; if (cp->data.bgcolor) { char* clrs[2]; int filled = setFill (job, cp->data.bgcolor, cp->data.gradientangle, cp->data.style, clrs); gvrender_box(job, pts, filled); free (clrs[0]); } if (cp->data.border) doBorder(job, cp->data.pencolor, cp->data.border, pts); if (cp->child.kind == HTML_TBL) emit_html_tbl(job, cp->child.u.tbl, env); else if (cp->child.kind == HTML_IMAGE) emit_html_img(job, cp->child.u.img, env); else emit_html_txt(job, cp->child.u.txt, env); if (inAnchor) endAnchor (job, &saved, 1); if (doAnchor && (job->flags & EMIT_CLUSTERS_LAST)) { if (initAnchor(job, env, &cp->data, pts, &saved, 0)) endAnchor (job, &saved, 0); } }
static void emit_html_tbl(GVJ_t * job, htmltbl_t * tbl, htmlenv_t * env) { boxf pts = tbl->data.box; pointf pos = env->pos; htmlcell_t **cells = tbl->u.n.cells; htmlcell_t *cp; static htmlfont_t savef; htmlmap_data_t saved; int anchor; /* if true, we need to undo anchor settings. */ int doAnchor = (tbl->data.href || tbl->data.target); pointf AF[4]; if (tbl->font) pushFontInfo(env, tbl->font, &savef); pts.LL.x += pos.x; pts.UR.x += pos.x; pts.LL.y += pos.y; pts.UR.y += pos.y; if (doAnchor && !(job->flags & EMIT_CLUSTERS_LAST)) anchor = initAnchor(job, env, &tbl->data, pts, &saved, 1); else anchor = 0; /* Set up rounded style */ if (tbl->data.style & ROUNDED) { AF[0] = pts.LL; AF[2] = pts.UR; if (tbl->data.border) { double delta = ((double)tbl->data.border)/2.0; AF[0].x += delta; AF[0].y += delta; AF[2].x -= delta; AF[2].y -= delta; } AF[1].x = AF[2].x; AF[1].y = AF[0].y; AF[3].x = AF[0].x; AF[3].y = AF[2].y; } /* Fill first */ if (tbl->data.bgcolor) { char* clrs[2]; int filled = setFill (job, tbl->data.bgcolor, tbl->data.gradientangle, tbl->data.style, clrs); if (tbl->data.style & ROUNDED){ round_corners (job, AF, 4, tbl->data.style, filled); } else gvrender_box(job, pts, filled); free (clrs[0]); } while (*cells) { emit_html_cell(job, *cells, env); cells++; } /* Draw table rules and border. * Draw after cells so we can draw over any fill. * At present, we set the penwidth to 1 for rules until we provide the calculations to take * into account wider rules. */ cells = tbl->u.n.cells; gvrender_set_penwidth(job, 1.0); while ((cp = *cells++)){ if (cp->ruled) emit_html_rules(job, cp, env, tbl->data.pencolor); } if (tbl->data.border) { if (tbl->data.style & ROUNDED) { char* color = (tbl->data.pencolor ? tbl->data.pencolor : DEFAULT_COLOR); gvrender_set_penwidth(job, tbl->data.border); gvrender_set_pencolor(job, color); round_corners (job, AF, 4, tbl->data.style, 0); } else doBorder(job, tbl->data.pencolor, tbl->data.border, pts); } if (anchor) endAnchor (job, &saved, 1); if (doAnchor && (job->flags & EMIT_CLUSTERS_LAST)) { if (initAnchor(job, env, &tbl->data, pts, &saved, 0)) endAnchor (job, &saved, 0); } if (tbl->font) popFontInfo(env, &savef); }