예제 #1
0
파일: mpeg4_text.c 프로젝트: bigbensk/gpac
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);
	}
}
예제 #2
0
파일: mpeg4_text.c 프로젝트: bigbensk/gpac
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);
	}
}
예제 #3
0
파일: svg_text.c 프로젝트: Brilon314/gpac
static GF_TextSpan *svg_get_text_span(GF_FontManager *fm, GF_Font *font, Fixed font_size, Bool x_offsets, Bool y_offsets, Bool rotate, SVGAllAttributes *atts, char *textContent, const char *lang, GF_TraverseState *tr_state)
{
	GF_TextSpan *span = NULL;
	char *dup_text;
	u32 i, j, len;
	char prev;

	Bool preserve = (atts->xml_space && (*atts->xml_space==XML_SPACE_PRESERVE)) ? GF_TRUE : GF_FALSE;

	len = (u32) strlen(textContent);
	dup_text = (char*)gf_malloc(len+1);

	switch (tr_state->last_char_type) {
	case 2:
		prev = 0;
		break;
	case 0:
	case 1:
	default:
		prev = ' ';
		break;
	}
	for (i = 0, j = 0; i < len; i++) {
		if (textContent[i] == ' ') {
			if (prev == ' ' && !preserve) {
				/* ignore space */
			} else {
				dup_text[j] = textContent[i];
				prev = dup_text[j];
				j++;
			}
		} else if (textContent[i] == '\t') {
			if (prev == ' ' && !preserve) {
				/* ignore space */
			} else {
				dup_text[j] = ' ';
				prev = dup_text[j];
				j++;
			}
		} else if ((textContent[i] == '\n') ||
		           (textContent[i] == '\r')
		          ) {
			if (prev == ' ' && preserve) {
				dup_text[j] = ' ';
				prev = dup_text[j];
				j++;
			} else if (!i && !prev) {
				prev = dup_text[j] = ' ';
				j++;
			}
		} else if (
		    (((u8) textContent[i] == 0xc2) && ((u8) textContent[i+1] == 0xa0))
		) {
			if (prev == ' ' && !preserve) {
				/* ignore space */
			} else {
				dup_text[j] = ' ';
				prev = dup_text[j];
				j++;
			}
			i++;
		} else {
			dup_text[j] = textContent[i];
			prev = dup_text[j];
			j++;
		}
	}
	dup_text[j] = 0;
	if (!j) tr_state->last_char_type = 1;
	else tr_state->last_char_type = (dup_text[j-1]==' ') ? 1 : 2;
	/*SVG text is fliped by default (text y-axis is the inverse of SVG y-axis*/
	span = gf_font_manager_create_span(fm, font, dup_text, font_size, x_offsets, y_offsets, rotate, lang, GF_TRUE, 0, tr_state->text_parent);
	gf_free(dup_text);
	if (span) span->flags |= GF_TEXT_SPAN_HORIZONTAL;
	return span;
}