changeset 19846:bcc792bfa431

Store bitmap glyphs in a separate struct, instead of FreeType's internal buffer. This is required for various bitmap modifications (like blur, outline and shadow).
author eugeni
date Sat, 16 Sep 2006 13:08:17 +0000
parents 900c9417644b
children d7c2e093e406
files libass/Makefile libass/ass_bitmap.c libass/ass_bitmap.h libass/ass_cache.c libass/ass_cache.h libass/ass_render.c
diffstat 6 files changed, 155 insertions(+), 64 deletions(-) [+]
line wrap: on
line diff
--- a/libass/Makefile	Sat Sep 16 10:15:42 2006 +0000
+++ b/libass/Makefile	Sat Sep 16 13:08:17 2006 +0000
@@ -5,7 +5,7 @@
 
 LIBS=$(LIBNAME)
 
-SRCS=ass.c ass_cache.c ass_fontconfig.c ass_render.c ass_utils.c ass_mp.c
+SRCS=ass.c ass_cache.c ass_fontconfig.c ass_render.c ass_utils.c ass_mp.c ass_bitmap.c
 
 OBJS=$(SRCS:.c=.o)
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libass/ass_bitmap.c	Sat Sep 16 13:08:17 2006 +0000
@@ -0,0 +1,91 @@
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <ft2build.h>
+#include FT_GLYPH_H
+
+#include "mp_msg.h"
+#include "ass_bitmap.h"
+
+static bitmap_t* alloc_bitmap(int w, int h)
+{
+	bitmap_t* bm;
+	bm = calloc(1, sizeof(bitmap_t));
+	bm->buffer = malloc(w*h);
+	bm->w = w;
+	bm->h = h;
+	bm->left = bm->top = 0;
+	return bm;
+}
+
+void ass_free_bitmap(bitmap_t* bm)
+{
+	if (bm) {
+		if (bm->buffer) free(bm->buffer);
+		free(bm);
+	}
+}
+
+static bitmap_t* glyph_to_bitmap_internal(FT_Glyph glyph, int bord)
+{
+	FT_BitmapGlyph bg;
+	FT_Bitmap* bit;
+	bitmap_t* bm;
+	int w, h;
+	unsigned char* src;
+	unsigned char* dst;
+	int i;
+	int error;
+
+	error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 0);
+	if (error) {
+		mp_msg(MSGT_GLOBAL, MSGL_WARN, "FT_Glyph_To_Bitmap error %d \n", error);
+		return 0;
+	}
+
+	bg = (FT_BitmapGlyph)glyph;
+	bit = &(bg->bitmap);
+	if (bit->pixel_mode != FT_PIXEL_MODE_GRAY) {
+		mp_msg(MSGT_GLOBAL, MSGL_WARN, "Unsupported pixel mode: %d\n", (int)(bit->pixel_mode));
+		FT_Done_Glyph(glyph);
+		return 0;
+	}
+
+	w = bit->width;
+	h = bit->rows;
+	bm = alloc_bitmap(w + 2*bord, h + 2*bord);
+	memset(bm->buffer, 0, bm->w * bm->h);
+	bm->left = bg->left - bord;
+	bm->top = - bg->top - bord;
+
+	src = bit->buffer;
+	dst = bm->buffer + bord + bm->w * bord;
+	for (i = 0; i < h; ++i) {
+		memcpy(dst, src, w);
+		src += bit->pitch;
+		dst += bm->w;
+	}
+
+	return bm;
+}
+
+int glyph_to_bitmap(FT_Glyph glyph, FT_Glyph outline_glyph, bitmap_t** bm_g, bitmap_t** bm_o)
+{
+	assert(bm_g);
+
+	if (glyph)
+		*bm_g = glyph_to_bitmap_internal(glyph, 0);
+	if (!*bm_g)
+		return 1;
+	if (outline_glyph && bm_o) {
+		*bm_o = glyph_to_bitmap_internal(outline_glyph, 0);
+		if (!*bm_o) {
+			ass_free_bitmap(*bm_g);
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libass/ass_bitmap.h	Sat Sep 16 13:08:17 2006 +0000
@@ -0,0 +1,14 @@
+#ifndef __ASS_BITMAP_H__
+#define __ASS_BITMAP_H__
+
+typedef struct bitmap_s {
+	int left, top;
+	int w, h; // width, height
+	unsigned char* buffer; // w x h buffer
+} bitmap_t;
+
+int glyph_to_bitmap(FT_Glyph glyph, FT_Glyph outline_glyph, bitmap_t** bm_g, bitmap_t** bm_o);
+void ass_free_bitmap(bitmap_t* bm);
+
+#endif
+
--- a/libass/ass_cache.c	Sat Sep 16 10:15:42 2006 +0000
+++ b/libass/ass_cache.c	Sat Sep 16 13:08:17 2006 +0000
@@ -2,11 +2,13 @@
 
 #include <ft2build.h>
 #include FT_FREETYPE_H
+#include FT_GLYPH_H
 
 #include <assert.h>
 
 #include "mp_msg.h"
 #include "ass_fontconfig.h"
+#include "ass_bitmap.h"
 #include "ass_cache.h"
 
 
@@ -197,8 +199,8 @@
 		glyph_hash_item_t* item = glyph_hash_root[i];
 		while (item) {
 			glyph_hash_item_t* next = item->next;
-			if (item->val.glyph) FT_Done_Glyph(item->val.glyph);
-			if (item->val.outline_glyph) FT_Done_Glyph(item->val.outline_glyph);
+			if (item->val.bm) ass_free_bitmap(item->val.bm);
+			if (item->val.bm_o) ass_free_bitmap(item->val.bm_o);
 			free(item);
 			item = next;
 		}
--- a/libass/ass_cache.h	Sat Sep 16 10:15:42 2006 +0000
+++ b/libass/ass_cache.h	Sat Sep 16 13:08:17 2006 +0000
@@ -35,8 +35,8 @@
 } glyph_hash_key_t;
 
 typedef struct glyph_hash_val_s {
-	FT_Glyph glyph; // the actual glyphs
-	FT_Glyph outline_glyph;
+	bitmap_t* bm; // the actual glyph bitmaps
+	bitmap_t* bm_o;
 	FT_BBox bbox_scaled; // bbox after scaling, but before rotation
 	FT_Vector advance; // 26.6, advance distance to the next glyph in line
 } glyph_hash_val_t;
--- a/libass/ass_render.c	Sat Sep 16 10:15:42 2006 +0000
+++ b/libass/ass_render.c	Sat Sep 16 13:08:17 2006 +0000
@@ -12,6 +12,7 @@
 #include "mp_msg.h"
 
 #include "ass.h"
+#include "ass_bitmap.h"
 #include "ass_cache.h"
 #include "ass_utils.h"
 #include "ass_fontconfig.h"
@@ -51,11 +52,12 @@
 	unsigned symbol;
 	FT_Glyph glyph;
 	FT_Glyph outline_glyph;
+	bitmap_t* bm;
+	bitmap_t* bm_o;
 	FT_BBox bbox;
 	FT_Vector pos;
 	char linebreak; // the first (leading) glyph of some line ?
 	uint32_t c[4]; // colors
-	char bitmap; // bool
 	FT_Vector advance; // 26.6
 	effect_t effect_type;
 	int effect_timing; // time duration of current karaoke word
@@ -223,6 +225,7 @@
 		fontconfig_done(fc_priv);
 		goto ass_init_exit;
 	}
+
 	priv->library = ft;
 	priv->fontconfig_priv = fc_priv;
 	// images_root and related stuff is zero-filled in calloc
@@ -280,7 +283,7 @@
  * \return pointer to the new list tail
  * Performs clipping. Uses my_draw_bitmap for actual bitmap convertion.
  */
-static ass_image_t** render_glyph(FT_BitmapGlyph bit, int dst_x, int dst_y, uint32_t color, uint32_t color2, int brk, ass_image_t** tail)
+static ass_image_t** render_glyph(bitmap_t* bm, int dst_x, int dst_y, uint32_t color, uint32_t color2, int brk, ass_image_t** tail)
 {
 	// brk is relative to dst_x
 	// color = color left of brk
@@ -288,19 +291,12 @@
 	int b_x0, b_y0, b_x1, b_y1; // visible part of the bitmap
 	int clip_x0, clip_y0, clip_x1, clip_y1;
 	int tmp;
-	FT_Bitmap* bitmap;
 	ass_image_t* img;
 
-	bitmap = &(bit->bitmap);
-	dst_x += bit->left;
-	dst_y -= bit->top;
-	brk -= bit->left;
+	dst_x += bm->left;
+	dst_y += bm->top;
+	brk -= bm->left;
 	
-	if (bitmap->pixel_mode != FT_PIXEL_MODE_GRAY) {
-		mp_msg(MSGT_GLOBAL, MSGL_WARN, "Unsupported pixel mode: %d\n", (int)(bitmap->pixel_mode));
-		return tail;
-	}
-
 	// clipping
 	clip_x0 = render_context.clip_x0;
 	clip_y0 = render_context.clip_y0;
@@ -308,8 +304,8 @@
 	clip_y1 = render_context.clip_y1;
 	b_x0 = 0;
 	b_y0 = 0;
-	b_x1 = bitmap->width;
-	b_y1 = bitmap->rows;
+	b_x1 = bm->w;
+	b_y1 = bm->h;
 	
 	tmp = dst_x - clip_x0;
 	if (tmp < 0) {
@@ -321,15 +317,15 @@
 		mp_msg(MSGT_GLOBAL, MSGL_DBG2, "clip top\n");
 		b_y0 = - tmp;
 	}
-	tmp = clip_x1 - dst_x - bitmap->width;
+	tmp = clip_x1 - dst_x - bm->w;
 	if (tmp < 0) {
 		mp_msg(MSGT_GLOBAL, MSGL_DBG2, "clip right\n");
-		b_x1 = bitmap->width + tmp;
+		b_x1 = bm->w + tmp;
 	}
-	tmp = clip_y1 - dst_y - bitmap->rows;
+	tmp = clip_y1 - dst_y - bm->h;
 	if (tmp < 0) {
 		mp_msg(MSGT_GLOBAL, MSGL_DBG2, "clip bottom\n");
-		b_y1 = bitmap->rows + tmp;
+		b_y1 = bm->h + tmp;
 	}
 	
 	if ((b_y0 >= b_y1) || (b_x0 >= b_x1))
@@ -337,16 +333,16 @@
 
 	if (brk > b_x0) { // draw left part
 		if (brk > b_x1) brk = b_x1;
-		img = my_draw_bitmap(bitmap->buffer + bitmap->pitch * b_y0 + b_x0, 
-			brk - b_x0, b_y1 - b_y0, bitmap->pitch,
+		img = my_draw_bitmap(bm->buffer + bm->w * b_y0 + b_x0, 
+			brk - b_x0, b_y1 - b_y0, bm->w,
 			dst_x + b_x0, dst_y + b_y0, color);
 		*tail = img;
 		tail = &img->next;
 	}
 	if (brk < b_x1) { // draw right part
 		if (brk < b_x0) brk = b_x0;
-		img = my_draw_bitmap(bitmap->buffer + bitmap->pitch * b_y0 + brk, 
-			b_x1 - brk, b_y1 - b_y0, bitmap->pitch,
+		img = my_draw_bitmap(bm->buffer + bm->w * b_y0 + brk, 
+			b_x1 - brk, b_y1 - b_y0, bm->w,
 			dst_x + brk, dst_y + b_y0, color2);
 		*tail = img;
 		tail = &img->next;
@@ -361,37 +357,31 @@
 static ass_image_t* render_text(text_info_t* text_info, int dst_x, int dst_y)
 {
 	int pen_x, pen_y;
-	int error, error2;
-	int i;
-	FT_Glyph image;
-	FT_BitmapGlyph bit;
+	int i, error;
+	bitmap_t* bm;
 	glyph_hash_val_t hash_val;
 	ass_image_t* head;
 	ass_image_t** tail = &head;
 
 	for (i = 0; i < text_info->length; ++i) {
-		if (text_info->glyphs[i].bitmap != 1) {
+		if (text_info->glyphs[i].glyph) {
 			if ((text_info->glyphs[i].symbol == '\n') || (text_info->glyphs[i].symbol == 0))
 				continue;
-			error = FT_Glyph_To_Bitmap( &(text_info->glyphs[i].outline_glyph), FT_RENDER_MODE_NORMAL, 0, 1);
-			error2 = FT_Glyph_To_Bitmap( &(text_info->glyphs[i].glyph), FT_RENDER_MODE_NORMAL, 0, 1);
+			error = glyph_to_bitmap(text_info->glyphs[i].glyph, text_info->glyphs[i].outline_glyph,
+					&text_info->glyphs[i].bm, &text_info->glyphs[i].bm_o);
+			if (error)
+				text_info->glyphs[i].symbol = 0;
+			FT_Done_Glyph(text_info->glyphs[i].glyph);
+			FT_Done_Glyph(text_info->glyphs[i].outline_glyph);
 
-			if (error || error2) {
-				FT_Done_Glyph(text_info->glyphs[i].outline_glyph);
-				FT_Done_Glyph(text_info->glyphs[i].glyph);
-				mp_msg(MSGT_GLOBAL, MSGL_WARN, "FT_Glyph_To_Bitmap error %d %d, symbol %d, index %d\n", 
-						error, error2, text_info->glyphs[i].symbol, text_info->glyphs[i].hash_key.index);
-				text_info->glyphs[i].symbol = 0; // do not render
-				continue;
-			}
 			// cache
-			text_info->glyphs[i].hash_key.bitmap = 1; // other hash_key fields were set in get_glyph()
 			hash_val.bbox_scaled = text_info->glyphs[i].bbox;
-			hash_val.outline_glyph = text_info->glyphs[i].outline_glyph;
-			hash_val.glyph = text_info->glyphs[i].glyph;
+			hash_val.bm_o = text_info->glyphs[i].bm_o;
+			hash_val.bm = text_info->glyphs[i].bm;
 			hash_val.advance.x = text_info->glyphs[i].advance.x;
 			hash_val.advance.y = text_info->glyphs[i].advance.y;
 			cache_add_glyph(&(text_info->glyphs[i].hash_key), &hash_val);
+
 		}
 	}
 
@@ -402,13 +392,12 @@
 
 		pen_x = dst_x + info->pos.x;
 		pen_y = dst_y + info->pos.y;
-		image = info->outline_glyph;
-		bit = (FT_BitmapGlyph)image;
+		bm = info->bm_o;
 		
 		if ((info->effect_type == EF_KARAOKE_KO) && (info->effect_timing <= info->bbox.xMax)) {
 			// do nothing
 		} else
-			tail = render_glyph(bit, pen_x, pen_y, info->c[2], 0, 1000000, tail);
+			tail = render_glyph(bm, pen_x, pen_y, info->c[2], 0, 1000000, tail);
 	}
 	for (i = 0; i < text_info->length; ++i) {
 		glyph_info_t* info = text_info->glyphs + i;
@@ -417,18 +406,17 @@
 
 		pen_x = dst_x + info->pos.x;
 		pen_y = dst_y + info->pos.y;
-		image = info->glyph;
-		bit = (FT_BitmapGlyph)image;
+		bm = info->bm;
 
 		if ((info->effect_type == EF_KARAOKE) || (info->effect_type == EF_KARAOKE_KO)) {
 			if (info->effect_timing > info->bbox.xMax)
-				tail = render_glyph(bit, pen_x, pen_y, info->c[0], 0, 1000000, tail);
+				tail = render_glyph(bm, pen_x, pen_y, info->c[0], 0, 1000000, tail);
 			else
-				tail = render_glyph(bit, pen_x, pen_y, info->c[1], 0, 1000000, tail);
+				tail = render_glyph(bm, pen_x, pen_y, info->c[1], 0, 1000000, tail);
 		} else if (info->effect_type == EF_KARAOKE_KF) {
-			tail = render_glyph(bit, pen_x, pen_y, info->c[0], info->c[1], info->effect_timing, tail);
+			tail = render_glyph(bm, pen_x, pen_y, info->c[0], info->c[1], info->effect_timing, tail);
 		} else
-			tail = render_glyph(bit, pen_x, pen_y, info->c[0], 0, 1000000, tail);
+			tail = render_glyph(bm, pen_x, pen_y, info->c[0], 0, 1000000, tail);
 	}
 
 	*tail = 0;
@@ -1206,20 +1194,16 @@
 	key->bold = render_context.bold;
 	key->italic = render_context.italic;
 
-	key->bitmap = 1; // looking for bitmap glyph
-
-	
 	val = cache_find_glyph(key);
 //	val = 0;
 	
 	if (val) {
-		// bitmap glyph found, no need for FT_Glyph_Copy
-		info->glyph = val->glyph;
-		info->outline_glyph = val->outline_glyph;
+		info->glyph = info->outline_glyph = 0;
+		info->bm = val->bm;
+		info->bm_o = val->bm_o;
 		info->bbox = val->bbox_scaled;
 		info->advance.x = val->advance.x;
 		info->advance.y = val->advance.y;
-		info->bitmap = 1; // bitmap glyph
 
 		return 0;
 	}
@@ -1258,7 +1242,7 @@
 		FT_Glyph_Copy(info->glyph, &info->outline_glyph);
 	}
 
-	info->bitmap = 0; // outline glyph
+	info->bm = info->bm_o = 0;
 
 	return 0;
 }
@@ -1599,7 +1583,7 @@
 		pen.y += text_info.glyphs[text_info.length].advance.y;
 		
 		// if it's an outline glyph, we still need to fill the bbox
-		if (text_info.glyphs[text_info.length].bitmap != 1) {
+		if (text_info.glyphs[text_info.length].glyph) {
 			FT_Glyph_Get_CBox( text_info.glyphs[text_info.length].glyph, FT_GLYPH_BBOX_PIXELS, &(text_info.glyphs[text_info.length].bbox) );
 		}
 
@@ -1822,7 +1806,7 @@
 			info->pos.y -= start.y >> 6;
 
 //			mp_msg(MSGT_GLOBAL, MSGL_DBG2, "shift: %d, %d\n", start.x / 64, start.y / 64);
-			if (info->bitmap != 1) {
+			if (info->glyph) {
 				FT_Glyph_Transform( info->glyph, &matrix_rotate, 0 );
 				FT_Glyph_Transform( info->outline_glyph, &matrix_rotate, 0 );
 			}