/* html_gr.c * (c) 2002 Mikulas Patocka * This file is a part of the Links program, released under GPL. */ #include "cfg.h" #define format format_ #ifdef G #include "links.h" int get_real_font_size(int size) { int fs=d_opt->font_size; if (size < 1) size = 1; if (size > 7) size = 7; switch (size) { case 1: return (14*fs)>>4; case 2: return (15*fs)>>4; case 3: return (16*fs)>>4; case 4: return (19*fs)>>4; case 5: return (22*fs)>>4; case 6: return (25*fs)>>4; case 7: return (28*fs)>>4; } return 0; } struct background *get_background(unsigned char *bg, unsigned char *bgcolor) { struct background *b; struct rgb r; if (!(b = mem_alloc(sizeof(struct background)))) return NULL; /* !!! FIXME: background image */ { b->img = 0; if (bgcolor && !decode_color(bgcolor, &r)) { b->u.sRGB=(r.r << 16) + (r.g << 8) + r.b; } else { b->u.sRGB=(d_opt->default_bg.r << 16) + (d_opt->default_bg.g << 8) + d_opt->default_bg.b; } } return b; } void g_put_chars(struct g_part *, unsigned char *, int); #define CH_BUF 256 void g_put_chars_conv(struct g_part *p, unsigned char *c, int l) { static char buffer[CH_BUF]; int bp = 0; int pp = 0; if (format.attr & AT_GRAPHICS) { g_put_chars(p, c, l); return; } /*{ debug("\"%.*s\"", l, c); }*/ if (!l) g_put_chars(p, NULL, 0); while (pp < l) { unsigned char *e; if (c[pp] < 128 && c[pp] != '&') { putc: if (!(buffer[bp++] = c[pp++])) buffer[bp - 1] = ' '; if (bp < CH_BUF) continue; goto flush; } if (c[pp] != '&') { struct conv_table *t; int i; if (!convert_table) goto putc; t = convert_table; i = pp; decode: if (!t[c[i]].t) { e = t[c[i]].u.str; } else { t = t[c[i++]].u.tbl; if (i >= l) goto putc; goto decode; } pp = i + 1; } else { int i = pp + 1; if (d_opt->plain & 1) goto putc; while (i < l && c[i] != ';' && c[i] != '&' && c[i] > ' ') i++; if (!(e = get_entity_string(&c[pp + 1], i - pp - 1, d_opt->cp))) goto putc; pp = i + (i < l && c[i] == ';'); } if (!e[0]) continue; if (!e[1]) { buffer[bp++] = e[0]; if (bp < CH_BUF) continue; flush: e = ""; goto flush1; } while (*e) { buffer[bp++] = *(e++); if (bp < CH_BUF) continue; flush1: g_put_chars(p, buffer, bp); bp = 0; } } if (bp) g_put_chars(p, buffer, bp); } /* Returns 0 to 2550 */ int gray (int r, int g, int b) { return r*3+g*6+b; } int too_near(int r1, int g1, int b1, int r2, int g2, int b2) { int gray1,gray2; gray1=gray(r1, g1, b1); gray2=gray(r2, g2, b2); if (gray1<=gray2) return gray2-gray1<=800; else return gray1-gray2<=800; } void separate_fg_bg(int *fgr, int *fgg, int *fgb , int bgr, int bgg, int bgb) { if (too_near(*fgr, *fgg, *fgb, bgr, bgg, bgb)){ *fgr=255-bgr; *fgg=255-bgg; *fgb=255-bgb; }else return; if (too_near(*fgr, *fgg, *fgb, bgr, bgg, bgb)){ if (gray(bgr, bgg, bgb)<=1275) *fgr=*fgg=*fgb=255; else *fgr=*fgg=*fgb=0; } } unsigned char *make_html_font_name(int attr) { unsigned char *str; int len; str=init_str();len=0; add_to_str(&str, &len, G_HTML_DEFAULT_FAMILY); add_to_str(&str, &len, attr & AT_BOLD ? "-bold" : "-medium"); add_to_str(&str, &len, attr & AT_ITALIC ? "-italic-serif" : "-roman-serif"); add_to_str(&str, &len, attr & AT_FIXED ? "-mono" : "-vari"); return str; } struct style *get_style_by_ta(struct text_attrib *ta, int *font_size) { int fg_r,fg_g,fg_b; /* sRGB 0-255 values */ int fs = get_real_font_size(ta->fontsize); struct style*stl; unsigned char *fontname; if (font_size) *font_size = fs; fg_r=ta->fg.r; fg_g=ta->fg.g; fg_b=ta->fg.b; separate_fg_bg(&fg_r,&fg_g,&fg_b,ta->bg.r,ta->bg.g,ta->bg.b); stl = g_get_style((fg_r << 16) + (fg_g << 8) + fg_b, (ta->bg.r << 16) + (ta->bg.g << 8) + ta->bg.b, fs, fontname=make_html_font_name(ta->attr), ta->attr & AT_UNDERLINE ? FF_UNDERLINE : 0); mem_free(fontname); return stl; } #define rm(x) ((x).width - (x).rightmargin * G_HTML_MARGIN > 0 ? (x).width - (x).rightmargin * G_HTML_MARGIN : 0) inline int pw2(int a) { int x = 1; while (x < a && x) x <<= 1; return x; } void flush_pending_line_to_obj(struct g_part *p, int minheight) { int i, pp, pos, w; struct g_object_line *l = p->line; struct g_object_area *a; if (!l) { return; } pp = 0; w = minheight; for (i = 0; i < l->n_entries; i++) { pp += l->entries[i]->xw; if (l->entries[i]->yw > w) w = l->entries[i]->yw; } if (par_format.align == AL_CENTER) pos = (rm(par_format) + par_format.leftmargin * G_HTML_MARGIN - pp) / 2; else if (par_format.align == AL_RIGHT) pos = rm(par_format) - pp; else pos = par_format.leftmargin * G_HTML_MARGIN; if (pos < par_format.leftmargin * G_HTML_MARGIN) pos = par_format.leftmargin * G_HTML_MARGIN; pp = pos; for (i = 0; i < l->n_entries; i++) { l->entries[i]->x = pp; pp += l->entries[i]->xw; l->entries[i]->y = w - l->entries[i]->yw; } l->x = 0; l->xw = par_format.width; l->yw = w; l->y = p->cy; if (l->xw > p->root->xw) p->root->xw = l->xw; p->root->yw = p->cy += w; if (!(a = mem_realloc(p->root, sizeof(struct g_object_area) + sizeof(struct g_object_text *) * pw2(++p->root->n_lines + 1)))) return; /* note: +1 is for extend_area */ p->root = a; p->root->lines[p->root->n_lines - 1] = l; p->line = NULL; p->w.pos = 0; p->w.last_wrap = NULL; p->w.last_wrap_obj = NULL; } void add_object_to_line(struct g_part *pp, struct g_object_line **lp, struct g_object *go) { struct g_object_line *l; if (go && (go->xw < 0 || go->yw < 0)) { internal("object has negative size: %d,%d", go->xw, go->yw); return; } if (!*lp) { if (!(l = mem_calloc(sizeof(struct g_object_line) + sizeof(struct g_object_text *)))) return; l->mouse_event = g_line_mouse; l->draw = g_line_draw; l->destruct = g_line_destruct; l->get_list = g_line_get_list; l->x = 0; l->y = 0; l->xw = 0; l->yw = 0; l->bg = pp->root->bg; if (!go) { *lp = l; return; } l->n_entries = 1; } else { if (!go) return; if (!(l = mem_realloc(*lp, sizeof(struct g_object_line) + sizeof(struct g_object *) * ++(*lp)->n_entries))) return; *lp = l; } l->entries[l->n_entries - 1] = go; *lp = l; if (pp->cx == -1) pp->cx = par_format.leftmargin * G_HTML_MARGIN; pp->cx += go->xw; } void flush_pending_text_to_line(struct g_part *p) { if (!p->text) return; add_object_to_line(p, &p->line, (struct g_object *)p->text); p->text = NULL; } void split_line_object(struct g_part *p, struct g_object_text *text, unsigned char *ptr) { struct g_object_text *t2; struct g_object_line *l2; int n; int esp; if (!ptr) { if (p->line && p->line->n_entries && (struct g_object *)text == p->line->entries[p->line->n_entries - 1]) { flush_pending_line_to_obj(p, 0); goto wwww; } t2 = NULL; goto nt2; } if (!(t2 = mem_calloc(sizeof(struct g_object_text) + strlen(ptr) + 1))) return; t2->mouse_event = g_text_mouse; t2->draw = g_text_draw; t2->destruct = g_text_destruct; t2->get_list = NULL; esp = 1; if (*ptr == ' ') { strcpy(t2->text, ptr + 1); *ptr = 0; /*debug("split: (%s)(%s)", text->text, ptr + 1);*/ } else { strcpy(t2->text, ptr); ptr[0] = '-'; ptr[1] = 0; esp = 0; } t2->style = g_clone_style(text->style); t2->bg = text->bg; t2->link_num = text->link_num; t2->link_order = text->link_order; text->xw = g_text_width(text->style, text->text); nt2: if (p->line) for (n = 0; n < p->line->n_entries; n++) if (p->line->entries[n] == (struct g_object *)text) goto found; if (text != p->text) { internal("split_line_object: bad wrap"); t2->destruct(t2); mem_free(t2); return; } if (0) { int nn; found: n += !ptr; if (!(l2 = mem_calloc(sizeof(struct g_object_line) + (p->line->n_entries - n) * sizeof(struct g_object_text *)))) { t2->destruct(t2); return; } l2->mouse_event = g_line_mouse; l2->draw = g_line_draw; l2->destruct = g_line_destruct; l2->get_list = g_line_get_list; l2->bg = p->root->bg; l2->n_entries = p->line->n_entries - n; l2->entries[0] = (struct g_object *)t2; memcpy(&l2->entries[!!ptr], p->line->entries + n + !!ptr, (l2->n_entries - !!ptr) * sizeof(struct g_object_text *)); p->line->n_entries = n + !!ptr; flush_pending_line_to_obj(p, 0); p->line = l2; if (ptr) { t2->xw = g_text_width(t2->style, t2->text); t2->yw = text->yw; p->w.pos = 0; } for (nn = 0; nn < l2->n_entries; nn++) { p->w.pos += l2->entries[nn]->xw; /* !!! FIXME: nastav last_wrap */ /*debug("a1: %d (%s)", l2->entries[nn]->xw, tt->text);*/ } wwww: if (p->text) p->w.pos += g_text_width(p->text->style, p->text->text); /*debug("%d", p->w.pos);*/ } else { flush_pending_text_to_line(p); flush_pending_line_to_obj(p, 0); p->line = NULL; t2->xw = g_text_width(t2->style, t2->text); t2->yw = text->yw; p->text = t2; p->pending_text_len = -1; p->w.pos = t2->xw; p->cx += g_char_width(t2->style, ' '); } p->w.last_wrap = NULL; p->w.last_wrap_obj = NULL; t2 = p->text; if (t2 && *t2->text && t2->text[strlen(t2->text) - 1] == ' ') { p->w.last_wrap = &t2->text[strlen(t2->text) - 1]; p->w.last_wrap_obj = t2; } } void add_object(struct g_part *p, struct g_object *o) { flush_pending_text_to_line(p); p->w.width = rm(par_format) - par_format.leftmargin * G_HTML_MARGIN; if (p->w.pos + o->xw > p->w.width) flush_pending_line_to_obj(p, 0); add_object_to_line(p, &p->line, o); p->w.last_wrap = NULL; p->w.last_wrap_obj = o; p->w.pos += o->xw; /* if (p->w.pos > p->w.width && p->w.last_wrap_obj) { split_line_object(p, p->w.last_wrap_obj, p->w.last_wrap); } */ } void g_line_break(struct g_part *p) { flush_pending_text_to_line(p); if (!p->line) { add_object_to_line(p, &p->line, NULL); flush_pending_line_to_obj(p, p->current_font_size); } else { flush_pending_line_to_obj(p, 0); } if (p->cx > p->xmax) p->xmax = p->cx; p->cx = -1; } /* SHADOWED IN html_form_control */ void g_html_form_control(struct g_part *p, struct form_control *fc) { if (!p->data) { /*destroy_fc(fc); mem_free(fc);*/ add_to_list(p->uf, fc); return; } fc->g_ctrl_num = g_ctrl_num++; if (fc->type == FC_TEXT || fc->type == FC_PASSWORD || fc->type == FC_TEXTAREA) { unsigned char *dv = convert_string(convert_table, fc->default_value, strlen(fc->default_value), d_opt); if (dv) { mem_free(fc->default_value); fc->default_value = dv; } /* for (i = 0; i < fc->nvalues; i++) if ((dv = convert_string(convert_table, fc->values[i], strlen(fc->values[i]), d_opt))) { mem_free(fc->values[i]); fc->values[i] = dv; } */ } add_to_list(p->data->forms, fc); } struct link **putchars_link_ptr = NULL; /* Probably releases clickable map */ void release_image_map(struct image_map *map) { int i; if (!map) return; for (i = 0; i < map->n_areas; i++) mem_free(map->area[i].coords); mem_free(map); } int is_in_area(struct map_area *a, int x, int y) { int i; int over; switch (a->shape) { case SHAPE_DEFAULT: return 1; case SHAPE_RECT: return a->ncoords >= 4 && x >= a->coords[0] && y >= a->coords[1] && x < a->coords[2] && y < a->coords[3]; case SHAPE_CIRCLE: return a->ncoords >= 3 && (a->coords[0]-x)*(a->coords[0]-x)+(a->coords[1]-y)*(a->coords[1]-y) <= a->coords[2]*a->coords[2]; case SHAPE_POLY: over = 0; if (a->ncoords >= 4) for (i = 0; i + 1 < a->ncoords; i += 2) { int x1, x2, y1, y2; x1 = a->coords[i]; y1 = a->coords[i + 1]; x2 = a->coords[0]; y2 = a->coords[1]; if (i + 3 < a->ncoords) { x2 = a->coords[i + 2]; y2 = a->coords[i + 3]; } if (y1 > y2) { int sw; sw = x1; x1 = x2; x2 = sw; sw = y1; y1 = y2; y2 = sw; } if (y >= y1 && y < y2) { int po = 10000 * (y - y1) / (y2 - y1); int xs = x1 + (x2 - x1) * po / 10000; if (xs >= x) over++; } } return over & 1; default: internal("is_in_area: bad shape: %d", a->shape); } return 0; } void do_image(struct g_part *p, struct image_description *im) { struct g_object_image *io; struct link *link; link = NULL; putchars_link_ptr = &link; g_put_chars(p, NULL, 0); putchars_link_ptr = NULL; if (!link) im->link_num = -1; else { im->link_num = link - p->data->links; im->link_order = link->obj_order++; if (link->img_alt)mem_free(link->img_alt); link->img_alt = stracpy(im->alt); } io = insert_image(p, im); if (!io) goto ab; io->ismap = im->ismap; add_object(p, (struct g_object *)io); if (im->usemap && p->data) { unsigned char *tag = extract_position(im->usemap); struct additional_file *af = request_additional_file(current_f_data, im->usemap); af->need_reparse = 1; if (af->rq && (af->rq->state == O_LOADING || af->rq->state == O_INCOMPLETE || af->rq->state == O_OK) && af->rq->ce) { struct memory_list *ml; struct menu_item *menu; struct cache_entry *ce = af->rq->ce; unsigned char *start, *end; int i; struct image_map *map; get_file(af->rq, &start, &end); if (start == end) goto ft; if (get_image_map(ce->head, start, end, tag, &menu, &ml, format.href_base, format.target_base, 0, 0, 0, 1)) goto ft; if (!(map = mem_alloc(sizeof(struct image_map)))) goto fml; map->n_areas = 0; for (i = 0; menu[i].text; i++) { struct link_def *ld = menu[i].data; struct map_area *a; struct image_map *new; struct link *link; int shape = !ld->shape || !*ld->shape ? SHAPE_RECT : !strcasecmp(ld->shape, "default") ? SHAPE_DEFAULT : !strcasecmp(ld->shape, "rect") ? SHAPE_RECT : !strcasecmp(ld->shape, "circle") ? SHAPE_CIRCLE : !strcasecmp(ld->shape, "poly") ? SHAPE_POLY : -1; if (shape == -1) continue; if (!(new = mem_realloc(map, sizeof(struct image_map) + (map->n_areas + 1) * sizeof(struct map_area)))) continue; map = new; a = &map->area[map->n_areas++]; a->shape = shape; a->coords = DUMMY; a->ncoords = 0; if (ld->coords) { unsigned char *p = ld->coords; int num; int *nco; next_coord: num = 0; while (*p && (*p < '0' || *p > '9')) p++; if (!*p) goto noc; while (*p >= '0' && *p <= '9' && num < 10000000) num = num * 10 + *p - '0', p++; if (*p == '%' && num < 1000) { int m = io->xw < io->yw ? io->xw : io->yw; num = num * m / 100; p++; } if (!(nco = mem_realloc(a->coords, (a->ncoords + 1) * sizeof(int)))) goto noc; (a->coords = nco)[a->ncoords++] = num; goto next_coord; } noc: if (!(link = new_link(p->data))) a->link_num = -1; else { link->pos = DUMMY; link->type = L_LINK; link->where = stracpy(ld->link); link->target = stracpy(ld->target); link->where_img = stracpy(im->url); #ifdef JS if (ld->onclick || ld->ondblclick || ld->onmousedown || ld->onmouseup || ld->onmouseover || ld->onmouseout || ld->onmousemove) { create_js_event_spec(&link->js_event); link->js_event->click_code = stracpy(ld->onclick); link->js_event->dbl_code = stracpy(ld->ondblclick); link->js_event->down_code = stracpy(ld->onmousedown); link->js_event->up_code = stracpy(ld->onmouseup); link->js_event->over_code = stracpy(ld->onmouseover); link->js_event->out_code = stracpy(ld->onmouseout); link->js_event->move_code = stracpy(ld->onmousemove); } #endif a->link_num = link - p->data->links; } if (last_link) mem_free(last_link), last_link = NULL; } io->map = map; fml: freeml(ml); ft:; } if (tag) mem_free(tag); } ab: if (im->usemap) mem_free(im->usemap); } void *g_html_special(struct g_part *p, int c, ...) { va_list l; unsigned char *t; struct form_control *fc; struct frameset_param *fsp; struct frame_param *fp; struct image_description *im; struct g_object_tag *tag; va_start(l, c); switch (c) { case SP_TAG: t = va_arg(l, unsigned char *); va_end(l); /*html_tag(p->data, t, X(p->cx), Y(p->cy));*/ if ((tag = mem_calloc(sizeof(struct g_object_tag) + strlen(t) + 1))) { tag->mouse_event = g_dummy_mouse; tag->draw = g_dummy_draw; tag->destruct = g_tag_destruct; strcpy(tag->name, t); flush_pending_text_to_line(p); add_object_to_line(p, &p->line, (struct g_object *)tag); } break; case SP_CONTROL: fc = va_arg(l, struct form_control *); va_end(l); g_html_form_control(p, fc); break; case SP_TABLE: va_end(l); return convert_table; case SP_USED: va_end(l); return (void *)!!p->data; case SP_FRAMESET: fsp = va_arg(l, struct frameset_param *); va_end(l); return create_frameset(p->data, fsp); case SP_FRAME: fp = va_arg(l, struct frame_param *); va_end(l); create_frame(fp); break; case SP_SCRIPT: t = va_arg(l, unsigned char *); va_end(l); if (p->data) process_script(p->data, t); break; case SP_IMAGE: im = va_arg(l, struct image_description *); va_end(l); do_image(p, im); break; case SP_NOWRAP: va_end(l); break; default: va_end(l); internal("html_special: unknown code %d", c); } return NULL; } unsigned char to_je_ale_prasarna[] = ""; unsigned char *cached_font_face = to_je_ale_prasarna; struct text_attrib_beginning ta_cache = { -1, { 0, 0, 0 }, { 0, 0, 0 } }; void g_put_chars(struct g_part *p, unsigned char *s, int l) { struct g_object_text *t = NULL; struct link *link; if (putchars_link_ptr) { link = NULL; goto check_link; } while (par_format.align != AL_NO && p->cx == -1 && l && *s == ' ') s++, l--; if (!l) return; if (p->cx == -1) p->cx = par_format.leftmargin * G_HTML_MARGIN; if (html_format_changed) { if (memcmp(&ta_cache, &format, sizeof(struct text_attrib_beginning)) || xstrcmp(cached_font_face, format.fontface) || cached_font_face == to_je_ale_prasarna || xstrcmp(format.link, last_link) || xstrcmp(format.target, last_target) || xstrcmp(format.image, last_image) || format.form != last_form || ((format.js_event || last_js_event) && compare_js_event_spec(format.js_event, last_js_event)) ) { /*if (!html_format_changed) internal("html_format_changed not set");*/ flush_pending_text_to_line(p); if (xstrcmp(cached_font_face, format.fontface) || cached_font_face == to_je_ale_prasarna) { if (cached_font_face && cached_font_face != to_je_ale_prasarna) mem_free(cached_font_face); copy_string(&cached_font_face, format.fontface); } memcpy(&ta_cache, &format, sizeof(struct text_attrib_beginning)); if (p->current_style) g_free_style(p->current_style); p->current_style = get_style_by_ta(&format, &p->current_font_size); } html_format_changed = 0; } /*if (p->cx == par_format.leftmargin * G_HTML_MARGIN && *s == ' ' && par_format.align != AL_NO) s++, l--;*/ if (!p->text) { link = NULL; if (!(t = mem_calloc(sizeof(struct g_object_text) + ALLOC_GR))) return; t->mouse_event = g_text_mouse; t->draw = g_text_draw; t->destruct = g_text_destruct; t->get_list = NULL; /*t->style = get_style_by_ta(format, &t->yw);*/ t->style = g_clone_style(p->current_style); t->bg = NULL; /* FIXME!!! */ t->yw = p->current_font_size; t->xw = 0; check_link: if (last_link || last_image || last_form || format.link || format.image || format.form || format.js_event || last_js_event ) goto process_link; back_link: if (putchars_link_ptr) { *putchars_link_ptr = link; return; } if (!link) t->link_num = -1; else { t->link_num = link - p->data->links; t->link_order = link->obj_order++; } t->text[0] = 0; p->pending_text_len = 0; p->text = t; } if (p->pending_text_len == -1) { p->pending_text_len = strlen(p->text->text); goto a1; } if ((p->pending_text_len & ~(ALLOC_GR - 1)) != ((p->pending_text_len + l) & ~(ALLOC_GR - 1))) a1:{ struct g_object_text *t = mem_realloc(p->text, sizeof(struct g_object_text) + ((p->pending_text_len + l + ALLOC_GR) & ~(ALLOC_GR - 1))); if (!t) return; if (p->w.last_wrap >= p->text->text && p->w.last_wrap < p->text->text + p->pending_text_len) p->w.last_wrap += (unsigned char *)t - (unsigned char *)p->text; if (p->w.last_wrap_obj == p->text) p->w.last_wrap_obj = t; p->text = t; } memcpy(p->text->text + p->pending_text_len, s, l), p->text->text[p->pending_text_len += l] = 0; p->text->xw += g_text_width(p->text->style, p->text->text + p->pending_text_len - l); /* !!! FIXME: move to g_wrap_text */ if (par_format.align != AL_NO) { p->w.text = p->text->text + p->pending_text_len - l; p->w.style = p->text->style; p->w.obj = p->text; p->w.width = rm(par_format) - par_format.leftmargin * G_HTML_MARGIN; if (p->w.width < 0) p->w.width = 0; if (!g_wrap_text(&p->w)) { split_line_object(p, p->w.last_wrap_obj, p->w.last_wrap); } } return; /* !!! WARNING: THE FOLLOWING CODE IS SHADOWED IN HTML_R.C */ process_link: if ((last_link /*|| last_target*/ || last_image || last_form) && !xstrcmp(format.link, last_link) && !xstrcmp(format.target, last_target) && !xstrcmp(format.image, last_image) && format.form == last_form && ((!format.js_event && !last_js_event) || !compare_js_event_spec(format.js_event, last_js_event))) { if (!p->data) goto back_link; if (!p->data->nlinks) { internal("no link"); goto back_link; } link = &p->data->links[p->data->nlinks - 1]; goto back_link; } else { if (last_link) mem_free(last_link); if (last_target) mem_free(last_target); if (last_image) mem_free(last_image); free_js_event_spec(last_js_event); last_link = last_target = last_image = NULL; last_form = NULL; last_js_event = NULL; if (!(format.link || format.image || format.form || format.js_event)) goto back_link; /*if (d_opt->num_links) { unsigned char s[64]; unsigned char *fl = format.link, *ft = format.target, *fi = format.image; struct form_control *ff = format.form; struct js_event_spec *js = format.js_event; format.link = format.target = format.image = NULL; format.form = NULL; format.js_event = NULL; s[0] = '['; snzprint(s + 1, 62, p->link_num); strcat(s, "]"); g_put_chars(p, s, strlen(s)); if (ff && ff->type == FC_TEXTAREA) g_line_break(p); if (p->cx == -1) p->cx = par_format.leftmargin * G_HTML_MARGIN; format.link = fl, format.target = ft, format.image = fi; format.form = ff; format.js_event = js; }*/ p->link_num++; last_link = stracpy(format.link); last_target = stracpy(format.target); last_image = stracpy(format.image); last_form = format.form; copy_js_event_spec(&last_js_event, format.js_event); if (!p->data) goto back_link; if (!(link = new_link(p->data))) goto back_link; link->num = p->link_num - 1; link->pos = DUMMY; copy_js_event_spec(&link->js_event, format.js_event); if (!last_form) { link->type = L_LINK; link->where = stracpy(last_link); link->target = stracpy(last_target); } else { link->type = last_form->type == FC_TEXT || last_form->type == FC_PASSWORD || last_form->type == FC_FILE ? L_FIELD : last_form->type == FC_TEXTAREA ? L_AREA : last_form->type == FC_CHECKBOX || last_form->type == FC_RADIO ? L_CHECKBOX : last_form->type == FC_SELECT ? L_SELECT : L_BUTTON; link->form = last_form; link->target = stracpy(last_form->target); } link->where_img = stracpy(last_image); link->sel_color = 0; link->n = 0; } goto back_link; } void g_do_format(char *start, char *end, struct g_part *part, unsigned char *head) { pr( parse_html(start, end, (void (*)(void *, unsigned char *, int)) g_put_chars_conv, (void (*)(void *)) g_line_break, (void *(*)(void *, int, ...)) g_html_special, part, head); /*if ((part->y -= line_breax) < 0) part->y = 0;*/ flush_pending_text_to_line(part); flush_pending_line_to_obj(part, 0); ); } struct g_table_cache_entry { struct g_table_cache_entry *next; struct g_table_cache_entry *prev; unsigned char *start; unsigned char *end; int align; int m; int width; int link_num; struct g_part p; }; struct list_head g_table_cache = { &g_table_cache, &g_table_cache }; void g_free_table_cache() { free_list(g_table_cache); } struct g_part *g_format_html_part(unsigned char *start, unsigned char *end, int align, int m, int width, unsigned char *head, int link_num, unsigned char *bg, unsigned char *bgcolor, struct f_data *f_d) { int wa; struct g_part *p; struct html_element *e; struct form_control *fc; int lm = margin; struct g_table_cache_entry *tce; if (!f_d) foreach(tce, g_table_cache) { if (tce->start == start && tce->end == end && tce->align == align && tce->m == m && tce->width == width && tce->link_num == link_num) { if ((p = mem_alloc(sizeof(struct g_part)))) { memcpy(p, &tce->p, sizeof(struct part)); return p; } } } margin = m; /*d_opt->tables = 0;*/ if (last_link) mem_free(last_link); if (last_image) mem_free(last_image); if (last_target) mem_free(last_target); free_js_event_spec(last_js_event); last_link = last_image = last_target = NULL; last_form = NULL; last_js_event = NULL; cached_font_face = to_je_ale_prasarna; if (!(p = mem_calloc(sizeof(struct g_part)))) return NULL; { struct g_object_area *a; if (!(a = mem_calloc(sizeof(struct g_object_area) + sizeof(struct g_object_line *)))) { mem_free(p); return NULL; } a->bg = get_background(bg, bgcolor); if (bgcolor) decode_color(bgcolor, &format.bg); if (bgcolor) decode_color(bgcolor, &par_format.bgcolor); a->mouse_event = g_area_mouse; a->draw = g_area_draw; a->destruct = g_area_destruct; a->get_list = g_area_get_list; a->lfo = DUMMY; a->rfo = DUMMY; a->n_lines = 0; p->root = a; init_list(p->uf); } p->data = f_d; p->x = p->y = 0; p->xmax = 0; html_stack_dup(); e = &html_top; html_top.dontkill = 2; html_top.namelen = 0; par_format.align = align; par_format.leftmargin = m; par_format.rightmargin = m; par_format.width = width; par_format.list_level = 0; par_format.list_number = 0; par_format.dd_margin = 0; p->cx = -1; g_do_format(start, end, p, head); /*nobreak = 0;*/ line_breax = 1; while (&html_top != e) { kill_html_stack_item(&html_top); if (!&html_top || (void *)&html_top == (void *)&html_stack) { internal("html stack trashed"); break; } } html_top.dontkill = 0; wa = g_get_area_width(p->root); if (wa > p->x) p->x = wa; g_x_extend_area(p->root, p->x, 0); if (p->x > p->xmax) p->xmax = p->x; p->y = p->root->yw; /*debug("WIDTH: obj (%d, %d), p (%d %d)", p->root->xw, p->root->yw, p->x, p->y);*/ kill_html_stack_item(&html_top); if (!f_d) g_release_part(p), p->root = NULL; if (cached_font_face && cached_font_face != to_je_ale_prasarna) mem_free(cached_font_face); cached_font_face = to_je_ale_prasarna; foreach(fc, p->uf) destroy_fc(fc); free_list(p->uf); margin = lm; if (last_link) mem_free(last_link); if (last_image) mem_free(last_image); if (last_target) mem_free(last_target); free_js_event_spec(last_js_event); last_link = last_image = last_target = NULL; last_form = NULL; last_js_event = NULL; if (table_level > 1 && !f_d && ((tce = mem_alloc(sizeof(struct g_table_cache_entry))))) { tce->start = start; tce->end = end; tce->align = align; tce->m = m; tce->width = width; tce->link_num = link_num; memcpy(&tce->p, p, sizeof(struct g_part)); add_to_list(g_table_cache, tce); } return p; } void g_release_part(struct g_part *p) { if (p->text) p->text->destruct(p->text); if (p->line) p->line->destruct(p->line); if (p->root) p->root->destruct(p->root); if (p->current_style) g_free_style(p->current_style); } void g_scan_width(struct g_object **o, int n, int *w) { while (n--) { if ((*o)->x + (*o)->xw > *w) *w = (*o)->x + (*o)->xw; o++; } } void g_scan_lines(struct g_object_line **o, int n, int *w) { while (n--) { if ((*o)->n_entries) { struct g_object *oo = (*o)->entries[(*o)->n_entries - 1]; if ((*o)->x + oo->x + oo->xw > *w) *w = (*o)->x + oo->x + oo->xw; } o++; } } int g_get_area_width(struct g_object_area *a) { int w = 0; g_scan_width(a->lfo, a->n_lfo, &w); g_scan_width(a->rfo, a->n_rfo, &w); g_scan_lines(a->lines, a->n_lines, &w); return w; } void g_x_extend_area(struct g_object_area *a, int width, int height) { struct g_object_line *l; int i; a->xw = width; for (i = 0; i < a->n_lines; i++) { a->lines[i]->xw = width; } for (i = a->n_lines - 1; i >= 0; i--) { l = a->lines[i]; if (!l->n_entries) { a->yw -= l->yw; l->destruct(l); a->n_lines--; continue; } break; } if (a->yw >= height) return; if (!(l = mem_calloc(sizeof(struct g_object_line)))) return; l->mouse_event = g_line_mouse; l->draw = g_line_draw; l->destruct = g_line_destruct; l->get_list = g_line_get_list; l->x = 0; l->y = a->yw; l->xw = width; l->yw = height - a->yw; l->bg = a->bg; l->n_entries = 0; a->lines[a->n_lines] = l; a->n_lines++; } #endif