Exemple #1
0
static void svg_reset_text_stack(SVG_TextStack *st)
{
	while (gf_list_count(st->spans)) {
		GF_TextSpan *span = (GF_TextSpan*)gf_list_get(st->spans, 0);
		gf_list_rem(st->spans, 0);
		gf_font_manager_delete_span(NULL, span);
	}
}
Exemple #2
0
void text_clean_paths(GF_Compositor *compositor, TextStack *stack)
{
	GF_TextSpan *span;
	/*delete all path objects*/
	while (gf_list_count(stack->spans)) {
		span = (GF_TextSpan*) gf_list_get(stack->spans, 0);
		gf_list_rem(stack->spans, 0);
		gf_font_manager_delete_span(compositor->font_manager, span);
	}
	stack->bounds.width = stack->bounds.height = 0;
	drawable_reset_path(stack->graph);
}
Exemple #3
0
static void build_text_split(TextStack *st, M_Text *txt, GF_TraverseState *tr_state)
{
	u32 i, j, k, len, styles, idx, first_char;
	Bool split_words = 0;
	GF_Font *font;
	GF_TextSpan *tspan;
	GF_FontManager *ft_mgr = tr_state->visual->compositor->font_manager;
	Fixed fontSize, start_y;
	M_FontStyle *fs = (M_FontStyle *)txt->fontStyle;

	fontSize = FSSIZE;
	if (fontSize <= 0) {
		fontSize = INT2FIX(12);
		if (!tr_state->pixel_metrics) fontSize = gf_divfix(fontSize, tr_state->visual->compositor->output_width);
    }

	styles = 0;
	if (fs && fs->style.buffer) {
		if (strstr(fs->style.buffer, "BOLD") || strstr(fs->style.buffer, "bold")) styles |= GF_FONT_WEIGHT_BOLD;
		if (strstr(fs->style.buffer, "ITALIC") || strstr(fs->style.buffer, "italic")) styles |= GF_FONT_ITALIC;
		if (strstr(fs->style.buffer, "UNDERLINED") || strstr(fs->style.buffer, "underlined")) styles |= GF_FONT_UNDERLINED;
	}

	font = gf_font_manager_set_font(ft_mgr, fs ? fs->family.vals : NULL, fs ? fs->family.count : 0, styles);
	if (!font) return;

	st->ascent = (fontSize*font->ascent) / font->em_size;
	st->descent = -(fontSize*font->descent) / font->em_size;

	if (!strcmp(FSMINOR, "MIDDLE")) {
		start_y = (st->descent + st->ascent)/2;
	}
	else if (!strcmp(FSMINOR, "BEGIN")) {
		start_y = st->descent;
	}
	else if (!strcmp(FSMINOR, "END")) {
		start_y = st->descent + st->ascent;
	}
	else {
		start_y = st->ascent;
	}
	
	st->bounds.width = st->bounds.x = st->bounds.height = 0;
	idx = 0;
	split_words = (tr_state->text_split_mode==1) ? 1 : 0;

	for (i=0; i < txt->string.count; i++) {

		char *str = txt->string.vals[i];
		if (!str || !strlen(str)) continue;

		tspan = gf_font_manager_create_span(ft_mgr, font, str, fontSize, 0, 0, 0, NULL, 0, styles, (GF_Node*)txt);
		if (!tspan) continue;

		len = tspan->nb_glyphs;
		tspan->flags |= GF_TEXT_SPAN_HORIZONTAL;

		first_char = 0;
		for (j=0; j<len; j++) {
			u32 is_space = 0;
			GF_TextSpan *span;

			if (!tspan->glyphs[j]) continue;

			/*we currently only split sentences at spaces*/
			if (tspan->glyphs[j]->utf_name == (unsigned short) ' ') is_space = 1;
			else if (tspan->glyphs[j]->utf_name == (unsigned short) '\n') 
				is_space = 2;
			if (split_words && (j+1!=len) && !is_space) 
				continue;

			span = (GF_TextSpan*) gf_malloc(sizeof(GF_TextSpan));
			memcpy(span, tspan, sizeof(GF_TextSpan));

			span->nb_glyphs = split_words ? (j - first_char) : 1;
			if (split_words && !is_space) span->nb_glyphs++;
			span->glyphs = gf_malloc(sizeof(void *)*span->nb_glyphs);

			span->bounds.height = st->ascent + st->descent;
			span->bounds.y = start_y;
			span->bounds.x = 0;
			span->bounds.width = 0;

			if (split_words) {
				for (k=0; k<span->nb_glyphs; k++) {
					span->glyphs[k] = tspan->glyphs[FSLTR ? (first_char+k) : (len - first_char - k - 1)];
					span->bounds.width += tspan->font_scale * (span->glyphs[k] ? span->glyphs[k]->horiz_advance : tspan->font->max_advance_h);
				}
			} else {
				span->glyphs[0] = tspan->glyphs[FSLTR ? j : (len - j - 1) ];
				span->glyphs[0] = tspan->glyphs[j];
				span->bounds.width = tspan->font_scale * (span->glyphs[0] ? span->glyphs[0]->horiz_advance : tspan->font->max_advance_h);
			}

			gf_list_add(st->spans, span);

			/*request a context (first one is always valid when entering sort phase)*/
			if (idx) parent_node_start_group(tr_state->parent, NULL, 0);

			idx++;
			parent_node_end_text_group(tr_state->parent, &span->bounds, st->ascent, st->descent, idx);

			if (is_space && split_words) {
				span = (GF_TextSpan*) gf_malloc(sizeof(GF_TextSpan));
				memcpy(span, tspan, sizeof(GF_TextSpan));
				span->nb_glyphs = 1;
				span->glyphs = gf_malloc(sizeof(void *));

				gf_list_add(st->spans, span);
				span->bounds.height = st->ascent + st->descent;
				span->bounds.y = start_y;
				span->bounds.x = 0;
				k = (j - first_char);
				span->glyphs[0] = tspan->glyphs[FSLTR ? (first_char+k) : (len - first_char - k - 1)];
				span->bounds.width = tspan->font_scale * (span->glyphs[0] ? span->glyphs[0]->horiz_advance : tspan->font->max_advance_h);
				parent_node_start_group(tr_state->parent, NULL, is_space);
				idx++;
				parent_node_end_text_group(tr_state->parent, &span->bounds, st->ascent, st->descent, idx);
			}
			first_char = j+1;
		}
		gf_font_manager_delete_span(ft_mgr, tspan);
	}
}
Exemple #4
0
static void build_text(TextStack *st, M_Text *txt, GF_TraverseState *tr_state)
{
	u32 i, j, int_major, k, styles, count;
	Fixed fontSize, start_x, start_y, line_spacing, tot_width, tot_height, max_scale, maxExtent;
	u32 size, trim_size;
	GF_Font *font;
	Bool horizontal;
	GF_TextSpan *trim_tspan = NULL;
	GF_FontManager *ft_mgr = tr_state->visual->compositor->font_manager;
	M_FontStyle *fs = (M_FontStyle *)txt->fontStyle;

	fontSize = FSSIZE;
	if (fontSize <= 0) {
		fontSize = INT2FIX(12);
		if (!tr_state->pixel_metrics) fontSize = gf_divfix(fontSize, tr_state->visual->compositor->output_width);
    }
	horizontal = FSHORIZ;
	start_x = start_y = 0;

	styles = 0;
	if (fs && fs->style.buffer) {
		if (strstr(fs->style.buffer, "BOLD") || strstr(fs->style.buffer, "bold")) styles |= GF_FONT_WEIGHT_BOLD;
		if (strstr(fs->style.buffer, "ITALIC") || strstr(fs->style.buffer, "italic")) styles |= GF_FONT_ITALIC;
		if (strstr(fs->style.buffer, "UNDERLINED") || strstr(fs->style.buffer, "underlined")) styles |= GF_FONT_UNDERLINED;
	}

	font = gf_font_manager_set_font(ft_mgr, fs ? fs->family.vals : NULL, fs ? fs->family.count : 0, styles);
	if (!font) return;

	/*NOTA: we could use integer maths here but we have a risk of overflow with large fonts, so use fixed maths*/
	st->ascent = gf_muldiv(fontSize, INT2FIX(font->ascent), INT2FIX(font->em_size));
	st->descent = -gf_muldiv(fontSize, INT2FIX(font->descent), INT2FIX(font->em_size));
	line_spacing = gf_mulfix(FSSPACE, fontSize);

	maxExtent = txt->maxExtent;
	trim_size = 0;

	if (maxExtent<0) {
		trim_tspan = gf_font_manager_create_span(ft_mgr, font, "...", fontSize, 0, 0, 0, NULL, 0, styles, (GF_Node*)txt);
		for (i=0; i<trim_tspan->nb_glyphs; i++) {
			if (horizontal) {
				trim_size += trim_tspan->glyphs[i] ? trim_tspan->glyphs[i]->horiz_advance : trim_tspan->font->max_advance_h;
			} else {
				trim_size += trim_tspan->glyphs[i] ? trim_tspan->glyphs[i]->vert_advance : trim_tspan->font->max_advance_v;
			}
		}
	}

	tot_width = tot_height = 0;
	for (i=0; i < txt->string.count; i++) {
		GF_TextSpan *tspan;
		char *str = txt->string.vals[i];
		if (!str) continue;

		tspan = gf_font_manager_create_span(ft_mgr, font, txt->string.vals[i], fontSize, 0, 0, 0, NULL, 0, styles, (GF_Node*)txt);
		if (!tspan) continue;
		
		if (horizontal) tspan->flags |= GF_TEXT_SPAN_HORIZONTAL;

		size = 0;
		if (trim_size) {
			for (j=0; j<tspan->nb_glyphs; j++) {
				if (horizontal) {
					size += tspan->glyphs[j] ? tspan->glyphs[j]->horiz_advance : tspan->font->max_advance_h;
				} else {
					size += tspan->glyphs[j] ? tspan->glyphs[j]->vert_advance : tspan->font->max_advance_v;
				}
				/*word is bigger than allowed extent, rewrite 3 previous chars*/
				if ((s32)size*tspan->font_scale >= -maxExtent) {
					u32 k;
					u32 nb_chars = (j<2) ? j : 3;

					for (k=0; k<nb_chars; k++) {
						u32 idx = nb_chars-k-1;
						if (horizontal) {
							size -= tspan->glyphs[j-k] ? tspan->glyphs[j-k]->horiz_advance : tspan->font->max_advance_h;
							size += trim_tspan->glyphs[idx] ? trim_tspan->glyphs[idx]->horiz_advance : tspan->font->max_advance_h;
						} else {
							size -= tspan->glyphs[j-k] ? tspan->glyphs[j-k]->vert_advance : tspan->font->max_advance_v;
							size += trim_tspan->glyphs[idx] ? trim_tspan->glyphs[idx]->vert_advance : tspan->font->max_advance_v;
						}
						tspan->glyphs[j-k] = trim_tspan->glyphs[idx];
					}
					tspan->nb_glyphs = j+1;
					break;
				}
			}
		}

		if ((horizontal && !FSLTR) || (!horizontal && !FSTTB)) {
			for (k=0; k<tspan->nb_glyphs/2; k++) {
				GF_Glyph *g = tspan->glyphs[k];
				tspan->glyphs[k] = tspan->glyphs[tspan->nb_glyphs-1-k];
				tspan->glyphs[tspan->nb_glyphs-k-1] = g;
			}
		}

		if (!size) {
			for (j=0; j<tspan->nb_glyphs; j++) {
				if (horizontal) {
					size += tspan->glyphs[j] ? tspan->glyphs[j]->horiz_advance : tspan->font->max_advance_h;
				} else {
					size += tspan->glyphs[j] ? tspan->glyphs[j]->vert_advance : tspan->font->max_advance_v;
				}
			}
		}
		gf_list_add(st->spans, tspan);

		if (horizontal) {
			tspan->bounds.width = tspan->font_scale * size;
			/*apply length*/
			if ((txt->length.count>i) && (txt->length.vals[i]>0)) {
				tspan->x_scale = gf_divfix(txt->length.vals[i], tspan->bounds.width);
				tspan->bounds.width = txt->length.vals[i];
			}
			if (tot_width < tspan->bounds.width ) tot_width = tspan->bounds.width;
		} else {
			tspan->bounds.height = tspan->font_scale * size;

			/*apply length*/
			if ((txt->length.count>i) && (txt->length.vals[i]>0)) {
				tspan->y_scale = gf_divfix(txt->length.vals[i], tspan->bounds.height);
				tspan->bounds.height = txt->length.vals[i];
			}
			if (tot_height < tspan->bounds.height) tot_height = tspan->bounds.height;
		}
	}
	if (trim_tspan)	gf_font_manager_delete_span(ft_mgr, trim_tspan);

	
	max_scale = FIX_ONE;
	if (horizontal) {
		if ((maxExtent > 0) && (tot_width>maxExtent)) {
			max_scale = gf_divfix(maxExtent, tot_width);
			tot_width = maxExtent;
		}
		tot_height = (txt->string.count-1) * line_spacing + (st->ascent + st->descent);
		st->bounds.height = tot_height;

		if (!strcmp(FSMINOR, "MIDDLE")) {
			if (FSTTB) {
				start_y = tot_height/2;
				st->bounds.y = start_y;
			} else {
				start_y = st->descent + st->ascent - tot_height/2;
				st->bounds.y = tot_height/2;
			}
		}
		else if (!strcmp(FSMINOR, "BEGIN")) {
			if (FSTTB) {
				start_y = st->descent;
				start_y = 0;
				st->bounds.y = start_y;
			} else {
				st->bounds.y = st->bounds.height;
				start_y = st->descent + st->ascent;
			}
		}
		else if (!strcmp(FSMINOR, "END")) {
			if (FSTTB) {
				start_y = tot_height;
				st->bounds.y = start_y;
			} else {
				start_y = -tot_height + 2*st->descent + st->ascent;
				st->bounds.y = start_y - (st->descent + st->ascent) + tot_height;
			}
		}
		else {
			start_y = st->ascent;
			st->bounds.y = FSTTB ? start_y : (tot_height - st->descent);
		}
	} else {
		if ((maxExtent > 0) && (tot_height>maxExtent) ) {
			max_scale = gf_divfix(maxExtent, tot_height);
			tot_height = maxExtent;
		}
		tot_width = txt->string.count * line_spacing;
		st->bounds.width = tot_width;

		if (!strcmp(FSMINOR, "MIDDLE")) {
			if (FSLTR) {
				start_x = -tot_width/2;
				st->bounds.x = start_x;
			} else {
				start_x = tot_width/2 - line_spacing;
				st->bounds.x = - tot_width + line_spacing;
			}
		}
		else if (!strcmp(FSMINOR, "END")) {
			if (FSLTR) {
				start_x = -tot_width;
				st->bounds.x = start_x;
			} else {
				start_x = tot_width-line_spacing;
				st->bounds.x = 0;
			}
		}
		else {
			if (FSLTR) {
				start_x = 0;
				st->bounds.x = start_x;
			} else {
				start_x = -line_spacing;
				st->bounds.x = -tot_width;
			}
		}
	}
			

	/*major-justification*/
	if (!strcmp(FSMAJOR, "MIDDLE") ) {
		int_major = 0;
	} else if (!strcmp(FSMAJOR, "END") ) {
		int_major = 1;
	} else {
		int_major = 2;
	}

	st->bounds.width = st->bounds.height = 0;

	count = gf_list_count(st->spans);
	for (i=0; i < count; i++) {
		GF_TextSpan *span = gf_list_get(st->spans, i);
		switch (int_major) {
		/*major-justification MIDDLE*/
		case 0:
			if (horizontal) {
				start_x = -span->bounds.width/2;
			} else {
				//start_y = FSTTB ? span->bounds.height/2 : (-span->bounds.height/2 + space);
				start_y = span->bounds.height/2;
			}
			break;
		/*major-justification END*/
		case 1:
			if (horizontal) {
				start_x = (FSLTR) ? -span->bounds.width : 0;
			} else {
				//start_y = FSTTB ? span->bounds.height : (-span->bounds.height + space);
				start_y = FSTTB ? span->bounds.height : 0;
			}
			break;
		/*BEGIN, FIRST or default*/
		default:
			if (horizontal) {
				start_x = (FSLTR) ? 0 : -span->bounds.width;
			} else {
				//start_y = FSTTB ? 0 : space;
				start_y = FSTTB ? 0 : span->bounds.height;
			}
			break;
		}
		span->off_x = start_x;
		span->bounds.x = start_x;
		if (horizontal) {
			span->off_y = start_y - st->ascent;
			span->x_scale = gf_mulfix(span->x_scale, max_scale);
			span->bounds.y = start_y;
		} else {
			span->y_scale = gf_mulfix(span->y_scale, max_scale);
			span->off_y = start_y - gf_mulfix(st->ascent, span->y_scale);
			span->bounds.y = start_y;
		}
		span->off_x = gf_mulfix(span->off_x, max_scale);
		span->off_y = gf_mulfix(span->off_y, max_scale);

		if (horizontal) {
			start_y += FSTTB ? -line_spacing : line_spacing;
			span->bounds.height = st->descent + st->ascent;
		} else {
			start_x += FSLTR ? line_spacing : -line_spacing;
			span->bounds.width = line_spacing;
		}
		gf_rect_union(&st->bounds, &span->bounds);
	}
}
Exemple #5
0
static void get_domtext_width(GF_Node *node, SVGAllAttributes *atts, GF_TraverseState *tr_state)
{
	u32 i;
	GF_Font *font;
	Fixed block_width, *entry;
	GF_FontManager *fm;
	GF_TextSpan *span;
	GF_DOMText *dom_text = (GF_DOMText *)node;

	if (!dom_text->textContent) return;

	fm = tr_state->visual->compositor->font_manager;
	if (!fm) return;

	font = svg_set_font(tr_state, fm);
	if (!font) return;

	span = svg_get_text_span(fm, font, tr_state->svg_props->font_size->value, (tr_state->count_x>1), (tr_state->count_y>1), GF_FALSE, atts, dom_text->textContent, atts->xml_lang ? *atts->xml_lang : NULL, tr_state);
	if (!span) return;

	i=0;
	//count_x, _y: number of x- (y-) position of characters to come in the text flow
	while ( (i<span->nb_glyphs)
	        && ( (tr_state->count_x>1) || (tr_state->count_y>1) )
	      ) {
		block_width = (span->glyphs[i] ? span->glyphs[i]->horiz_advance : font->max_advance_h) * span->font_scale;

		//store width in tr_state->x_anchors
		entry = (Fixed*)gf_malloc(sizeof(Fixed));
		if (span->flags & GF_TEXT_SPAN_RIGHT_TO_LEFT) *entry = -block_width;
		else *entry = block_width;

		gf_list_add(tr_state->x_anchors, entry);

		if (tr_state->count_x>0) tr_state->count_x--;
		if (tr_state->count_y>0) tr_state->count_y--;
		i++;
	}

	//chars are taken one by one while there are indicated positions, then remaining chars are treated as a block
	if (i<span->nb_glyphs) {
		block_width = 0;
		while (i<span->nb_glyphs) {
			block_width += (span->glyphs[i] ? span->glyphs[i]->horiz_advance : font->max_advance_h) * span->font_scale;
			i++;
		}
		//if last indicated position, create a new item
		if ((tr_state->count_x==1)||(tr_state->count_y==1)
		        || !gf_list_count(tr_state->x_anchors) ) {
			entry = (Fixed*)gf_malloc(sizeof(Fixed));
			*entry = block_width;

			if (span->flags & GF_TEXT_SPAN_RIGHT_TO_LEFT) *entry = -block_width;
			else *entry = block_width;

			gf_list_add(tr_state->x_anchors, entry);
		} else { // (count_x == 0 && count_y == 0) otherwise increment last one
			Fixed *prec_lw = gf_list_last(tr_state->x_anchors);
			(*prec_lw) += block_width;
		}
		//force counters to 0 for next spans/DOM texts
		if (tr_state->count_x==1) tr_state->count_x = 0;
		if (tr_state->count_y==1) tr_state->count_y = 0;
	}
	gf_font_manager_delete_span(fm, span);
}