📄 renderer.c
字号:
if (tag) { tag->x = x; tag->y = y; memcpy(tag->name, t, tag_len + 1); add_to_list(document->tags, tag); if ((void *) renderer_context.last_tag_for_newline == &document->tags) renderer_context.last_tag_for_newline = tag; }}static voidput_chars_conv(struct part *part, unsigned char *chars, int charslen){ assert(part && chars && charslen); if_assert_failed return; if (format.style.attr & AT_GRAPHICS) { put_chars(part, chars, charslen); return; } convert_string(renderer_context.convert_table, chars, charslen, CSM_DEFAULT, NULL, (void (*)(void *, unsigned char *, int)) put_chars, part);}static inline voidput_link_number(struct part *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(part, s, slen); renderer_context.nosearchable = 0; if (ff && ff->type == FC_TEXTAREA) line_break(part); /* 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 = format.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 part *part, enum link_state link_state, unsigned char *chars, int charslen){ 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(part->document, part->link_num, 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(void){ 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;}voidprocess_hidden_link(struct part *part){ enum link_state state = get_link_state(); process_link(part, state, NULL, 0);}#define is_drawing_subs_or_sups() \ ((format.style.attr & AT_SUBSCRIPT && global_doc_opts->display_subs) \ || (format.style.attr & AT_SUPERSCRIPT && global_doc_opts->display_sups))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 part *part, unsigned char *chars, int charslen){ enum link_state link_state; int update_after_subscript = renderer_context.did_subscript; 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 = (void *) &part->document->tags; } int_lower_bound(&part->box.height, part->cy + 1); link_state = get_link_state(); 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 (global_doc_opts->num_links_display) put_link_number(part); } set_hline(part, chars, charslen, link_state); if (link_state != LINK_STATE_NONE) { /* 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.did_subscript)) { link_state = get_link_state(); } process_link(part, 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(part); if (!x) break; if (part->document) align_line(part, 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 part *part){ struct tag *tag; 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(part, part->cx - 1, part->cy); part->cx--; } if (part->cx > 0) align_line(part, part->cy, 1); for (tag = renderer_context.last_tag_for_newline; tag && (void *) 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), CSM_QUERY, NULL, NULL, NULL); if (dv) mem_free_set(&fc->default_value, dv); } if (list_empty(part->document->forms)) { /* No forms encountered yet, that means a homeless form * control. Generate a dummy form for those Flying * Dutchmans. */ form = init_form(); form->form_num = 0; add_to_list(part->document->forms, form); } /* Attach this form control to the last form encountered. */ form = part->document->forms.next; fc->form = form; add_to_list(form->items, fc);}/* Reparents form items based on position in the source. */voidcheck_html_form_hierarchy(struct part *part){ struct document *document = part->document; INIT_LIST_HEAD(form_controls); struct form *form; struct form_control *fc, *next; if (list_empty(document->forms)) return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -