Example #1
0
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;
}
Example #2
0
static void
htdoc_layout(fz_context *ctx, fz_document *doc_, float w, float h, float em)
{
	html_document *doc = (html_document*)doc_;

	if (doc->box)
	{
		doc->page_margin[T] = fz_from_css_number(doc->box->style.margin[T], em, em);
		doc->page_margin[B] = fz_from_css_number(doc->box->style.margin[B], em, em);
		doc->page_margin[L] = fz_from_css_number(doc->box->style.margin[L], em, em);
		doc->page_margin[R] = fz_from_css_number(doc->box->style.margin[R], em, em);
	}

	doc->page_w = w - doc->page_margin[L] - doc->page_margin[R];
	doc->page_h = h - doc->page_margin[T] - doc->page_margin[B];
	doc->em = em;

	fz_layout_html(ctx, doc->box, doc->page_w, doc->page_h, doc->em);
}
Example #3
0
static void
epub_layout(fz_context *ctx, fz_document *doc_, float w, float h, float em)
{
	epub_document *doc = (epub_document*)doc_;
	epub_chapter *ch;

	printf("epub: laying out chapters.\n");
	for (ch = doc->spine; ch; ch = ch->next)
	{
		ch->em = em;
		ch->page_margin[T] = fz_from_css_number(ch->box->style.margin[T], em, em);
		ch->page_margin[B] = fz_from_css_number(ch->box->style.margin[B], em, em);
		ch->page_margin[L] = fz_from_css_number(ch->box->style.margin[L], em, em);
		ch->page_margin[R] = fz_from_css_number(ch->box->style.margin[R], em, em);
		ch->page_w = w - ch->page_margin[L] - ch->page_margin[R];
		ch->page_h = h - ch->page_margin[T] - ch->page_margin[B];
		fz_layout_html(ctx, ch->box, ch->page_w, ch->page_h, ch->em);
	}
	printf("epub: done.\n");
}
Example #4
0
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;
}
Example #5
0
static void layout_flow(fz_context *ctx, fz_html *box, fz_html *top, float em, float page_h)
{
    fz_html_flow *node, *line, *mark;
    float line_w;
    float indent;
    int align;
    int line_align;

    em = fz_from_css_number(box->style.font_size, em, em);
    indent = box->is_first_flow ? fz_from_css_number(top->style.text_indent, em, top->w) : 0;
    align = top->style.text_align;

    if (box->flow_dir == BIDI_RIGHT_TO_LEFT)
    {
        if (align == TA_LEFT)
            align = TA_RIGHT;
        else if (align == TA_RIGHT)
            align = TA_LEFT;
    }

    box->x = top->x;
    box->y = top->y + top->h;
    box->w = top->w;
    box->h = 0;

    if (!box->flow_head)
        return;

    for (node = box->flow_head; node; node = node->next)
    {
        if (node->type == FLOW_IMAGE)
        {
            float w = 0, h = 0;
            find_accumulated_margins(ctx, box, &w, &h);
            measure_image(ctx, node, top->w - w, page_h - h);
        }
        else
        {
            measure_word(ctx, node, em);
        }
    }

    /* start by skipping whitespace (and newline) at the beginning of tags */
    node = box->flow_head;
    if (node->type == FLOW_BREAK)
        node = node->next;
    while (node && node->type == FLOW_GLUE)
        node = node->next;

    mark = NULL;
    line = node;
    line_w = indent;

    while (node)
    {
        switch (node->type)
        {
        case FLOW_WORD:
            break;
        case FLOW_IMAGE:
            /* TODO: break before/after image */
            mark = node;
            break;
        case FLOW_GLUE:
            mark = node;
            break;
        case FLOW_BREAK:
            line_align = align == TA_JUSTIFY ? TA_LEFT : align;
            flush_line(ctx, box, page_h, top->w, line_align, indent, line, node);
            indent = 0;
            line = node->next;
            line_w = 0;
            mark = NULL;
            break;
        }

        if (mark && line_w + node->w > top->w)
        {
            flush_line(ctx, box, page_h, top->w, align, indent, line, mark);
            indent = 0;
            node = mark;
            while (node && node->type == FLOW_GLUE)
                node = node->next;
            line = node;
            line_w = 0;
            mark = NULL;
        }

        if (node)
        {
            line_w += node->w;
            node = node->next;
        }
    }

    if (line)
    {
        line_align = align == TA_JUSTIFY ? TA_LEFT : align;
        flush_line(ctx, box, page_h, top->w, line_align, indent, line, NULL);
    }
}
Example #6
0
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;
		}
	}
}
Example #7
0
static void layout_flow(fz_context *ctx, fz_html *box, fz_html *top, float em, float page_h)
{
	fz_html_flow *node, *line_start, *word_start, *word_end, *line_end;
	float glue_w;
	float word_w;
	float line_w;
	float indent;
	float avail, line_h;
	float baseline;
	int align;

	em = fz_from_css_number(box->style.font_size, em, em);
	indent = box->is_first_flow ? fz_from_css_number(top->style.text_indent, em, top->w) : 0;
	align = top->style.text_align;

	box->x = top->x;
	box->y = top->y + top->h;
	box->w = top->w;
	box->h = 0;

	if (!box->flow_head)
		return;

	for (node = box->flow_head; node; node = node->next)
		if (node->type == FLOW_IMAGE)
			measure_image(ctx, node, top->w, page_h);
		else
			measure_word(ctx, node, em);

	line_start = find_next_word(box->flow_head, &glue_w);
	line_end = NULL;

	line_w = indent;
	word_w = 0;
	word_start = line_start;
	while (word_start)
	{
		word_end = find_next_glue(word_start, &word_w);
		if (line_w + word_w <= top->w)
		{
			line_w += word_w;
			glue_w = 0;
			line_end = word_end;
			word_start = find_next_word(word_end, &glue_w);
			word_w = glue_w;
		}
		else
		{
			avail = page_h - fmodf(box->y + box->h, page_h);
			line_h = measure_line(line_start, line_end, &baseline);
			if (line_h > avail)
				box->h += avail;
			layout_line(ctx, indent, top->w, line_w, align, line_start, line_end, box, baseline);
			box->h += line_h;
			word_start = find_next_word(line_end, &glue_w);
			line_start = word_start;
			line_end = NULL;
			indent = 0;
			line_w = 0;
			word_w = 0;
		}
	}

	/* don't justify the last line of a paragraph */
	if (align == TA_JUSTIFY)
		align = TA_LEFT;

	if (line_start)
	{
		avail = page_h - fmodf(box->y + box->h, page_h);
		line_h = measure_line(line_start, line_end, &baseline);
		if (line_h > avail)
			box->h += avail;
		layout_line(ctx, indent, top->w, line_w, align, line_start, line_end, box, baseline);
		box->h += line_h;
	}
}
Example #8
0
static fz_css_color
color_from_value(fz_css_value *value, fz_css_color initial)
{
	if (!value)
		return initial;

	if (value->type == CSS_HASH)
	{
		int r, g, b;
		size_t n = strlen(value->data);
		if (n == 3)
		{
			r = tohex(value->data[0]) * 16 + tohex(value->data[0]);
			g = tohex(value->data[1]) * 16 + tohex(value->data[1]);
			b = tohex(value->data[2]) * 16 + tohex(value->data[2]);
		}
		else if (n == 6)
		{
			r = tohex(value->data[0]) * 16 + tohex(value->data[1]);
			g = tohex(value->data[2]) * 16 + tohex(value->data[3]);
			b = tohex(value->data[4]) * 16 + tohex(value->data[5]);
		}
		else
		{
			r = g = b = 0;
		}
		return make_color(r, g, b, 255);
	}

	if (value->type == '(' && !strcmp(value->data, "rgb"))
	{
		fz_css_value *vr, *vg, *vb;
		int r, g, b;
		vr = value->args;
		vg = vr && vr->next ? vr->next->next : NULL; /* skip the ',' nodes */
		vb = vg && vg->next ? vg->next->next : NULL; /* skip the ',' nodes */
		r = fz_from_css_number(number_from_value(vr, 0, N_NUMBER), 255, 255);
		g = fz_from_css_number(number_from_value(vg, 0, N_NUMBER), 255, 255);
		b = fz_from_css_number(number_from_value(vb, 0, N_NUMBER), 255, 255);
		return make_color(r, g, b, 255);
	}

	if (value->type == CSS_KEYWORD)
	{
		if (!strcmp(value->data, "transparent"))
			return make_color(0, 0, 0, 0);
		if (!strcmp(value->data, "maroon"))
			return make_color(0x80, 0x00, 0x00, 255);
		if (!strcmp(value->data, "red"))
			return make_color(0xFF, 0x00, 0x00, 255);
		if (!strcmp(value->data, "orange"))
			return make_color(0xFF, 0xA5, 0x00, 255);
		if (!strcmp(value->data, "yellow"))
			return make_color(0xFF, 0xFF, 0x00, 255);
		if (!strcmp(value->data, "olive"))
			return make_color(0x80, 0x80, 0x00, 255);
		if (!strcmp(value->data, "purple"))
			return make_color(0x80, 0x00, 0x80, 255);
		if (!strcmp(value->data, "fuchsia"))
			return make_color(0xFF, 0x00, 0xFF, 255);
		if (!strcmp(value->data, "white"))
			return make_color(0xFF, 0xFF, 0xFF, 255);
		if (!strcmp(value->data, "lime"))
			return make_color(0x00, 0xFF, 0x00, 255);
		if (!strcmp(value->data, "green"))
			return make_color(0x00, 0x80, 0x00, 255);
		if (!strcmp(value->data, "navy"))
			return make_color(0x00, 0x00, 0x80, 255);
		if (!strcmp(value->data, "blue"))
			return make_color(0x00, 0x00, 0xFF, 255);
		if (!strcmp(value->data, "aqua"))
			return make_color(0x00, 0xFF, 0xFF, 255);
		if (!strcmp(value->data, "teal"))
			return make_color(0x00, 0x80, 0x80, 255);
		if (!strcmp(value->data, "black"))
			return make_color(0x00, 0x00, 0x00, 255);
		if (!strcmp(value->data, "silver"))
			return make_color(0xC0, 0xC0, 0xC0, 255);
		if (!strcmp(value->data, "gray"))
			return make_color(0x80, 0x80, 0x80, 255);
		return make_color(0, 0, 0, 255);
	}
	return initial;
}