From c90b2253e40cc5646319bcc79e69b1dc7154db92 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 12 Nov 2014 15:38:45 +0100 Subject: html: Line breaking and font styling. --- source/html/css-apply.c | 33 +++++++-------- source/html/font.c | 52 +++++++++++------------- source/html/layout.c | 106 ++++++++++++++++++++++++++++++++++++------------ 3 files changed, 118 insertions(+), 73 deletions(-) (limited to 'source/html') diff --git a/source/html/css-apply.c b/source/html/css-apply.c index 325b0dab..63a4941c 100644 --- a/source/html/css-apply.c +++ b/source/html/css-apply.c @@ -767,6 +767,17 @@ from_number(struct number number, float em, float width) } } +float +from_number_scale(struct number number, float scale, float em, float width) +{ + switch (number.unit) { + default: + case N_NUMBER: return number.value * scale; + case N_SCALE: return number.value * em; + case N_PERCENT: return number.value * 0.01 * width; + } +} + int get_style_property_display(struct style *node) { @@ -811,7 +822,7 @@ default_computed_style(struct computed_style *style) } void -compute_style(struct computed_style *style, struct style *node) +compute_style(html_document *doc, struct computed_style *style, struct style *node) { struct value *value; @@ -879,20 +890,7 @@ compute_style(struct computed_style *style, struct style *node) const char *font_variant = get_style_property_string(node, "font-variant", "normal"); const char *font_style = get_style_property_string(node, "font-style", "normal"); const char *font_weight = get_style_property_string(node, "font-weight", "normal"); - - style->font_family = font_family; - - style->smallcaps = 0; - if (!strcmp(font_variant, "small-caps")) - style->smallcaps = 1; - - style->italic = 0; - if (!strcmp(font_style, "italic") || !strcmp(font_style, "oblique")) - style->italic = 1; - - style->bold = 0; - if (!strcmp(font_weight, "bold") || !strcmp(font_weight, "bolder") || atoi(font_weight) > 400) - style->bold = 1; + style->font = html_load_font(doc, font_family, font_variant, font_style, font_weight); } } @@ -901,10 +899,7 @@ print_style(struct computed_style *style) { printf("style {\n"); printf("\tfont-size = %g%c;\n", style->font_size.value, style->font_size.unit); - printf("\tfont = %s", style->font_family); - printf(" %s", style->bold ? "bold" : "normal"); - printf(" %s", style->italic ? "italic" : "normal"); - printf(" %s;\n", style->smallcaps ? "small-caps" : "normal"); + printf("\tfont = %s;\n", style->font->name); printf("\tline-height = %g%c;\n", style->line_height.value, style->line_height.unit); printf("\ttext-indent = %g%c;\n", style->text_indent.value, style->text_indent.unit); printf("\ttext-align = %d;\n", style->text_align); diff --git a/source/html/font.c b/source/html/font.c index 102bb8df..9c408367 100644 --- a/source/html/font.c +++ b/source/html/font.c @@ -1,40 +1,36 @@ #include "mupdf/html.h" -#include "mupdf/pdf.h" /* for pdf_lookup_substitute_font */ +#include "mupdf/pdf.h" /* for pdf_lookup_builtin_font */ -#include -#include FT_FREETYPE_H - -static int ft_is_bold(FT_Face face) -{ - return face->style_flags & FT_STYLE_FLAG_BOLD; -} - -static int ft_is_italic(FT_Face face) -{ - return face->style_flags & FT_STYLE_FLAG_ITALIC; -} +static const char *font_names[16] = { + "Times-Roman", "Times-Italic", "Times-Bold", "Times-BoldItalic", + "Helvetica", "Helvetica-Oblique", "Helvetica-Bold", "Helvetica-BoldOblique", + "Courier", "Courier-Oblique", "Courier-Bold", "Courier-BoldOblique", + "Courier", "Courier-Oblique", "Courier-Bold", "Courier-BoldOblique", +}; fz_font * -html_load_font(fz_context *ctx, +html_load_font(html_document *doc, const char *family, const char *variant, const char *style, const char *weight) { + fz_context *ctx = doc->ctx; unsigned char *data; unsigned int size; - fz_font *font; - - int is_bold = !strcmp(weight, "bold"); - int is_italic = !strcmp(style, "italic"); int is_mono = !strcmp(family, "monospace"); int is_sans = !strcmp(family, "sans-serif"); - - // TODO: keep a cache of loaded fonts - - data = pdf_lookup_substitute_font(is_mono, !is_sans, is_bold, is_italic, &size); - - font = fz_new_font_from_memory(ctx, family, data, size, 0, 1); - font->ft_bold = is_bold && !ft_is_bold(font->ft_face); - font->ft_italic = is_italic && !ft_is_italic(font->ft_face); - - return font; + int is_bold = !strcmp(weight, "bold") || !strcmp(weight, "bolder") || atoi(weight) > 400; + int is_italic = !strcmp(style, "italic") || !strcmp(style, "oblique"); + + int idx = is_mono * 8 + is_sans * 4 + is_bold * 2 + is_italic; + if (!doc->fonts[idx]) + { + data = pdf_lookup_builtin_font(font_names[idx], &size); + if (!data) { + printf("data=%p idx=%d s=%s\n", data, idx, font_names[idx]); + abort(); + } + doc->fonts[idx] = fz_new_font_from_memory(ctx, font_names[idx], data, size, 0, 1); + } + + return doc->fonts[idx]; } diff --git a/source/html/layout.c b/source/html/layout.c index 6d9753ba..d07b2dab 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -30,8 +30,6 @@ static const char *default_css = "center{text-align:center}" "svg{display:none}"; -static fz_font *font = NULL; - enum { BOX_BLOCK, /* block-level: contains block and flow boxes */ @@ -218,8 +216,9 @@ static void insert_inline_box(fz_context *ctx, struct box *box, struct box *top) } } -static void generate_boxes(fz_context *ctx, fz_xml *node, struct box *top, struct rule *rule, struct style *up_style) +static void generate_boxes(html_document *doc, fz_xml *node, struct box *top, struct rule *rule, struct style *up_style) { + fz_context *ctx = doc->ctx; struct style style; struct box *box; int display; @@ -257,7 +256,7 @@ static void generate_boxes(fz_context *ctx, fz_xml *node, struct box *top, struc } if (fz_xml_down(node)) - generate_boxes(ctx, fz_xml_down(node), box, rule, &style); + generate_boxes(doc, fz_xml_down(node), box, rule, &style); // TODO: remove empty flow boxes } @@ -268,60 +267,117 @@ static void generate_boxes(fz_context *ctx, fz_xml *node, struct box *top, struc generate_text(ctx, box, fz_xml_text(node)); } - compute_style(&box->style, &style); + compute_style(doc, &box->style, &style); node = fz_xml_next(node); } } -static void layout_text(fz_context *ctx, struct flow *node, struct box *top, float em) +static void measure_word(fz_context *ctx, struct flow *node, float em) { const char *s; int c, g; float w; em = from_number(node->style->font_size, em, em); - node->x = top->x + top->w; - node->y = top->y; - node->h = em; + node->x = 0; + node->y = 0; + node->h = from_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, font, c); - w += fz_advance_glyph(ctx, font, g) * em; + g = fz_encode_character(ctx, node->style->font, c); + w += fz_advance_glyph(ctx, node->style->font, g) * em; } node->w = w; node->em = em; } +static float layout_line(fz_context *ctx, float indent, struct flow *node, struct flow *end, struct box *box) +{ + float x = box->x + indent; + float y = box->y + box->h; + float h = 0; + + while (node != end) + { + node->x = x; + node->y = y; + x += node->w; + if (node->h > h) + h = node->h; + node = node->next; + } + + return h; +} + static void layout_flow(fz_context *ctx, struct box *box, struct box *top, float em) { - struct flow *node; + struct flow *node, *first_word, *last_glue; + float line_w, line_h; + float indent; em = from_number(box->style.font_size, em, em); + indent = from_number(top->style.text_indent, em, top->w); + box->x = top->x; box->y = top->y + top->h; - box->h = 0; box->w = 0; + box->h = 0; + first_word = box->flow_head; + last_glue = NULL; + line_w = indent; for (node = box->flow_head; node; node = node->next) { - layout_text(ctx, node, box, em); - if (node->h > box->h) - box->h = node->h; - box->w += node->w; + if (node->type == FLOW_GLUE) + last_glue = node; + + measure_word(ctx, node, em); + if (last_glue && line_w + node->w > top->w) + { + line_h = layout_line(ctx, indent, first_word, last_glue, box); + if (line_w > box->w) + box->w = line_w; + box->h += line_h; + + if (node == last_glue && node->next) + { + node = node->next; + measure_word(ctx, node, em); + } + + first_word = node; + last_glue = NULL; + line_w = node->w; + indent = 0; + } + else if (line_w + node->w > top->w) + { + printf("WARNING: line overflow! (%s)\n", node->text); + line_w += node->w; + } + else + { + line_w += node->w; + } } + + line_h = layout_line(ctx, indent, first_word, NULL, box); + if (line_w > box->w) + box->w = line_w; + box->h += line_h; } static void layout_block(fz_context *ctx, struct box *box, struct box *top, float em, float top_collapse_margin) { struct box *child; float box_collapse_margin; - float bottom; em = from_number(box->style.font_size, em, em); @@ -422,8 +478,8 @@ static void print_box(fz_context *ctx, struct box *box, int level) printf("\n"); if (box->down) print_box(ctx, box->down, level + 1); - if (box->flow_head) - print_flow(ctx, box->flow_head, level + 1); +// if (box->flow_head) +// print_flow(ctx, box->flow_head, level + 1); box = box->next; } } @@ -446,7 +502,7 @@ draw_flow_box(fz_context *ctx, struct box *box, fz_device *dev, const fz_matrix if (node->type == FLOW_WORD) { fz_scale(&trm, node->em, -node->em); - text = fz_new_text(ctx, font, &trm, 0); + text = fz_new_text(ctx, node->style->font, &trm, 0); x = node->x; y = node->y + node->em * 0.8; @@ -454,9 +510,9 @@ draw_flow_box(fz_context *ctx, struct box *box, fz_device *dev, const fz_matrix while (*s) { s += fz_chartorune(&c, s); - g = fz_encode_character(ctx, font, c); + g = fz_encode_character(ctx, node->style->font, c); fz_add_text(ctx, text, g, c, x, y); - x += fz_advance_glyph(ctx, font, g) * node->em; + x += fz_advance_glyph(ctx, node->style->font, g) * node->em; } fz_fill_text(dev, text, ctm, fz_device_gray(ctx), black, 1); @@ -586,8 +642,6 @@ html_layout_document(html_document *doc, float w, float h) else strcpy(dirname, "./"); #endif - font = html_load_font(doc->ctx, "serif", "normal", "normal", "normal"); - css = fz_parse_css(doc->ctx, NULL, default_css); css = load_css(doc->ctx, css, doc->xml); @@ -602,7 +656,7 @@ html_layout_document(html_document *doc, float w, float h) win_box->w = w; win_box->h = 0; - generate_boxes(doc->ctx, doc->xml, root_box, css, &style); + generate_boxes(doc, doc->xml, root_box, css, &style); layout_block(doc->ctx, root_box, win_box, 12, 0); -- cgit v1.2.3