diff options
Diffstat (limited to 'source/html')
-rw-r--r-- | source/html/css-apply.c | 103 | ||||
-rw-r--r-- | source/html/html-layout.c | 72 |
2 files changed, 143 insertions, 32 deletions
diff --git a/source/html/css-apply.c b/source/html/css-apply.c index 42e247e1..98818239 100644 --- a/source/html/css-apply.c +++ b/source/html/css-apply.c @@ -64,6 +64,29 @@ static const char *color_kw[] = { "yellow", }; +static const char *list_style_type_kw[] = { + "armenian", + "circle", + "decimal", + "decimal-leading-zero", + "disc", + "georgian", + "lower-alpha", + "lower-greek", + "lower-latin", + "lower-roman", + "none", + "square", + "upper-alpha", + "upper-latin", + "upper-roman", +}; + +static const char *list_style_position_kw[] = { + "inside", + "outside", +}; + static int keyword_in_list(const char *name, const char **list, int n) { @@ -418,6 +441,26 @@ add_shorthand_border(fz_css_match *match, fz_css_value *value, int spec) } static void +add_shorthand_list_style(fz_css_match *match, fz_css_value *value, int spec) +{ + while (value) + { + if (value->type == CSS_KEYWORD) + { + if (keyword_in_list(value->data, list_style_type_kw, nelem(list_style_type_kw))) + { + add_property(match, "list-style-type", value, spec); + } + else if (keyword_in_list(value->data, list_style_position_kw, nelem(list_style_position_kw))) + { + add_property(match, "list-style-position", value, spec); + } + } + value = value->next; + } +} + +static void add_property(fz_css_match *match, const char *name, fz_css_value *value, int spec) { int i; @@ -442,6 +485,11 @@ add_property(fz_css_match *match, const char *name, fz_css_value *value, int spe add_shorthand_border(match, value, spec); return; } + if (!strcmp(name, "list-style")) + { + add_shorthand_list_style(match, value, spec); + return; + } /* shorthand expansions: */ /* TODO: border-color */ @@ -751,10 +799,10 @@ white_space_from_property(fz_css_match *match) if (value) { if (!strcmp(value->data, "normal")) return WS_NORMAL; - if (!strcmp(value->data, "pre")) return WS_PRE; - if (!strcmp(value->data, "nowrap")) return WS_NOWRAP; - if (!strcmp(value->data, "pre-wrap")) return WS_PRE_WRAP; - if (!strcmp(value->data, "pre-line")) return WS_PRE_LINE; + else if (!strcmp(value->data, "pre")) return WS_PRE; + else if (!strcmp(value->data, "nowrap")) return WS_NOWRAP; + else if (!strcmp(value->data, "pre-wrap")) return WS_PRE_WRAP; + else if (!strcmp(value->data, "pre-line")) return WS_PRE_LINE; } return WS_NORMAL; } @@ -766,6 +814,7 @@ fz_default_css_style(fz_context *ctx, fz_css_style *style) style->text_align = TA_LEFT; style->vertical_align = VA_BASELINE; style->white_space = WS_NORMAL; + style->list_style_type = LST_DISC; style->font_size = make_number(1, N_SCALE); } @@ -784,29 +833,20 @@ fz_apply_css_style(fz_context *ctx, fz_html_font_set *set, fz_css_style *style, value = value_from_property(match, "text-align"); if (value) { - if (!strcmp(value->data, "left")) - style->text_align = TA_LEFT; - if (!strcmp(value->data, "right")) - style->text_align = TA_RIGHT; - if (!strcmp(value->data, "center")) - style->text_align = TA_CENTER; - if (!strcmp(value->data, "justify")) - style->text_align = TA_JUSTIFY; + if (!strcmp(value->data, "left")) style->text_align = TA_LEFT; + else if (!strcmp(value->data, "right")) style->text_align = TA_RIGHT; + else if (!strcmp(value->data, "center")) style->text_align = TA_CENTER; + else if (!strcmp(value->data, "justify")) style->text_align = TA_JUSTIFY; } value = value_from_property(match, "vertical-align"); if (value) { - if (!strcmp(value->data, "baseline")) - style->vertical_align = VA_BASELINE; - if (!strcmp(value->data, "sub")) - style->vertical_align = VA_SUB; - if (!strcmp(value->data, "super")) - style->vertical_align = VA_SUPER; - if (!strcmp(value->data, "top")) - style->vertical_align = VA_TOP; - if (!strcmp(value->data, "bottom")) - style->vertical_align = VA_BOTTOM; + if (!strcmp(value->data, "baseline")) style->vertical_align = VA_BASELINE; + else if (!strcmp(value->data, "sub")) style->vertical_align = VA_SUB; + else if (!strcmp(value->data, "super")) style->vertical_align = VA_SUPER; + else if (!strcmp(value->data, "top")) style->vertical_align = VA_TOP; + else if (!strcmp(value->data, "bottom")) style->vertical_align = VA_BOTTOM; } value = value_from_property(match, "font-size"); @@ -831,12 +871,19 @@ fz_apply_css_style(fz_context *ctx, fz_html_font_set *set, fz_css_style *style, value = value_from_property(match, "border-style"); if (value) { - if (!strcmp(value->data, "none")) - style->border_style = BS_NONE; - if (!strcmp(value->data, "hidden")) - style->border_style = BS_NONE; - if (!strcmp(value->data, "solid")) - style->border_style = BS_SOLID; + if (!strcmp(value->data, "none")) style->border_style = BS_NONE; + else if (!strcmp(value->data, "hidden")) style->border_style = BS_NONE; + else if (!strcmp(value->data, "solid")) style->border_style = BS_SOLID; + } + + value = value_from_property(match, "list-style-type"); + if (value) + { + if (!strcmp(value->data, "none")) style->list_style_type = LST_NONE; + else if (!strcmp(value->data, "disc")) style->list_style_type = LST_DISC; + else if (!strcmp(value->data, "circle")) style->list_style_type = LST_CIRCLE; + else if (!strcmp(value->data, "square")) style->list_style_type = LST_SQUARE; + else if (!strcmp(value->data, "decimal")) style->list_style_type = LST_DECIMAL; } style->line_height = number_from_property(match, "line-height", 1.2f, N_SCALE); diff --git a/source/html/html-layout.c b/source/html/html-layout.c index 157c8685..7231205f 100644 --- a/source/html/html-layout.c +++ b/source/html/html-layout.c @@ -271,7 +271,7 @@ static void insert_inline_box(fz_context *ctx, fz_html *box, fz_html *top) } static void generate_boxes(fz_context *ctx, fz_html_font_set *set, fz_archive *zip, const char *base_uri, - fz_xml *node, fz_html *top, fz_css_rule *rule, fz_css_match *up_match) + fz_xml *node, fz_html *top, fz_css_rule *rule, fz_css_match *up_match, int list_counter) { fz_css_match match; fz_html *box; @@ -321,6 +321,7 @@ static void generate_boxes(fz_context *ctx, fz_html_font_set *set, fz_archive *z else if (display == DIS_LIST_ITEM) { top = insert_block_box(ctx, box, top); + box->list_item = ++list_counter; } else if (display == DIS_INLINE) { @@ -333,7 +334,12 @@ static void generate_boxes(fz_context *ctx, fz_html_font_set *set, fz_archive *z } if (fz_xml_down(node)) - generate_boxes(ctx, set, zip, base_uri, fz_xml_down(node), box, rule, &match); + { + int child_counter = list_counter; + if (!strcmp(tag, "ul") || !strcmp(tag, "ol")) + child_counter = 0; + generate_boxes(ctx, set, zip, base_uri, fz_xml_down(node), box, rule, &match, child_counter); + } // TODO: remove empty flow boxes } @@ -602,7 +608,7 @@ static void layout_block(fz_context *ctx, fz_html *box, fz_html *top, float em, float *border = box->border; float *padding = box->padding; - em = fz_from_css_number(box->style.font_size, em, em); + em = box->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); @@ -754,6 +760,59 @@ static void draw_rect(fz_context *ctx, fz_device *dev, const fz_matrix *ctm, flo fz_drop_path(ctx, path); } +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_text *text; + fz_matrix trm; + float x, y, w, baseline; + float color[3]; + const char *s, *p; + char buf[40]; + int c, g; + + fz_scale(&trm, box->em, -box->em); + text = fz_new_text(ctx, box->style.font, &trm, 0); + baseline = box->em * 0.8 + (box->h - box->em) / 2; + + switch (box->style.list_style_type) + { + default: + case LST_DISC: p = "\342\227\217 "; break; /* U+25CF BLACK CIRCLE */ + case LST_CIRCLE: p = "\342\227\213 "; break; /* U+25CB WHITE CIRCLE */ + case LST_SQUARE: p = "\342\226\240 "; break; /* U+25A0 BLACK SQUARE */ + case LST_DECIMAL: p = buf; fz_snprintf(buf, sizeof buf, "%d. ", n); break; + case LST_NONE: p = ""; break; + } + + s = p; + w = 0; + while (*s) + { + s += fz_chartorune(&c, s); + g = fz_encode_character(ctx, box->style.font, c); + w += fz_advance_glyph(ctx, box->style.font, g) * box->em; + } + + s = p; + x = box->x - box->padding[L] - box->border[L] - box->margin[L] - w; + y = box->y + baseline; + while (*s) + { + s += fz_chartorune(&c, s); + g = fz_encode_character(ctx, box->style.font, c); + fz_add_text(ctx, text, g, c, x, y); + x += fz_advance_glyph(ctx, box->style.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 draw_block_box(fz_context *ctx, fz_html *box, float page_top, float page_bot, fz_device *dev, const fz_matrix *ctm) { float x0, y0, x1, y1; @@ -798,6 +857,11 @@ static void draw_block_box(fz_context *ctx, fz_html *box, float page_top, float draw_rect(ctx, dev, ctm, color, x1, y0 - border[T], x1 + border[R], y1 + border[B]); } + if (box->list_item) + { + draw_list_mark(ctx, box, page_top, page_bot, dev, ctm, box->list_item); + } + for (box = box->down; box; box = box->next) { switch (box->type) @@ -927,7 +991,7 @@ fz_parse_html(fz_context *ctx, fz_html_font_set *set, fz_archive *zip, const cha match.up = NULL; match.count = 0; - generate_boxes(ctx, set, zip, base_uri, xml, box, css, &match); + generate_boxes(ctx, set, zip, base_uri, xml, box, css, &match, 0); fz_drop_css(ctx, css); fz_drop_xml(ctx, xml); |