renderer.c
来自「elinks下lynx是最重要的二个文本浏览器, 在linux下非常实用, el」· C语言 代码 · 共 2,052 行 · 第 1/4 页
C
2,052 行
case FC_SUBMIT: case FC_IMAGE: case FC_RESET: case FC_BUTTON: case FC_HIDDEN: link->type = LINK_BUTTON; } link->data.form_control = fc; /* At this point, format.form might already be set but * the form_control not registered through SP_CONTROL * yet, therefore without fc->form set. It is always * after the "good" last form was already processed, * though, so we can safely just take that. */ form = fc->form; if (!form && !list_empty(document->forms)) form = document->forms.next; link->target = null_or_stracpy(form ? form->target : NULL); } link->color.background = format.style.bg; link->color.foreground = link_is_textinput(link) ? format.style.fg : format.clink; init_link_event_hooks(html_context, link); return link;}static voidhtml_special_tag(struct document *document, unsigned char *t, int x, int y){ struct tag *tag; int tag_len; assert(document); if_assert_failed return; tag_len = strlen(t); /* One byte is reserved for name in struct tag. */ tag = mem_alloc(sizeof(*tag) + tag_len); if (!tag) return; tag->x = x; tag->y = y; memcpy(tag->name, t, tag_len + 1); add_to_list(document->tags, tag); if (renderer_context.last_tag_for_newline == (struct tag *) &document->tags) renderer_context.last_tag_for_newline = tag;}static voidput_chars_conv(struct html_context *html_context, unsigned char *chars, int charslen){ struct part *part; assert(html_context); if_assert_failed return; part = html_context->part; assert(part && chars && charslen); if_assert_failed return; if (format.style.attr & AT_GRAPHICS) { put_chars(html_context, chars, charslen); return; } convert_string(renderer_context.convert_table, chars, charslen, html_context->options->cp, CSM_DEFAULT, NULL, (void (*)(void *, unsigned char *, int)) put_chars, html_context);}static inline voidput_link_number(struct html_context *html_context){ struct part *part = html_context->part; unsigned char s[64]; unsigned char *fl = format.link; unsigned char *ft = format.target; unsigned char *fi = format.image; struct form_control *ff = format.form; int slen = 0; format.link = format.target = format.image = NULL; format.form = NULL; s[slen++] = '['; ulongcat(s, &slen, part->link_num, sizeof(s) - 3, 0); s[slen++] = ']'; s[slen] = '\0'; renderer_context.nosearchable = 1; put_chars(html_context, s, slen); renderer_context.nosearchable = 0; if (ff && ff->type == FC_TEXTAREA) line_break(html_context); /* We might have ended up on a new line after the line breaking * or putting the link number chars. */ if (part->cx == -1) part->cx = par_format.leftmargin; format.link = fl; format.target = ft; format.image = fi; format.form = ff;}#define assert_link_variable(old, new) \ assertm(!(old), "Old link value [%s]. New value [%s]", old, new);static inline voidinit_link_state_info(unsigned char *link, unsigned char *target, unsigned char *image, struct form_control *form){ assert_link_variable(renderer_context.link_state_info.image, image); assert_link_variable(renderer_context.link_state_info.target, target); assert_link_variable(renderer_context.link_state_info.link, link); renderer_context.link_state_info.link = null_or_stracpy(link); renderer_context.link_state_info.target = null_or_stracpy(target); renderer_context.link_state_info.image = null_or_stracpy(image); renderer_context.link_state_info.form = form;}static inline voiddone_link_state_info(void){ mem_free_if(renderer_context.link_state_info.link); mem_free_if(renderer_context.link_state_info.target); mem_free_if(renderer_context.link_state_info.image); memset(&renderer_context.link_state_info, 0, sizeof(renderer_context.link_state_info));}static inline voidprocess_link(struct html_context *html_context, enum link_state link_state, unsigned char *chars, int charslen){ struct part *part = html_context->part; struct link *link; int x_offset = 0; switch (link_state) { case LINK_STATE_SAME: { unsigned char *name; if (!part->document) return; assertm(part->document->nlinks > 0, "no link"); if_assert_failed return; link = &part->document->links[part->document->nlinks - 1]; name = get_link_name(link); if (name) { unsigned char *new_name; new_name = straconcat(name, chars, NULL); if (new_name) { mem_free(name); link->data.name = new_name; } } /* FIXME: Concatenating two adjectent <a> elements to a single * link is broken since we lose the event handlers for the * second one. OTOH simply appending them here won't fly since * we may get here multiple times for even a single link. We * will probably need some SP_ for creating a new link or so. * --pasky */ break; } case LINK_STATE_NEW: part->link_num++; init_link_state_info(format.link, format.target, format.image, format.form); if (!part->document) return; /* Trim leading space from the link text */ while (x_offset < charslen && chars[x_offset] <= ' ') x_offset++; if (x_offset) { charslen -= x_offset; chars += x_offset; } link = new_link(html_context, chars, charslen); if (!link) return; break; case LINK_STATE_NONE: default: INTERNAL("bad link_state %i", (int) link_state); return; } /* Add new canvas positions to the link. */ if (realloc_points(link, link->npoints + charslen)) { struct point *point = &link->points[link->npoints]; int x = X(part->cx) + x_offset; int y = Y(part->cy); link->npoints += charslen; for (; charslen > 0; charslen--, point++, x++) { point->x = x; point->y = y; } }}static inline enum link_stateget_link_state(struct html_context *html_context){ enum link_state state; if (!(format.link || format.image || format.form)) { state = LINK_STATE_NONE; } else if ((renderer_context.link_state_info.link || renderer_context.link_state_info.image || renderer_context.link_state_info.form) && !xstrcmp(format.link, renderer_context.link_state_info.link) && !xstrcmp(format.target, renderer_context.link_state_info.target) && !xstrcmp(format.image, renderer_context.link_state_info.image) && format.form == renderer_context.link_state_info.form) { return LINK_STATE_SAME; } else { state = LINK_STATE_NEW; } done_link_state_info(); return state;}static inline inthtml_has_non_space_chars(unsigned char *chars, int charslen){ int pos = 0; while (pos < charslen) if (!isspace(chars[pos++])) return 1; return 0;}voidput_chars(struct html_context *html_context, unsigned char *chars, int charslen){ enum link_state link_state; int update_after_subscript = renderer_context.subscript; struct part *part; assert(html_context); if_assert_failed return; part = html_context->part; assert(part); if_assert_failed return; assert(chars && charslen); if_assert_failed return; /* If we are not handling verbatim aligning and we are at the begining * of a line trim whitespace. */ if (part->cx == -1) { /* If we are not handling verbatim aligning trim leading * whitespaces. */ if (!html_is_preformatted()) { while (charslen && *chars == ' ') { chars++; charslen--; } if (charslen < 1) return; } part->cx = par_format.leftmargin; } /* For preformatted html always update 'the last tag' so we never end * up moving tags to the wrong line (Fixes bug 324). For all other html * it is moved only when the line being rendered carry some real * non-whitespace content. */ if (html_is_preformatted() || html_has_non_space_chars(chars, charslen)) { renderer_context.last_tag_for_newline = (struct tag *) &part->document->tags; } int_lower_bound(&part->box.height, part->cy + 1); link_state = get_link_state(html_context); if (link_state == LINK_STATE_NEW) { int x_offset = 0; /* Don't add inaccessible links. It seems to be caused * by the parser putting a space char after stuff like * <img>-tags or comments wrapped in <a>-tags. See bug * 30 for test case. */ while (x_offset < charslen && chars[x_offset] <= ' ') x_offset++; /* For pure spaces reset the link state */ if (x_offset == charslen) link_state = LINK_STATE_NONE; else if (html_context->options->links_numbering) put_link_number(html_context); } set_hline(html_context, chars, charslen, link_state); if (link_state != LINK_STATE_NONE) {#define is_drawing_subs_or_sups() \ ((format.style.attr & AT_SUBSCRIPT \ && html_context->options->display_subs) \ || (format.style.attr & AT_SUPERSCRIPT \ && html_context->options->display_sups)) /* We need to update the current @link_state because <sub> and * <sup> tags will output to the canvas using an inner * put_chars() call which results in their process_link() call * will ``update'' the @link_state. */ if (link_state == LINK_STATE_NEW && (is_drawing_subs_or_sups() || update_after_subscript != renderer_context.subscript)) { link_state = get_link_state(html_context); }#undef is_drawing_subs_or_sups process_link(html_context, link_state, chars, charslen); } if (renderer_context.nowrap && part->cx + charslen > overlap(par_format)) return; part->cx += charslen; renderer_context.nobreak = 0; if (!html_is_preformatted()) { while (part->cx > overlap(par_format) && part->cx > par_format.leftmargin) { int x = split_line(html_context); if (!x) break; if (part->document) align_line(html_context, part->cy - 1, 0); renderer_context.nobreak = !!(x - 1); } } assert(charslen > 0); part->xa += charslen; int_lower_bound(&part->max_width, part->xa + par_format.leftmargin + par_format.rightmargin - (chars[charslen - 1] == ' ' && !html_is_preformatted())); return;}#undef overlapvoidline_break(struct html_context *html_context){ struct part *part; struct tag *tag; assert(html_context); if_assert_failed return; part = html_context->part; assert(part); if_assert_failed return; int_lower_bound(&part->box.width, part->cx + par_format.rightmargin); if (renderer_context.nobreak) { renderer_context.nobreak = 0; part->cx = -1; part->xa = 0; return; } if (!part->document || !part->document->data) goto end; if (!realloc_lines(part->document, part->box.height + part->cy + 1)) return; if (part->cx > par_format.leftmargin && LEN(part->cy) > part->cx - 1 && POS(part->cx - 1, part->cy).data == ' ') { del_chars(html_context, part->cx - 1, part->cy); part->cx--; } if (part->cx > 0) align_line(html_context, part->cy, 1); for (tag = renderer_context.last_tag_for_newline; tag && tag != (struct tag *) &part->document->tags; tag = tag->prev) { tag->x = X(0); tag->y = Y(part->cy + 1); }end: part->cy++; part->cx = -1; part->xa = 0; memset(part->spaces, 0, part->spaces_len);}static voidhtml_special_form(struct part *part, struct form *form){ assert(part && form); if_assert_failed return; if (!part->document) { done_form(form); return; } if (!list_empty(part->document->forms)) { struct form *nform; /* Make sure the new form ``claims'' its slice of the form range * maintained in the form_num and form_end variables. */ foreach (nform, part->document->forms) { if (form->form_num < nform->form_num || nform->form_end < form->form_num) continue; /* First check if the form has identical form numbers. * That should only be the case when the form being * added is in fact the same form in which case it * should be dropped. The fact that this can happen * suggests that the table renderering can be confused. * See bug 647 for a test case. */ if (nform->form_num == form->form_num && nform->form_end == form->form_end) { done_form(form); return; } /* The form start is inside an already added form, so * partition the space of the existing form and get * |old|new|. */ nform->form_end = form->form_num - 1; assertm(nform->form_num <= nform->form_end, "[%d:%d] [%d:%d]", nform->form_num, nform->form_end, form->form_num, form->form_end); break; } } else { /* If it is the first form make sure it eats the whole form * range. */#if 0 /* Disabled because in tables the parse order may lead to a * later form being parsed before a preceeding one causing the * wrong order if we set it to zero. Let's hope it doesn't break * anything else. */ form->form_num = 0;#endif } add_to_list(part->document->forms, form);}static voidhtml_special_form_control(struct part *part, struct form_control *fc){ struct form *form; assert(part && fc); if_assert_failed return; if (!part->document) { done_form_control(fc); mem_free(fc); return; } fc->g_ctrl_num = renderer_context.g_ctrl_num++; /* We don't want to recode hidden fields. */ if (fc->type == FC_TEXT || fc->type == FC_PASSWORD || fc->type == FC_TEXTAREA) { unsigned char *dv = convert_string(renderer_context.convert_table, fc->default_value, strlen(fc->default_value), part->document->options.cp, CSM_QUERY, NULL, NULL, NULL); if (dv) mem_free_set(&fc->default_value, dv); }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?