summaryrefslogtreecommitdiffstats
path: root/libass
diff options
context:
space:
mode:
authoreugeni <eugeni@b3059339-0415-0410-9bf9-f77b7e298cf2>2006-09-16 13:08:17 +0000
committereugeni <eugeni@b3059339-0415-0410-9bf9-f77b7e298cf2>2006-09-16 13:08:17 +0000
commit867aa92076b8b4264e8e1a3378a1b6ed076da7f0 (patch)
tree67e35551c43ac77b304deb23289c14241c1f6679 /libass
parent52204b1e9381b7c856be3e16dc795a97b041b068 (diff)
downloadmpv-867aa92076b8b4264e8e1a3378a1b6ed076da7f0.tar.bz2
mpv-867aa92076b8b4264e8e1a3378a1b6ed076da7f0.tar.xz
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). git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@19852 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'libass')
-rw-r--r--libass/Makefile2
-rw-r--r--libass/ass_bitmap.c91
-rw-r--r--libass/ass_bitmap.h14
-rw-r--r--libass/ass_cache.c6
-rw-r--r--libass/ass_cache.h4
-rw-r--r--libass/ass_render.c104
6 files changed, 156 insertions, 65 deletions
diff --git a/libass/Makefile b/libass/Makefile
index 3385a4c067..070c8529be 100644
--- a/libass/Makefile
+++ b/libass/Makefile
@@ -5,7 +5,7 @@ LIBNAME=libass.a
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)
diff --git a/libass/ass_bitmap.c b/libass/ass_bitmap.c
new file mode 100644
index 0000000000..9d98ec000a
--- /dev/null
+++ b/libass/ass_bitmap.c
@@ -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;
+}
+
diff --git a/libass/ass_bitmap.h b/libass/ass_bitmap.h
new file mode 100644
index 0000000000..edf4790584
--- /dev/null
+++ b/libass/ass_bitmap.h
@@ -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
+
diff --git a/libass/ass_cache.c b/libass/ass_cache.c
index 64f915becf..2dce591d93 100644
--- a/libass/ass_cache.c
+++ b/libass/ass_cache.c
@@ -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 @@ void ass_glyph_cache_done(void)
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;
}
diff --git a/libass/ass_cache.h b/libass/ass_cache.h
index 68f57296bf..f24886e873 100644
--- a/libass/ass_cache.h
+++ b/libass/ass_cache.h
@@ -35,8 +35,8 @@ typedef struct glyph_hash_key_s {
} 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;
diff --git a/libass/ass_render.c b/libass/ass_render.c
index 6aee3cd8d4..e0096ca219 100644
--- a/libass/ass_render.c
+++ b/libass/ass_render.c
@@ -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 @@ typedef struct glyph_info_s {
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 @@ ass_instance_t* ass_init(void)
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 @@ static ass_image_t* my_draw_bitmap(unsigned char* bitmap, int bitmap_w, int bitm
* \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 @@ static ass_image_t** render_glyph(FT_BitmapGlyph bit, int dst_x, int dst_y, uint
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 @@ static ass_image_t** render_glyph(FT_BitmapGlyph bit, int dst_x, int dst_y, uint
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 @@ static ass_image_t** render_glyph(FT_BitmapGlyph bit, int dst_x, int dst_y, uint
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 @@ static ass_image_t** render_glyph(FT_BitmapGlyph bit, int dst_x, int dst_y, uint
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_glyph(FT_BitmapGlyph bit, int dst_x, int dst_y, uint
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);
-
- 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;
- }
+ 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);
+
// 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 @@ static ass_image_t* render_text(text_info_t* text_info, int dst_x, int dst_y)
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 @@ static ass_image_t* render_text(text_info_t* text_info, int dst_x, int dst_y)
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 @@ static int get_glyph(int index, int symbol, glyph_info_t* info, FT_Vector* advan
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 @@ static int get_glyph(int index, int symbol, glyph_info_t* info, FT_Vector* advan
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 @@ static int ass_render_event(ass_event_t* event, event_images_t* event_images)
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 @@ static int ass_render_event(ass_event_t* event, event_images_t* event_images)
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 );
}