diff -u base/plugins/titler/title.C hvirtual-1.1.6/plugins/titler/title.C
--- base/plugins/titler/title.C	2003-05-16 12:55:10.000000000 +0200
+++ hvirtual-1.1.6/plugins/titler/title.C	2003-06-26 17:14:31.000000000 +0200
@@ -3,8 +3,6 @@
 // Andraz Tori <Andraz.tori1@guest.arnes.si>
 
 
-
-
 #include "clip.h"
 #include "colormodels.h"
 #include "filexml.h"
@@ -13,6 +11,10 @@
 #include "plugincolors.h"
 #include "title.h"
 #include "titlewindow.h"
+#include "freetype/ftglyph.h"
+#include "freetype/ftbbox.h"
+#include "freetype/ftoutln.h"
+#include "freetype/ftstroker.h"
 
 
 #include <errno.h>
@@ -35,6 +37,7 @@
 {
 	style = 0;
 	color = BLACK;
+	color_stroke = 0xff0000;
 	size = 24;
 	motion_strategy = NO_MOTION;
 	loop = 0;
@@ -50,6 +53,7 @@
 	sprintf(encoding, "ISO8859-1");
 	pixels_per_second = 1.0;
 	timecode = 0;
+	stroke_width = 1.0;
 }
 
 // Does not test equivalency but determines if redrawing text is necessary.
@@ -59,6 +63,8 @@
 		style == that.style &&
 		size == that.size &&
 		color == that.color &&
+		color_stroke == that.color_stroke &&
+		stroke_width == that.stroke_width &&
 		timecode == that.timecode && 
 		hjustification == that.hjustification &&
 		vjustification == that.vjustification &&
@@ -74,6 +80,8 @@
 	style = that.style;
 	size = that.size;
 	color = that.color;
+	color_stroke = that.color_stroke;
+	stroke_width = that.stroke_width;
 	pixels_per_second = that.pixels_per_second;
 	motion_strategy = that.motion_strategy;
 	loop = that.loop;
@@ -100,6 +108,8 @@
 	style = prev.style;
 	size = prev.size;
 	color = prev.color;
+	color_stroke = prev.color_stroke;
+	stroke_width = prev.stroke_width;
 	motion_strategy = prev.motion_strategy;
 	loop = prev.loop;
 	hjustification = prev.hjustification;
@@ -194,6 +204,7 @@
 	char_code = 0;
 	c=0;
 	data = 0;
+	data_stroke = 0;
 }
 
 
@@ -201,6 +212,7 @@
 {
 //printf("TitleGlyph::~TitleGlyph 1\n");
 	if(data) delete data;
+	if(data_stroke) delete data_stroke;
 }
 
 
@@ -213,10 +225,6 @@
 
 
 
-
-
-
-
 GlyphPackage::GlyphPackage() : LoadPackage()
 {
 }
@@ -260,10 +268,12 @@
 
 	if(!result)
 	{
-
-		if(FT_Load_Char(freetype_face, glyph->char_code, FT_LOAD_RENDER))
+		int gindex = FT_Get_Char_Index(freetype_face, glyph->char_code);
+//		if(FT_Load_Char(freetype_face, glyph->char_code, FT_LOAD_RENDER))
+		if (gindex == 0) 
 		{
-			printf("GlyphUnit::process_package FT_Load_Char failed.\n");
+			if (glyph->char_code != 10)  // carrige return
+				printf("GlyphUnit::process_package FT_Load_Char failed - char: %i.\n",glyph->char_code);
 // Prevent a crash here
 			glyph->width = 8;
 			glyph->height = 8;
@@ -277,19 +287,133 @@
 				8,
 				BC_A8,
 				8);
+			glyph->data->clear_frame();
+			glyph->data_stroke = 0;
+			if (plugin->config.stroke_width >= 1.0/64) // effectively zero
+			{	glyph->data_stroke = new VFrame(0,
+					8,
+					8,
+					BC_A8,
+					8);
+				glyph->data_stroke->clear_frame();
+			}
 		}
 		else
+		if (plugin->config.stroke_width < 1.0/64) // effectively zero
 		{
-			glyph->width = freetype_face->glyph->bitmap.width;
-			glyph->height = freetype_face->glyph->bitmap.rows;
-			glyph->pitch = freetype_face->glyph->bitmap.pitch;
-			glyph->left = freetype_face->glyph->bitmap_left;
-			glyph->top = freetype_face->glyph->bitmap_top;
-			glyph->freetype_index = FT_Get_Char_Index(freetype_face, glyph->char_code);
-			glyph->advance_w = (freetype_face->glyph->advance.x >> 6);
-
+			FT_Glyph glyph_image;
+			FT_BBox bbox;
+			FT_Bitmap bm;
+			FT_Load_Glyph(freetype_face, gindex, FT_LOAD_DEFAULT);
+		    	FT_Get_Glyph(freetype_face->glyph, &glyph_image);
+			FT_Outline_Get_BBox(&((FT_OutlineGlyph) glyph_image)->outline, &bbox);
+//			printf("Stroke: Xmin: %ld, Xmax: %ld, Ymin: %ld, yMax: %ld\n",
+//					bbox.xMin,bbox.xMax, bbox.yMin, bbox.yMax);
+
+			FT_Outline_Translate(&((FT_OutlineGlyph) glyph_image)->outline,
+				- bbox.xMin,
+				- bbox.yMin);
+			glyph->width = bm.width = ((bbox.xMax - bbox.xMin + 63) >> 6);
+			glyph->height = bm.rows = ((bbox.yMax - bbox.yMin + 63) >> 6);
+			glyph->pitch = bm.pitch = bm.width;
+			bm.pixel_mode = FT_PIXEL_MODE_GRAY;
+			bm.num_grays = 256;
+			glyph->left = (bbox.xMin + 31) >> 6;
+			if (glyph->left < 0) glyph->left = 0;
+			glyph->top = (bbox.yMax + 31) >> 6;
+			glyph->freetype_index = gindex;
+			glyph->advance_w = ((freetype_face->glyph->advance.x + 31) >> 6);
+//printf("GlyphUnit::process_package 1 width=%d height=%d pitch=%d left=%d top=%d advance_w=%d freetype_index=%d\n", 
+//glyph->width, glyph->height, glyph->pitch, glyph->left, glyph->top, glyph->advance_w, glyph->freetype_index);
+	
+			glyph->data = new VFrame(0,
+				glyph->width,
+				glyph->height,
+				BC_A8,
+				glyph->pitch);
+			glyph->data->clear_frame();
+			bm.buffer = glyph->data->get_data();
+			FT_Outline_Get_Bitmap( freetype_library,
+				&((FT_OutlineGlyph) glyph_image)->outline,
+				&bm);
+			FT_Done_Glyph(glyph_image);
+		} else {
+			FT_Glyph glyph_image;
+			int no_outline = 0;
+			FT_Stroker stroker;
+			FT_Outline outline;
+			FT_Bitmap bm;
+			FT_BBox bbox;
+			FT_UInt npoints, ncontours;	
+			typedef struct  FT_LibraryRec_ {    FT_Memory          memory; } FT_LibraryRec;
+			FT_Load_Glyph(freetype_face, gindex, FT_LOAD_DEFAULT);
+			FT_Get_Glyph(freetype_face->glyph, &glyph_image);
+
+// check if the outline is ok (non-empty);
+			FT_Outline_Get_BBox(&((FT_OutlineGlyph) glyph_image)->outline, &bbox);
+			if (bbox.xMin == 0 && bbox.xMax == 0 && bbox.yMin ==0 && bbox.yMax == 0)
+			{
+				FT_Done_Glyph(glyph_image);
+				glyph->data =  new VFrame(0, 0, BC_A8,0);
+				glyph->data_stroke =  new VFrame(0, 0, BC_A8,0);;
+				glyph->width=0;
+				glyph->height=0;
+				glyph->top=0;
+				glyph->left=0;
+				glyph->advance_w =((int)(freetype_face->glyph->advance.x + plugin->config.stroke_width*64)) >> 6;
+				return;
+			}
+			FT_Stroker_New(((FT_LibraryRec *)freetype_library)->memory, &stroker);
+			FT_Stroker_Set(stroker, (int)(plugin->config.stroke_width*64), FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
+			FT_Stroker_ParseOutline(stroker, &((FT_OutlineGlyph) glyph_image)->outline,1);
+			FT_Stroker_GetCounts(stroker,&npoints, &ncontours);
+			if (npoints ==0 && ncontours == 0) {
+// this never happens, but FreeType has a bug regarding Linotype's Palatino font
+				FT_Stroker_Done(stroker);
+				FT_Done_Glyph(glyph_image);
+				glyph->data =  new VFrame(0, 0, BC_A8,0);
+				glyph->data_stroke =  new VFrame(0, 0, BC_A8,0);;
+				glyph->width=0;
+				glyph->height=0;
+				glyph->top=0;
+				glyph->left=0;
+				glyph->advance_w =((int)(freetype_face->glyph->advance.x + plugin->config.stroke_width*64)) >> 6;
+				return;
+			};
+
+			FT_Outline_New(freetype_library, npoints, ncontours, &outline);
+			outline.n_points=0;
+			outline.n_contours=0;
+			FT_Stroker_Export (stroker, &outline);
+			FT_Outline_Get_BBox(&outline, &bbox);
+		
+			FT_Outline_Translate(&outline,
+					- bbox.xMin,
+					- bbox.yMin);
+		
+			FT_Outline_Translate(&((FT_OutlineGlyph) glyph_image)->outline,
+					- bbox.xMin,
+					- bbox.yMin + (int)(plugin->config.stroke_width*32));
+//			printf("Stroke: Xmin: %ld, Xmax: %ld, Ymin: %ld, yMax: %ld\nFill	Xmin: %ld, Xmax: %ld, Ymin: %ld, yMax: %ld\n",
+//					bbox.xMin,bbox.xMax, bbox.yMin, bbox.yMax,
+//					bbox_fill.xMin,bbox_fill.xMax, bbox_fill.yMin, bbox_fill.yMax);
+	
+			glyph->width = bm.width = ((bbox.xMax - bbox.xMin) >> 6)+1;
+			glyph->height = bm.rows = ((bbox.yMax - bbox.yMin) >> 6) +1;
+			glyph->pitch = bm.pitch = bm.width;
+			bm.pixel_mode = FT_PIXEL_MODE_GRAY;
+			bm.num_grays = 256;
+			glyph->left = (bbox.xMin + 31) >> 6;
+			if (glyph->left < 0) glyph->left = 0;
+			glyph->top = (bbox.yMax + 31) >> 6;
+			glyph->freetype_index = gindex;
+			int real_advance = ((int)ceil((float)freetype_face->glyph->advance.x + plugin->config.stroke_width*64) >> 6);
+			glyph->advance_w = glyph->width + glyph->left;
+			if (real_advance > glyph->advance_w) 
+				glyph->advance_w = real_advance;
 //printf("GlyphUnit::process_package 1 width=%d height=%d pitch=%d left=%d top=%d advance_w=%d freetype_index=%d\n", 
-//	glyph->width, glyph->height, glyph->pitch, glyph->left, glyph->top, glyph->advance_w, glyph->freetype_index);
+//glyph->width, glyph->height, glyph->pitch, glyph->left, glyph->top, glyph->advance_w, glyph->freetype_index);
+
 
 //printf("GlyphUnit::process_package 1\n");
 			glyph->data = new VFrame(0,
@@ -297,14 +421,27 @@
 				glyph->height,
 				BC_A8,
 				glyph->pitch);
+			glyph->data_stroke = new VFrame(0,
+				glyph->width,
+				glyph->height,
+				BC_A8,
+				glyph->pitch);
+			glyph->data->clear_frame();
+			glyph->data_stroke->clear_frame();
+// for debugging	memset(	glyph->data_stroke->get_data(), 60, glyph->pitch * glyph->height);
+			bm.buffer=glyph->data->get_data();
+			FT_Outline_Get_Bitmap( freetype_library,
+				&((FT_OutlineGlyph) glyph_image)->outline,
+				&bm);	
+			bm.buffer=glyph->data_stroke->get_data();
+			FT_Outline_Get_Bitmap( freetype_library,
+               		&outline,
+			&bm);
+			FT_Outline_Done(freetype_library,&outline);
+			FT_Stroker_Done(stroker);
+			FT_Done_Glyph(glyph_image);
 
 //printf("GlyphUnit::process_package 2\n");
-			for(int i = 0; i < glyph->height; i++)
-			{
-				memcpy(glyph->data->get_rows()[i], 
-					freetype_face->glyph->bitmap.buffer + glyph->pitch * i,
-					glyph->pitch);
-			}
 		}
 	}
 }
@@ -372,7 +509,8 @@
 //printf("TitleUnit::draw_glyph 1 %c %d %d\n", glyph->c, x, y);
 	for(int in_y = 0; in_y < glyph_h; in_y++)
 	{
-		int y_out = y + plugin->ascent + in_y - glyph->top;
+//		int y_out = y + plugin->ascent + in_y - glyph->top;
+		int y_out = y + plugin->get_char_height() + in_y - glyph->top;
 
 //printf("TitleUnit::draw_glyph 1 %d\n", y_out);
 		if(y_out >= 0 && y_out < output_h)
@@ -406,6 +544,12 @@
 			if(glyph->c == pkg->c)
 			{
 				draw_glyph(plugin->text_mask, glyph, pkg->x, pkg->y);
+				if (plugin->config.stroke_width >= 1.0/64) {
+					VFrame *tmp = glyph->data;
+					glyph->data = glyph->data_stroke;
+					draw_glyph(plugin->text_mask_stroke, glyph, pkg->x, pkg->y);
+					glyph->data = tmp;
+				}
 				break;
 			}
 		}
@@ -473,8 +617,6 @@
 
 
 
-
-
 #define TRANSLATE(type, max, components, r, g, b) \
 { \
 	unsigned char **in_rows = plugin->text_mask->get_rows(); \
@@ -560,6 +702,62 @@
 	} \
 }
 
+
+#define TRANSLATEA(type, max, components, r, g, b) \
+{ \
+	unsigned char **in_rows = plugin->text_mask->get_rows(); \
+	type **out_rows = (type**)plugin->output->get_rows(); \
+ \
+	for(int i = pkg->y1; i < pkg->y2; i++) \
+	{ \
+		if(i + server->out_y1_int >= 0 && \
+			i + server->out_y1_int < server->output_h) \
+		{ \
+			unsigned char *in_row = in_rows[i]; \
+			type *out_row = out_rows[i + server->out_y1_int]; \
+ \
+			for(int j = server->out_x1; j < server->out_x2_int; j++) \
+			{ \
+				if(j  >= 0 && \
+					j < server->output_w) \
+				{ \
+					int input = (int)(in_row[j - server->out_x1]);  \
+ \
+					input *= plugin->alpha; \
+/* Alpha is 0 - 256 */ \
+					input >>= 8; \
+ \
+					int anti_input = 0xff - input; \
+					if(components == 4) \
+					{ \
+						out_row[j * components + 0] =  \
+							(r * input + out_row[j * components + 0] * anti_input) / 0xff; \
+						out_row[j * components + 1] =  \
+							(g * input + out_row[j * components + 1] * anti_input) / 0xff; \
+						out_row[j * components + 2] =  \
+							(b * input + out_row[j * components + 2] * anti_input) / 0xff; \
+						if(max == 0xffff) \
+							out_row[j * components + 3] =  \
+								MAX((input << 8) | input, out_row[j * components + 3]); \
+						else \
+							out_row[j * components + 3] =  \
+								MAX(input, out_row[j * components + 3]); \
+					} \
+					else \
+					{ \
+						out_row[j * components + 0] =  \
+							(r * input + out_row[j * components + 0] * anti_input) / 0xff; \
+						out_row[j * components + 1] =  \
+							(g * input + out_row[j * components + 1] * anti_input) / 0xff; \
+						out_row[j * components + 2] =  \
+							(b * input + out_row[j * components + 2] * anti_input) / 0xff; \
+					} \
+				} \
+			} \
+		} \
+	} \
+}
+
 static YUV yuv;
 
 void TitleTranslateUnit::process_package(LoadPackage *package)
@@ -573,6 +771,7 @@
 	r_in = (plugin->config.color & 0xff0000) >> 16;
 	g_in = (plugin->config.color & 0xff00) >> 8;
 	b_in = plugin->config.color & 0xff;
+
 	switch(plugin->output->get_color_model())
 	{
 		case BC_RGB888:
@@ -700,7 +899,7 @@
 
 //printf("TitleTranslate::init_packages 1\n");
 
-
+	
 	out_y1 = out_y1_int;
 	out_y2 = out_y2_int;
 	out_x1 = out_x1_int;
@@ -758,11 +957,13 @@
 // Build font database
 	build_fonts();
 	text_mask = 0;
+	text_mask_stroke = 0;
 	glyph_engine = 0;
 	title_engine = 0;
 	freetype_library = 0;
 	freetype_face = 0;
 	char_positions = 0;
+	rows_bottom = 0;
 	translate = 0;
 	need_reconfigure = 1;
 }
@@ -772,7 +973,9 @@
 //printf("TitleMain::~TitleMain 1\n");
 	PLUGIN_DESTRUCTOR_MACRO
 	if(text_mask) delete text_mask;
+	if(text_mask_stroke) delete text_mask_stroke;
 	if(char_positions) delete [] char_positions;
+	if(rows_bottom) delete [] rows_bottom;
 	clear_glyphs();
 	if(glyph_engine) delete glyph_engine;
 	if(title_engine) delete title_engine;
@@ -1131,7 +1334,8 @@
 
 int TitleMain::get_char_height()
 {
-	return config.size;
+// this is height above the zero line, but does not include characters that go below
+	return config.size+ (int)ceil(config.stroke_width*2);
 }
 
 int TitleMain::get_char_advance(int current, int next)
@@ -1174,7 +1378,7 @@
 	else
 		kerning.x = 0;
 //printf("TitleMain::get_char_advance 2 %d %d\n", result, kerning.x);
-
+	
 	return result + (kerning.x >> 6);
 }
 
@@ -1256,6 +1460,7 @@
 	int row_start = 0;
 	text_len = strlen(config.text);
 	if(!char_positions) char_positions = new title_char_position_t[text_len];
+	
 	text_rows = 0;
 	text_w = 0;
 	ascent = 0;
@@ -1264,13 +1469,35 @@
 		if(glyphs.values[i]->top > ascent) ascent = glyphs.values[i]->top;
 //printf("TitleMain::get_total_extents %d\n", ascent);
 
+	// get the number of rows first
+	for(int i = 0; i < text_len; i++)
+	{
+		if(config.text[i] == 0xa || i == text_len - 1)
+		{
+			text_rows++;
+		}
+	}
+	if (!rows_bottom) rows_bottom = new int[text_rows+1];
+	text_rows = 0;
+	rows_bottom[0] = 0;
 
 	for(int i = 0; i < text_len; i++)
 	{
 		char_positions[i].x = current_w;
 		char_positions[i].y = text_rows * get_char_height();
 		char_positions[i].w = get_char_advance(config.text[i], config.text[i + 1]);
-
+		TitleGlyph *current_glyph = 0;
+		for(int j = 0; j < glyphs.total; j++)
+		{
+			if(glyphs.values[j]->c == config.text[i])
+			{
+				current_glyph = glyphs.values[j];
+				break;
+			}
+		}
+		int current_bottom = current_glyph->top - current_glyph->height;
+		if (current_bottom < rows_bottom[text_rows])
+			rows_bottom[text_rows] = current_bottom ;
 
 // printf("TitleMain::get_total_extents 1 %c %d %d %d\n", 
 // 	config.text[i], 
@@ -1282,6 +1509,7 @@
 		if(config.text[i] == 0xa || i == text_len - 1)
 		{
 			text_rows++;
+			rows_bottom[text_rows] = 0;
 			if(current_w > text_w) text_w = current_w;
 			current_w = 0;
 		}
@@ -1478,18 +1706,24 @@
 	int need_redraw = 0;
 	if(text_mask &&
 		(text_mask->get_w() != text_w ||
-		text_mask->get_h() != visible_rows * get_char_height()))
+		text_mask->get_h() != visible_rows * get_char_height() - rows_bottom[visible_row2-1]))
 	{
 		delete text_mask;
 		text_mask = 0;
+		text_mask_stroke = 0;
 	}
 
 	if(!text_mask)
 	{
 		text_mask = new VFrame(0,
 			text_w,
-			visible_rows * get_char_height(),
+			visible_rows * get_char_height() - rows_bottom[visible_row2-1],
+			BC_A8);
+		text_mask_stroke = new VFrame(0,
+			text_w,
+			visible_rows * get_char_height() - rows_bottom[visible_row2-1],
 			BC_A8);
+			
 		need_redraw = 1;
 	}
 
@@ -1504,6 +1738,7 @@
 	{
 //printf("TitleMain::draw_mask 2\n");
 		text_mask->clear_frame();
+		text_mask_stroke->clear_frame();
 
 // for(int i = 0; i < text_mask->get_h(); i++)
 // 	for(int j = 0; j < text_mask->get_w(); j++)
@@ -1600,6 +1835,17 @@
 	{
 		if(!translate) translate = new TitleTranslate(this, PluginClient::smp + 1);
 		translate->process_packages();
+		if (config.stroke_width >= 1.0/64) 
+		{
+			int temp_color = config.color;
+			VFrame *tmp_text_mask = this->text_mask;
+			config.color = config.color_stroke;
+			this->text_mask = this->text_mask_stroke;
+
+			translate->process_packages();
+			config.color = temp_color;
+			this->text_mask = tmp_text_mask;
+		}
 	}
 //printf("TitleMain::overlay_mask 200\n");
 }
@@ -1660,6 +1906,7 @@
 	}
 
 	if(config.size <= 0 || config.size >= 2048) return 0;
+	if(config.stroke_width < 0 || config.stroke_width >= 512) return 0;
 	if(!strlen(config.text)) return 0;
 	if(!strlen(config.encoding)) return 0;
 
@@ -1670,7 +1917,9 @@
 	{
 //printf("TitleMain::process_realtime 2\n");
 		if(text_mask) delete text_mask;
+		if(text_mask_stroke) delete text_mask_stroke;
 		text_mask = 0;
+		text_mask_stroke = 0;
 //printf("TitleMain::process_realtime 2\n");
 		if(freetype_face) FT_Done_Face(freetype_face);
 		freetype_face = 0;
@@ -1680,6 +1929,8 @@
 //printf("TitleMain::process_realtime 2\n");
 		if(char_positions) delete [] char_positions;
 		char_positions = 0;
+		if(rows_bottom) delete [] rows_bottom;
+		rows_bottom = 0;
 //printf("TitleMain::process_realtime 2\n");
 		clear_glyphs();
 //printf("TitleMain::process_realtime 2\n");
@@ -1793,6 +2044,8 @@
 	config.style = defaults->get("STYLE", (long)config.style);
 	config.size = defaults->get("SIZE", config.size);
 	config.color = defaults->get("COLOR", config.color);
+	config.color_stroke = defaults->get("COLOR_STROKE", config.color_stroke);
+	config.stroke_width = defaults->get("STROKE_WIDTH", config.stroke_width);
 	config.motion_strategy = defaults->get("MOTION_STRATEGY", config.motion_strategy);
 	config.loop = defaults->get("LOOP", config.loop);
 	config.pixels_per_second = defaults->get("PIXELS_PER_SECOND", config.pixels_per_second);
@@ -1836,6 +2089,8 @@
 	defaults->update("STYLE", (long)config.style);
 	defaults->update("SIZE", config.size);
 	defaults->update("COLOR", config.color);
+	defaults->update("COLOR_STROKE", config.color_stroke);
+	defaults->update("STROKE_WIDTH", config.stroke_width);
 	defaults->update("MOTION_STRATEGY", config.motion_strategy);
 	defaults->update("LOOP", config.loop);
 	defaults->update("PIXELS_PER_SECOND", config.pixels_per_second);
@@ -1935,6 +2190,8 @@
 	output.tag.set_property("STYLE", (long)config.style);
 	output.tag.set_property("SIZE", config.size);
 	output.tag.set_property("COLOR", config.color);
+	output.tag.set_property("COLOR_STROKE", config.color_stroke);
+	output.tag.set_property("STROKE_WIDTH", config.stroke_width);
 	output.tag.set_property("MOTION_STRATEGY", config.motion_strategy);
 	output.tag.set_property("LOOP", config.loop);
 	output.tag.set_property("PIXELS_PER_SECOND", config.pixels_per_second);
@@ -1984,6 +2241,8 @@
 				config.style = input.tag.get_property("STYLE", (long)config.style);
 				config.size = input.tag.get_property("SIZE", config.size);
 				config.color = input.tag.get_property("COLOR", config.color);
+				config.color_stroke = input.tag.get_property("COLOR_STROKE", config.color_stroke);
+				config.stroke_width = input.tag.get_property("STROKE_WIDTH", config.stroke_width);
 				config.motion_strategy = input.tag.get_property("MOTION_STRATEGY", config.motion_strategy);
 				config.loop = input.tag.get_property("LOOP", config.loop);
 				config.pixels_per_second = input.tag.get_property("PIXELS_PER_SECOND", config.pixels_per_second);
diff -u base/plugins/titler/title.h hvirtual-1.1.6/plugins/titler/title.h
--- base/plugins/titler/title.h	2003-05-16 12:55:10.000000000 +0200
+++ hvirtual-1.1.6/plugins/titler/title.h	2003-06-26 15:12:13.000000000 +0200
@@ -84,6 +84,7 @@
 	long style;
 	int size;
 	int color;
+	int color_stroke;
 // Motion of title across frame
 	int motion_strategy;
 // Loop motion path
@@ -108,6 +109,8 @@
 	char text[BCTEXTLEN];
 // Encoding to convert from 
 	char encoding[BCTEXTLEN];
+// Width of the stroke
+	double stroke_width;
 };
 
 class FontEntry
@@ -148,6 +151,7 @@
 	FT_ULong char_code;
 	int width, height, pitch, advance_w, left, top, freetype_index;
 	VFrame *data;
+	VFrame *data_stroke;
 };
 
 
@@ -358,6 +362,7 @@
 
 // Stage 1 parameters must be compared to redraw the text mask
 	VFrame *text_mask;
+	VFrame *text_mask_stroke;
 	GlyphEngine *glyph_engine;
 	TitleEngine *title_engine;
 	TitleTranslate *translate;
@@ -403,7 +408,8 @@
 	int text_h;
 // Position of each character relative to total text extents
 	title_char_position_t *char_positions;
-
+// Positions of the bottom pixels of the rows
+	int *rows_bottom;
 	VFrame *input, *output;
 
 	int need_reconfigure;
diff -u base/plugins/titler/titlewindow.C hvirtual-1.1.6/plugins/titler/titlewindow.C
--- base/plugins/titler/titlewindow.C	2003-05-16 12:55:10.000000000 +0200
+++ hvirtual-1.1.6/plugins/titler/titlewindow.C	2003-06-26 15:12:13.000000000 +0200
@@ -60,6 +60,7 @@
 	sizes.remove_all_objects();
 	encodings.remove_all_objects();
 	delete color_thread;
+	delete color_stroke_thread;
 	delete title_x;
 	delete title_y;
 }
@@ -244,6 +245,18 @@
 	color_y = y + 20;
 	color_thread = new TitleColorThread(client, this);
 
+	x = 265;
+	y += 50;
+	add_tool(strokewidth_title = new BC_Title(x, y, "Stroke width:"));
+	add_tool(stroke_width = new TitleFade(client, this, &client->config.stroke_width, x, y + 20));
+
+	x += 120;
+	add_tool(color_stroke_button = new TitleColorStrokeButton(client, this, x, y + 20));
+	color_stroke_x = color_x;
+	color_stroke_y = y + 20;
+	color_stroke_thread = new TitleColorStrokeThread(client, this);
+
+
 	x = 10;
 	y += 50;
 
@@ -296,6 +309,7 @@
 	encoding_title->reposition_window(encoding_title->get_x(), encoding_title->get_y());
 	encoding->reposition_window(encoding->get_x(), encoding->get_y());
 	color_button->reposition_window(color_button->get_x(), color_button->get_y());
+	color_stroke_button->reposition_window(color_stroke_button->get_x(), color_stroke_button->get_y());
 	motion_title->reposition_window(motion_title->get_x(), motion_title->get_y());
 	motion->reposition_window(motion->get_x(), motion->get_y());
 	loop->reposition_window(loop->get_x(), loop->get_y());
@@ -306,6 +320,8 @@
 	fadeout_title->reposition_window(fadeout_title->get_x(), fadeout_title->get_y());
 	fade_out->reposition_window(fade_out->get_x(), fade_out->get_y());
 	text_title->reposition_window(text_title->get_x(), text_title->get_y());
+	stroke_width->reposition_window(stroke_width->get_x(), stroke_width->get_y());
+	strokewidth_title->reposition_window(strokewidth_title->get_x(), strokewidth_title->get_y());
 	timecode->reposition_window(timecode->get_x(), timecode->get_y());
 
 	text->reposition_window(text->get_x(), 
@@ -381,6 +397,9 @@
 	set_color(client->config.color);
 	draw_box(color_x, color_y, 100, 30);
 	flash(color_x, color_y, 100, 30);
+	set_color(client->config.color_stroke);
+	draw_box(color_stroke_x, color_stroke_y, 100, 30);
+	flash(color_stroke_x, color_stroke_y, 100, 30);
 }
 
 void TitleWindow::update_justification()
@@ -406,6 +425,7 @@
 	dropshadow->update((float)client->config.dropshadow);
 	fade_in->update((float)client->config.fade_in);
 	fade_out->update((float)client->config.fade_out);
+	stroke_width->update((float)client->config.stroke_width);
 	font->update(client->config.font);
 	text->update(client->config.text);
 	speed->update(client->config.pixels_per_second);
@@ -522,6 +542,18 @@
 	return 1;
 }
 
+TitleColorStrokeButton::TitleColorStrokeButton(TitleMain *client, TitleWindow *window, int x, int y)
+ : BC_GenericButton(x, y, "Stroke color...")
+{
+	this->client = client;
+	this->window = window;
+}
+int TitleColorStrokeButton::handle_event()
+{
+	window->color_stroke_thread->start_window(client->config.color_stroke, 0);
+	return 1;
+}
+
 TitleMotion::TitleMotion(TitleMain *client, TitleWindow *window, int x, int y)
  : BC_PopupTextBox(window, 
 		&window->paths,
@@ -813,3 +845,18 @@
 	client->send_configure_change();
 	return 1;
 }
+TitleColorStrokeThread::TitleColorStrokeThread(TitleMain *client, TitleWindow *window)
+ : ColorThread()
+{
+	this->client = client;
+	this->window = window;
+}
+
+int TitleColorStrokeThread::handle_event(int output)
+{
+	client->config.color_stroke = output;
+	window->update_color();
+	window->flush();
+	client->send_configure_change();
+	return 1;
+}
diff -u base/plugins/titler/titlewindow.h hvirtual-1.1.6/plugins/titler/titlewindow.h
--- base/plugins/titler/titlewindow.h	2003-05-16 12:55:10.000000000 +0200
+++ hvirtual-1.1.6/plugins/titler/titlewindow.h	2003-06-26 15:12:13.000000000 +0200
@@ -35,6 +35,7 @@
 class TitleSize;
 class TitleEncoding;
 class TitleColorButton;
+class TitleColorStrokeButton;
 class TitleDropShadow;
 class TitleMotion;
 class TitleLoop;
@@ -50,6 +51,7 @@
 class TitleMid;
 class TitleBottom;
 class TitleColorThread;
+class TitleColorStrokeThread;
 class TitleSpeed;
 class TitleTimecode;
 
@@ -88,6 +90,8 @@
 	TitleEncoding *encoding;
 	TitleColorButton *color_button;
 	TitleColorThread *color_thread;
+	TitleColorStrokeButton *color_stroke_button;
+	TitleColorStrokeThread *color_stroke_thread;
 	BC_Title *motion_title;
 	TitleMotion *motion;
 	TitleLoop *loop;
@@ -95,6 +99,8 @@
 	TitleFade *fade_in;
 	BC_Title *fadeout_title;
 	TitleFade *fade_out;
+	BC_Title *strokewidth_title;
+	TitleFade *stroke_width;
 	BC_Title *text_title;
 	TitleText *text;
 	BC_Title *justify_title;
@@ -109,7 +115,7 @@
 	TitleTimecode *timecode;
 
 // Color preview
-	int color_x, color_y;
+	int color_x, color_y, color_stroke_x, color_stroke_y;
 	ArrayList<BC_ListBoxItem*> sizes;
 	ArrayList<BC_ListBoxItem*> encodings;
 	ArrayList<BC_ListBoxItem*> paths;
@@ -172,6 +178,14 @@
 	TitleMain *client;
 	TitleWindow *window;
 };
+class TitleColorStrokeButton : public BC_GenericButton
+{
+public:
+	TitleColorStrokeButton(TitleMain *client, TitleWindow *window, int x, int y);
+	int handle_event();
+	TitleMain *client;
+	TitleWindow *window;
+};
 class TitleMotion : public BC_PopupTextBox
 {
 public:
@@ -318,4 +332,13 @@
 	TitleWindow *window;
 };
 
+class TitleColorStrokeThread : public ColorThread
+{
+public:
+	TitleColorStrokeThread(TitleMain *client, TitleWindow *window);
+	int handle_event(int output);
+	TitleMain *client;
+	TitleWindow *window;
+};
+
 #endif
