static void measure_word(fz_context *ctx, fz_html_flow *node, float em) { const char *s; int c, g; float w; em = fz_from_css_number(node->style->font_size, em, em); node->x = 0; node->y = 0; node->h = fz_from_css_number_scale(node->style->line_height, em, em, em); w = 0; s = node->text; while (*s) { s += fz_chartorune(&c, s); g = fz_encode_character(ctx, node->style->font, c); if (g) { w += fz_advance_glyph(ctx, node->style->font, g) * em; } else { g = fz_encode_character(ctx, node->style->fallback, c); w += fz_advance_glyph(ctx, node->style->fallback, g) * em; } } node->w = w; node->em = em; }
static float layout_block(fz_context *ctx, fz_html *box, fz_html *top, float em, float page_h, float vertical) { fz_html *child; int first; fz_css_style *style = &box->style; float *margin = box->margin; float *border = box->border; float *padding = box->padding; em = box->em = fz_from_css_number(style->font_size, em, em); margin[0] = fz_from_css_number(style->margin[0], em, top->w); margin[1] = fz_from_css_number(style->margin[1], em, top->w); margin[2] = fz_from_css_number(style->margin[2], em, top->w); margin[3] = fz_from_css_number(style->margin[3], em, top->w); padding[0] = fz_from_css_number(style->padding[0], em, top->w); padding[1] = fz_from_css_number(style->padding[1], em, top->w); padding[2] = fz_from_css_number(style->padding[2], em, top->w); padding[3] = fz_from_css_number(style->padding[3], em, top->w); border[0] = style->border_style[0] ? fz_from_css_number(style->border_width[0], em, top->w) : 0; border[1] = style->border_style[1] ? fz_from_css_number(style->border_width[1], em, top->w) : 0; border[2] = style->border_style[2] ? fz_from_css_number(style->border_width[2], em, top->w) : 0; border[3] = style->border_style[3] ? fz_from_css_number(style->border_width[3], em, top->w) : 0; box->x = top->x + margin[L] + border[L] + padding[L]; box->w = top->w - (margin[L] + margin[R] + border[L] + border[R] + padding[L] + padding[R]); if (margin[T] > vertical) margin[T] -= vertical; else margin[T] = 0; if (padding[T] == 0 && border[T] == 0) vertical += margin[T]; else vertical = 0; box->y = top->y + top->h + margin[T] + border[T] + padding[T]; box->h = 0; first = 1; for (child = box->down; child; child = child->next) { if (child->type == BOX_BLOCK) { vertical = layout_block(ctx, child, box, em, page_h, vertical); if (first) { /* move collapsed parent/child top margins to parent */ margin[T] += child->margin[T]; box->y += child->margin[T]; child->margin[T] = 0; first = 0; } box->h += child->h + child->padding[T] + child->padding[B] + child->border[T] + child->border[B] + child->margin[T] + child->margin[B]; } else if (child->type == BOX_BREAK) { box->h += fz_from_css_number_scale(style->line_height, em, em, em); vertical = 0; first = 0; } else if (child->type == BOX_FLOW) { layout_flow(ctx, child, box, em, page_h); if (child->h > 0) { box->h += child->h; vertical = 0; first = 0; } } } /* reserve space for the list mark */ if (box->list_item && box->h == 0) { box->h += fz_from_css_number_scale(style->line_height, em, em, em); vertical = 0; } if (box->h == 0) { if (margin[B] > vertical) margin[B] -= vertical; else margin[B] = 0; } else { box->h -= vertical; vertical = fz_max(margin[B], vertical); margin[B] = vertical; } return vertical; }
static void draw_list_mark(fz_context *ctx, fz_html *box, float page_top, float page_bot, fz_device *dev, const fz_matrix *ctm, int n) { fz_font *font; fz_text *text; fz_matrix trm; fz_html_flow *line; float y, w; float color[3]; const char *s; char buf[40]; int c, g; fz_scale(&trm, box->em, -box->em); text = fz_new_text(ctx); line = find_list_mark_anchor(ctx, box); if (line) { y = line->y; } else { float h = fz_from_css_number_scale(box->style.line_height, box->em, box->em, box->em); float a = box->em * 0.8; float d = box->em * 0.2; if (a + d > h) h = a + d; y = box->y + a + (h - a - d) / 2; } if (y > page_bot || y < page_top) return; format_list_number(ctx, box->style.list_style_type, n, buf, sizeof buf); s = buf; w = 0; while (*s) { s += fz_chartorune(&c, s); g = fz_encode_character_with_fallback(ctx, box->style.font, c, UCDN_SCRIPT_LATIN, &font); w += fz_advance_glyph(ctx, font, g) * box->em; } s = buf; trm.e = box->x - w; trm.f = y; while (*s) { s += fz_chartorune(&c, s); g = fz_encode_character_with_fallback(ctx, box->style.font, c, UCDN_SCRIPT_LATIN, &font); fz_add_text(ctx, text, font, 0, &trm, g, c); trm.e += fz_advance_glyph(ctx, font, g) * box->em; } color[0] = box->style.color.r / 255.0f; color[1] = box->style.color.g / 255.0f; color[2] = box->style.color.b / 255.0f; fz_fill_text(ctx, dev, text, ctm, fz_device_rgb(ctx), color, 1); fz_drop_text(ctx, text); }
static void layout_block(fz_context *ctx, fz_html *box, fz_html *top, float em, float top_collapse_margin, float page_h) { fz_html *child; float box_collapse_margin; int prev_br; float *margin = box->margin; float *border = box->border; float *padding = box->padding; em = fz_from_css_number(box->style.font_size, em, em); margin[0] = fz_from_css_number(box->style.margin[0], em, top->w); margin[1] = fz_from_css_number(box->style.margin[1], em, top->w); margin[2] = fz_from_css_number(box->style.margin[2], em, top->w); margin[3] = fz_from_css_number(box->style.margin[3], em, top->w); padding[0] = fz_from_css_number(box->style.padding[0], em, top->w); padding[1] = fz_from_css_number(box->style.padding[1], em, top->w); padding[2] = fz_from_css_number(box->style.padding[2], em, top->w); padding[3] = fz_from_css_number(box->style.padding[3], em, top->w); if (box->style.border_style) { border[0] = fz_from_css_number(box->style.border_width[0], em, top->w); border[1] = fz_from_css_number(box->style.border_width[1], em, top->w); border[2] = fz_from_css_number(box->style.border_width[2], em, top->w); border[3] = fz_from_css_number(box->style.border_width[3], em, top->w); } else border[0] = border[1] = border[2] = border[3] = 0; if (padding[T] == 0 && border[T] == 0) box_collapse_margin = margin[T]; else box_collapse_margin = 0; if (margin[T] > top_collapse_margin) margin[T] -= top_collapse_margin; else margin[T] = 0; box->x = top->x + margin[L] + border[L] + padding[L]; box->y = top->y + top->h + margin[T] + border[T] + padding[T]; box->w = top->w - (margin[L] + margin[R] + border[L] + border[R] + padding[L] + padding[R]); box->h = 0; prev_br = 0; for (child = box->down; child; child = child->next) { if (child->type == BOX_BLOCK) { layout_block(ctx, child, box, em, box_collapse_margin, page_h); box->h += child->h + child->padding[T] + child->padding[B] + child->border[T] + child->border[B] + child->margin[T] + child->margin[B]; box_collapse_margin = child->margin[B]; prev_br = 0; } else if (child->type == BOX_BREAK) { /* TODO: interaction with page breaks */ if (prev_br) box->h += fz_from_css_number_scale(box->style.line_height, em, em, em); prev_br = 1; } else if (child->type == BOX_FLOW) { layout_flow(ctx, child, box, em, page_h); if (child->h > 0) { box->h += child->h; box_collapse_margin = 0; prev_br = 0; } } } if (padding[B] == 0 && border[B] == 0) { if (margin[B] > 0) { box->h -= box_collapse_margin; if (margin[B] < box_collapse_margin) margin[B] = box_collapse_margin; } } }