📄 renderer.c
字号:
continue; matched = 1; if (link->points[i].x < X(xf)) continue; if (yt >= 0) { link->points[i].y = Y(yt); link->points[i].x += -xf + xt; } else { int to_move = link->npoints - (i + 1); assert(to_move >= 0); if (to_move > 0) { memmove(&link->points[i], &link->points[i + 1], to_move * sizeof(*link->points)); i--; } link->npoints--; } } if (!matched) { renderer_context.last_link_to_move = nlink; } } /* Don't move tags when removing links. */ if (yt < 0) return; matched = 0; tag = renderer_context.last_tag_to_move; while (list_has_next(part->document->tags, tag)) { tag = tag->next; if (tag->y == Y(yf)) { matched = 1; if (tag->x >= X(xf)) { tag->y = Y(yt); tag->x += -xf + xt; } } else if (!matched && tag->y > Y(yf)) { /* Fix for bug 479 (part two) */ matched = 1; } if (!matched) renderer_context.last_tag_to_move = tag; }}static inline voidcopy_chars(struct part *part, int x, int y, int width, struct screen_char *d){ assert(width > 0 && part && part->document && part->document->data); if_assert_failed return; if (realloc_line(part->document, Y(y), X(x) + width - 1)) return; copy_screen_chars(&POS(x, y), d, width);}static inline voidmove_chars(struct part *part, int x, int y, int nx, int ny){ assert(part && part->document && part->document->data); if_assert_failed return; if (LEN(y) - x <= 0) return; copy_chars(part, nx, ny, LEN(y) - x, &POS(x, y)); LINE(y).length = X(x); move_links(part, x, y, nx, ny);}static inline voidshift_chars(struct part *part, int y, int shift){ struct screen_char *a; int len; assert(part && part->document && part->document->data); if_assert_failed return; len = LEN(y); a = mem_alloc(len * sizeof(*a)); if (!a) return; copy_screen_chars(a, &POS(0, y), len); clear_hchars(part, 0, y, shift); copy_chars(part, shift, y, len, a); mem_free(a); move_links(part, 0, y, shift, y);}static inline voiddel_chars(struct part *part, int x, int y){ assert(part && part->document && part->document->data); if_assert_failed return; LINE(y).length = X(x); move_links(part, x, y, -1, -1);}#define overlap(x) int_max((x).width - (x).rightmargin, 0)static int inlinesplit_line_at(struct part *part, int width){ int tmp; int new_width = width + par_format.rightmargin; assert(part); if_assert_failed return 0; /* Make sure that we count the right margin to the total * actual box width. */ int_lower_bound(&part->box.width, new_width); if (part->document) { assert(part->document->data); if_assert_failed return 0; assertm(POS(width, part->cy).data == ' ', "bad split: %c", POS(width, part->cy).data); move_chars(part, width + 1, part->cy, par_format.leftmargin, part->cy + 1); del_chars(part, width, part->cy); } width++; /* Since we were using (x + 1) only later... */ tmp = part->spaces_len - width; if (tmp > 0) { /* 0 is possible and I'm paranoid ... --Zas */ memmove(part->spaces, part->spaces + width, tmp); } assert(tmp >= 0); if_assert_failed tmp = 0; memset(part->spaces + tmp, 0, width); if (par_format.leftmargin > 0) { tmp = part->spaces_len - par_format.leftmargin; assertm(tmp > 0, "part->spaces_len - par_format.leftmargin == %d", tmp); /* So tmp is zero, memmove() should survive that. Don't recover. */ memmove(part->spaces + par_format.leftmargin, part->spaces, tmp); } part->cy++; if (part->cx == width) { part->cx = -1; int_lower_bound(&part->box.height, part->cy); return 2; } else { part->cx -= width - par_format.leftmargin; int_lower_bound(&part->box.height, part->cy + 1); return 1; }}/* Here, we scan the line for a possible place where we could split it into two * (breaking it, because it is too long), if it is overlapping from the maximal * box width. *//* Returns 0 if there was found no spot suitable for breaking the line. * 1 if the line was split into two. * 2 if the (second) splitted line is blank (that is useful to determine * ie. if the next line_break() should really break the line; we don't * want to see any blank lines to pop up, do we?). */static intsplit_line(struct part *part){ int x; assert(part); if_assert_failed return 0; for (x = overlap(par_format); x >= par_format.leftmargin; x--) if (x < part->spaces_len && part->spaces[x]) return split_line_at(part, x); for (x = par_format.leftmargin; x < part->cx ; x++) if (x < part->spaces_len && part->spaces[x]) return split_line_at(part, x); /* Make sure that we count the right margin to the total * actual box width. */ int_lower_bound(&part->box.width, part->cx + par_format.rightmargin); return 0;}/* Insert @new_spaces spaces before the coordinates @x and @y, * adding those spaces to whatever link is at those coordinates. *//* TODO: Integrate with move_links. */static voidinsert_spaces_in_link(struct part *part, int x, int y, int new_spaces){ int i = part->document->nlinks; x = X(x); y = Y(y); while (i--) { struct link *link = &part->document->links[i]; int j = link->npoints; while (j-- > 1) { struct point *point = &link->points[j]; if (point->x != x || point->y != y) continue; if (!realloc_points(link, link->npoints + new_spaces)) return; link->npoints += new_spaces; point = &link->points[link->npoints - 1]; while (new_spaces--) { point->x = --x; point->y = y; point--; } return; } }}/* This function is very rare exemplary of clean and beautyful code here. * Please handle with care. --pasky */static voidjustify_line(struct part *part, int y){ struct screen_char *line; /* we save original line here */ int len; int pos; int *space_list; int spaces; assert(part && part->document && part->document->data); if_assert_failed return; len = LEN(y); assert(len > 0); if_assert_failed return; line = fmem_alloc(len * sizeof(*line)); if (!line) return; /* It may sometimes happen that the line is only one char long and that * char is space - then we're going to write to both [0] and [1], but * we allocated only one field. Thus, we've to do (len + 1). --pasky */ space_list = fmem_alloc((len + 1) * sizeof(*space_list)); if (!space_list) { fmem_free(line); return; } copy_screen_chars(line, &POS(0, y), len); /* Skip leading spaces */ spaces = 0; pos = 0; while (line[pos].data == ' ') pos++; /* Yes, this can be negative, we know. But we add one to it always * anyway, so it's ok. */ space_list[spaces++] = pos - 1; /* Count spaces */ for (; pos < len; pos++) if (line[pos].data == ' ') space_list[spaces++] = pos; space_list[spaces] = len; /* Realign line */ if (spaces > 1) { int insert = overlap(par_format) - len; int prev_end = 0; int word; clear_hchars(part, 0, y, overlap(par_format)); for (word = 0; word < spaces; word++) { /* We have to increase line length by 'insert' num. of * characters, so we move 'word'th word 'word_shift' * characters right. */ int word_start = space_list[word] + 1; int word_len = space_list[word + 1] - word_start; int word_shift; int new_start; int new_spaces; assert(word_len >= 0); if_assert_failed continue; if (!word_len) continue; word_shift = (word * insert) / (spaces - 1); new_start = word_start + word_shift; copy_chars(part, new_start, y, word_len, &line[word_start]); new_spaces = new_start - prev_end - 1; if (word && new_spaces) { move_links(part, prev_end + 1, y, new_start, y); insert_spaces_in_link(part, new_start, y, new_spaces); } prev_end = new_start + word_len; } } fmem_free(space_list); fmem_free(line);}static voidalign_line(struct part *part, int y, int last){ int shift; int len; assert(part && part->document && part->document->data); if_assert_failed return; len = LEN(y); if (!len || par_format.align == ALIGN_LEFT) return; if (par_format.align == ALIGN_JUSTIFY) { if (!last) justify_line(part, y); return; } shift = overlap(par_format) - len; if (par_format.align == ALIGN_CENTER) shift /= 2; if (shift > 0) shift_chars(part, y, shift);}static struct link *new_link(struct document *document, int link_number, unsigned char *name, int namelen){ struct link *link; assert(document); if_assert_failed return NULL; if (!ALIGN_LINK(&document->links, document->nlinks, document->nlinks + 1)) return NULL; link = &document->links[document->nlinks++]; link->number = link_number - 1; if (document->options.use_tabindex) link->number += format.tabindex; link->accesskey = format.accesskey; link->title = null_or_stracpy(format.title); link->where_img = null_or_stracpy(format.image); if (!format.form) { link->target = null_or_stracpy(format.target); link->data.name = memacpy(name, namelen); /* if (strlen(url) > 4 && !strncasecmp(url, "MAP@", 4)) { */ if (format.link && ((format.link[0]|32) == 'm') && ((format.link[1]|32) == 'a') && ((format.link[2]|32) == 'p') && (format.link[3] == '@') && format.link[4]) { link->type = LINK_MAP; link->where = stracpy(format.link + 4); } else { link->type = LINK_HYPERTEXT; link->where = null_or_stracpy(format.link); } } else { struct form_control *fc = format.form; struct form *form; switch (fc->type) { case FC_TEXT: case FC_PASSWORD: case FC_FILE: link->type = LINK_FIELD; break; case FC_TEXTAREA: link->type = LINK_AREA; break; case FC_CHECKBOX: case FC_RADIO: link->type = LINK_CHECKBOX; break; case FC_SELECT: link->type = LINK_SELECT; break; 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; link->event_hooks = mem_calloc(1, sizeof(*link->event_hooks)); if (link->event_hooks) { init_list(*link->event_hooks);#define add_evhook(list_, type_, src_) \do { \ struct script_event_hook *evhook = mem_calloc(1, sizeof(*evhook)); \ \ if (evhook) { \ evhook->type = type_; \ evhook->src = stracpy(src_); \ add_to_list(*list_, evhook); \ } \} while (0) if (format.onclick) add_evhook(link->event_hooks, SEVHOOK_ONCLICK, format.onclick); if (format.ondblclick) add_evhook(link->event_hooks, SEVHOOK_ONDBLCLICK, format.ondblclick); if (format.onmouseover) add_evhook(link->event_hooks, SEVHOOK_ONMOUSEOVER, format.onmouseover); if (format.onhover) add_evhook(link->event_hooks, SEVHOOK_ONHOVER, format.onhover); if (format.onfocus) add_evhook(link->event_hooks, SEVHOOK_ONFOCUS, format.onfocus); if (format.onmouseout) add_evhook(link->event_hooks, SEVHOOK_ONMOUSEOUT, format.onmouseout); if (format.onblur) add_evhook(link->event_hooks, SEVHOOK_ONBLUR, format.onblur);#undef add_evhook } 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -