dynamic keyframes, textbox rework, andrea ffmpeg.opts, perpetual chkpt undo, lv2...
[goodguy/history.git] / cinelerra-5.1 / plugins / titler / titler.C
index a3f2411bd98594b36bcf5d4ab5061a2a821f0270..d0f4f681ca08fddd629e7cffa36f392c6aa8317f 100644 (file)
@@ -51,7 +51,7 @@
 #include "titlerwindow.h"
 #include "transportque.h"
 #include "vrender.h"
-
+#include "workarounds.h"
 
 #include <errno.h>
 #include <stdint.h>
@@ -78,11 +78,15 @@ REGISTER_PLUGIN(TitleMain)
 #endif
 #define DEFAULT_TIMECODEFORMAT TIME_HMS
 
+static inline int kw_strcmp(const char *ap, const char *bp) {
+       return !strcmp(ap, bp) ? 0 : strcmp(ap,_(bp));
+}
+
 TitleConfig::TitleConfig()
 {
        strcpy(font, "fixed");
        strcpy(encoding, DEFAULT_ENCODING);
-       style = 0;
+       style = FONT_ALIAS;
        size = 24;
        color = BLACK;
        alpha = 0xff;
@@ -98,7 +102,7 @@ TitleConfig::TitleConfig()
        vjustification = JUSTIFY_MID;
        fade_in = 0.0;  fade_out = 0.0;
        pixels_per_second = 100.0;
-       wtext[0] = 0;  wlen = 0;
+       wtext = 0;  wsize = 0;  wlen = 0;
        title_x = title_y = 0.0;
        title_w = title_h = 0;
        window_w = 860;
@@ -116,6 +120,7 @@ TitleConfig::TitleConfig()
 
 TitleConfig::~TitleConfig()
 {
+       delete [] wtext;
 }
 
 int TitleConfig::equivalent(TitleConfig &that)
@@ -174,7 +179,7 @@ void TitleConfig::copy_from(TitleConfig &that)
        fade_in = that.fade_in;
        fade_out = that.fade_out;
        pixels_per_second = that.pixels_per_second;
-       wlen = that.wlen;
+       demand(wlen = that.wlen);
        memcpy(wtext, that.wtext, that.wlen * sizeof(wchar_t));
        title_x = that.title_x;  title_y = that.title_y;
        title_w = that.title_w;  title_h = that.title_h;
@@ -212,7 +217,7 @@ void TitleConfig::interpolate(TitleConfig &prev, TitleConfig &next,
        fade_in = prev.fade_in;
        fade_out = prev.fade_out;
        pixels_per_second = prev.pixels_per_second;
-       wlen = prev.wlen;
+       demand(wlen = prev.wlen);
        memcpy(wtext, prev.wtext, prev.wlen * sizeof(wchar_t));
        wtext[wlen] = 0;
        this->title_x = prev.title_x == next.title_x ? prev.title_x :
@@ -235,10 +240,21 @@ void TitleConfig::interpolate(TitleConfig &prev, TitleConfig &next,
        loop_playback = prev.loop_playback;
 }
 
+int TitleConfig::demand(long sz)
+{
+       if( wtext && wsize >= sz ) return 0;
+       delete [] wtext;
+       wsize = sz + wlen/2 + 0x1000;
+       wtext = new wchar_t[wsize+1];
+       wtext[wsize] = 0;
+       return 1;
+}
+
 void TitleConfig::to_wtext(const char *from_enc, const char *text, int tlen)
 {
+       demand(tlen);
        wlen = BC_Resources::encode(from_enc, BC_Resources::wide_encoding,
-               (char*)text,tlen, (char *)wtext,sizeof(wtext)) / sizeof(wchar_t);
+               (char*)text,tlen, (char *)wtext,sizeof(*wtext)*wsize) / sizeof(wchar_t);
        while( wlen > 0 && !wtext[wlen-1] ) --wlen;
 }
 
@@ -286,7 +302,18 @@ GlyphUnit::GlyphUnit(TitleMain *plugin, GlyphEngine *server)
 GlyphUnit::~GlyphUnit()
 {
        if( freetype_library )
-               FT_Done_FreeType(freetype_library);
+               ft_Done_FreeType(freetype_library);
+}
+
+static inline void to_mono(VFrame *data)
+{
+       if( !data ) return;
+       int w = data->get_w(), h = data->get_h();
+       uint8_t **rows = data->get_rows();
+       for( int y=0; y<h; ++y ) {
+               uint8_t *dp = rows[y];
+               for( int x=0; x<w; ++x,++dp ) *dp = *dp >= 0x80 ? 0xff : 0;
+       }
 }
 
 void GlyphUnit::process_package(LoadPackage *package)
@@ -305,11 +332,11 @@ void GlyphUnit::process_package(LoadPackage *package)
                result = 1;
        }
        if( !result ) {
-               int gindex = FT_Get_Char_Index(freetype_face, glyph->char_code);
+               int gindex = ft_Get_Char_Index(freetype_face, glyph->char_code);
                if( !gindex && !freetype_face->charmap && // if no default charmap
                    freetype_face->charmaps && freetype_face->charmaps[0] &&
-                   !FT_Select_Charmap(freetype_face, freetype_face->charmaps[0]->encoding) ) {
-                       gindex = FT_Get_Char_Index(freetype_face, glyph->char_code);
+                   !ft_Select_Charmap(freetype_face, freetype_face->charmaps[0]->encoding) ) {
+                       gindex = ft_Get_Char_Index(freetype_face, glyph->char_code);
                }
                if( gindex == 0 ) {
 printf("GlyphUnit::process_package 1 glyph not found (%s) %04x, '%c'\n",
@@ -318,10 +345,10 @@ printf("GlyphUnit::process_package 1 glyph not found (%s) %04x, '%c'\n",
                        if( resources->find_font_by_char(glyph->char_code, new_path, freetype_face) ) {
                                plugin->load_freetype_face(freetype_library,
                                        freetype_face, new_path);
-                               gindex = FT_Get_Char_Index(freetype_face, glyph->char_code);
+                               gindex = ft_Get_Char_Index(freetype_face, glyph->char_code);
                        }
                }
-               FT_Set_Pixel_Sizes(freetype_face, glyph->size, 0);
+               ft_Set_Pixel_Sizes(freetype_face, glyph->size, 0);
 
                if( gindex == 0 ) {
 // carrige return
@@ -351,9 +378,9 @@ printf("GlyphUnit::process_package 1 glyph not found (%s) %04x, '%c'\n",
                        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);
+                       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);
 
@@ -374,12 +401,12 @@ printf("GlyphUnit::process_package 1 glyph not found (%s) %04x, '%c'\n",
                        glyph->data = new VFrame(glyph->width, glyph->height, BC_A8, glyph->pitch);
                        glyph->data->clear_frame();
                        bm.buffer = glyph->data->get_data();
-                       FT_Outline_Translate(&((FT_OutlineGlyph) glyph_image)->outline,
+                       ft_Outline_Translate(&((FT_OutlineGlyph) glyph_image)->outline,
                                - bbox.xMin, - bbox.yMin);
-                       FT_Outline_Get_Bitmap( freetype_library,
+                       ft_Outline_Get_Bitmap( freetype_library,
                                &((FT_OutlineGlyph) glyph_image)->outline,
                                &bm);
-                       FT_Done_Glyph(glyph_image);
+                       ft_Done_Glyph(glyph_image);
                }
                else {
 // Outline desired and glyph found
@@ -390,14 +417,14 @@ printf("GlyphUnit::process_package 1 glyph not found (%s) %04x, '%c'\n",
                        FT_BBox bbox;
                        FT_UInt npoints, ncontours;
 
-                       FT_Load_Glyph(freetype_face, gindex, FT_LOAD_DEFAULT);
-                       FT_Get_Glyph(freetype_face->glyph, &glyph_image);
+                       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);
+                       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);
+                               ft_Done_Glyph(glyph_image);
                                glyph->width = 0;   glyph->height = 0;
                                glyph->left = 0;    glyph->top = 0;
                                glyph->right = 0;   glyph->bottom = 0;
@@ -411,18 +438,18 @@ printf("GlyphUnit::process_package 1 glyph not found (%s) %04x, '%c'\n",
                                return;
                        }
 #if FREETYPE_MAJOR > 2 || (FREETYPE_MAJOR == 2 && FREETYPE_MINOR >= 2)
-                       FT_Stroker_New(freetype_library, &stroker);
+                       ft_Stroker_New(freetype_library, &stroker);
 #else
-                       FT_Stroker_New(((FT_LibraryRec *)freetype_library)->memory, &stroker);
+                       ft_Stroker_New(((FT_LibraryRec *)freetype_library)->memory, &stroker);
 #endif
-                       FT_Stroker_Set(stroker, (int)(plugin->config.stroke_width * 64),
+                       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);
+                       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);
+                               ft_Stroker_Done(stroker);
+                               ft_Done_Glyph(glyph_image);
                                glyph->width = 0;   glyph->height = 0;
                                glyph->left = 0;    glyph->top = 0;
                                glyph->right = 0;   glyph->bottom = 0;
@@ -436,13 +463,13 @@ printf("GlyphUnit::process_package 1 glyph not found (%s) %04x, '%c'\n",
                                return;
                        };
 
-                       FT_Outline_New(freetype_library, npoints, ncontours, &outline);
+                       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,
+                       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\n"
@@ -478,19 +505,24 @@ printf("GlyphUnit::process_package 1 glyph not found (%s) %04x, '%c'\n",
                        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_Outline_Get_Bitmap( freetype_library,
                                &((FT_OutlineGlyph) glyph_image)->outline,
                                &bm);
                        bm.buffer=glyph->data_stroke->get_data();
-                       FT_Outline_Get_Bitmap( freetype_library,
+                       ft_Outline_Get_Bitmap( freetype_library,
                        &outline,
                                &bm);
-                       FT_Outline_Done(freetype_library,&outline);
-                       FT_Stroker_Done(stroker);
-                       FT_Done_Glyph(glyph_image);
+                       ft_Outline_Done(freetype_library,&outline);
+                       ft_Stroker_Done(stroker);
+                       ft_Done_Glyph(glyph_image);
 
 //printf("GlyphUnit::process_package 2\n");
                }
+
+               if( !(glyph->style & FONT_ALIAS) ) {
+                       to_mono(glyph->data);
+                       to_mono(glyph->data_stroke);
+               }
        }
 }
 
@@ -841,6 +873,10 @@ TitleCurFixed::TitleCurFixed(TitleParser *parser, TitleMain *plugin)
  : TitleStack<int>(parser, 0)
 {
 }
+TitleCurAlias::TitleCurAlias(TitleParser *parser, TitleMain *plugin)
+ : TitleStack<int>(parser, (plugin->config.style & FONT_ALIAS) ? 1 : 0)
+{
+}
 TitleCurSuper::TitleCurSuper(TitleParser *parser, TitleMain *plugin)
  : TitleStack<int>(parser, 0)
 {
@@ -859,6 +895,7 @@ TitleParser::TitleParser(TitleMain *plugin)
    cur_under(this, plugin),
    cur_blink(this, plugin),
    cur_fixed(this, plugin),
+   cur_alias(this, plugin),
    cur_super(this, plugin)
 {
        bfr = out = plugin->config.wtext;
@@ -917,9 +954,9 @@ TitleMain::~TitleMain()
        delete glyph_engine;
        delete title_engine;
        if( freetype_face )
-               FT_Done_Face(freetype_face);
+               ft_Done_Face(freetype_face);
        if( freetype_library )
-               FT_Done_FreeType(freetype_library);
+               ft_Done_FreeType(freetype_library);
        delete translate;
        delete outline_engine;
 }
@@ -1004,8 +1041,8 @@ void TitleMain::build_previews(TitleWindow *gui)
 //                                     (char *)new_path);
                                strcpy(new_path, font->path);
                                if( load_freetype_face(freetype_library, freetype_face, new_path)) continue;
-                               FT_Set_Pixel_Sizes(freetype_face, text_height, 0);
-                               if( FT_Load_Char(freetype_face, c, FT_LOAD_RENDER) ) continue;
+                               ft_Set_Pixel_Sizes(freetype_face, text_height, 0);
+                               if( ft_Load_Char(freetype_face, c, FT_LOAD_RENDER) ) continue;
                                int glyph_w = freetype_face->glyph->bitmap.width;
                                int glyph_h = freetype_face->glyph->bitmap.rows;
                                if( glyph_h > max_height ) glyph_h = max_height;
@@ -1049,7 +1086,7 @@ void TitleMain::build_previews(TitleWindow *gui)
                }
        }
 
-       if( freetype_library ) FT_Done_FreeType(freetype_library);
+       if( freetype_library ) ft_Done_FreeType(freetype_library);
 }
 
 
@@ -1065,20 +1102,20 @@ int TitleMain::check_char_code_path(FT_Library &freetype_library,
        FcConfig *config;
        FcPattern *font;
 
-       FcInit();
-       config = FcConfigGetCurrent();
-       FcConfigSetRescanInterval(config, 0);
+       fcInit();
+       config = fcConfigGetCurrent();
+       fcConfigSetRescanInterval(config, 0);
 
-       pat = FcPatternCreate();
-       os = FcObjectSetBuild ( FC_FILE, FC_FONTFORMAT, (char *) 0);
-       fs = FcFontList(config, pat, os);
+       pat = fcPatternCreate();
+       os = fcObjectSetBuild( FC_FILE, FC_FONTFORMAT, (char *) 0);
+       fs = fcFontList(config, pat, os);
        int found = 0;
        char tmpstring[BCTEXTLEN];
        int limit_to_truetype = 0; //if you want to limit search to truetype put 1
-       if( !freetype_library ) FT_Init_FreeType(&freetype_library);
-       if( !FT_New_Face(freetype_library, path_old, 0, &temp_freetype_face) ) {
-               FT_Set_Pixel_Sizes(temp_freetype_face, 128, 0);
-               int gindex = FT_Get_Char_Index(temp_freetype_face, char_code);
+       if( !freetype_library ) ft_Init_FreeType(&freetype_library);
+       if( !ft_New_Face(freetype_library, path_old, 0, &temp_freetype_face) ) {
+               ft_Set_Pixel_Sizes(temp_freetype_face, 128, 0);
+               int gindex = ft_Get_Char_Index(temp_freetype_face, char_code);
                if( gindex != 0 && char_code == 10 ) {
                        strcpy(path_new, path_old);
                        found = 1;
@@ -1088,13 +1125,13 @@ int TitleMain::check_char_code_path(FT_Library &freetype_library,
        if( !found ) {
                for( int i=0; fs && i<fs->nfont; ++i ) {
                        font = fs->fonts[i];
-                       FcPatternGetString(font, FC_FONTFORMAT, 0, &format);
+                       fcPatternGetString(font, FC_FONTFORMAT, 0, &format);
                        if( strcmp((char *)format, "TrueType") && !limit_to_truetype ) continue;
-                       if( FcPatternGetString(font, FC_FILE, 0, &file) != FcResultMatch ) continue;
+                       if( fcPatternGetString(font, FC_FILE, 0, &file) != FcResultMatch ) continue;
                        sprintf(tmpstring, "%s", file);
-                       if( !FT_New_Face(freetype_library, tmpstring, 0, &temp_freetype_face) ) continue;
-                       FT_Set_Pixel_Sizes(temp_freetype_face, 128, 0);
-                       int gindex = FT_Get_Char_Index(temp_freetype_face, char_code);
+                       if( !ft_New_Face(freetype_library, tmpstring, 0, &temp_freetype_face) ) continue;
+                       ft_Set_Pixel_Sizes(temp_freetype_face, 128, 0);
+                       int gindex = ft_Get_Char_Index(temp_freetype_face, char_code);
                        if( gindex != 0 && char_code == 10 ) {
                                sprintf(path_new, "%s", tmpstring);
                                found = 1;
@@ -1104,8 +1141,8 @@ int TitleMain::check_char_code_path(FT_Library &freetype_library,
        }
 
 done:
-       if( fs ) FcFontSetDestroy(fs);
-       if( temp_freetype_face ) FT_Done_Face(temp_freetype_face);
+       if( fs ) fcFontSetDestroy(fs);
+       if( temp_freetype_face ) ft_Done_Face(temp_freetype_face);
        temp_freetype_face = 0;
 
        if( !found ) {
@@ -1122,14 +1159,14 @@ int TitleMain::load_freetype_face(FT_Library &freetype_library,
 {
 //printf("TitleMain::load_freetype_face 1\n");
        if( !freetype_library )
-               FT_Init_FreeType(&freetype_library);
+               ft_Init_FreeType(&freetype_library);
        if( freetype_face )
-               FT_Done_Face(freetype_face);
+               ft_Done_Face(freetype_face);
        freetype_face = 0;
 //printf("TitleMain::load_freetype_face 2\n");
 
 // Use freetype's internal function for loading font
-       if( FT_New_Face(freetype_library, path, 0, &freetype_face) ) {
+       if( ft_New_Face(freetype_library, path, 0, &freetype_face) ) {
                fprintf(stderr, _("TitleMain::load_freetype_face %s failed.\n"), path);
                freetype_face = 0;
                freetype_library = 0;
@@ -1365,7 +1402,7 @@ int TitleMain::get_width(TitleGlyph *cur, TitleGlyph *nxt)
        int result = cur->advance_x;
        if( !nxt ) return result;
        FT_Vector kerning;
-       if( !FT_Get_Kerning(freetype_face,
+       if( !ft_Get_Kerning(freetype_face,
            cur->freetype_index, nxt->freetype_index,
            ft_kerning_default, &kerning) )
                result += (kerning.x >> 6);
@@ -1578,6 +1615,14 @@ int TitleCurFixed::set(const char *txt)
        return 0;
 }
 
+int TitleCurAlias::set(const char *txt)
+{
+       int alias = !*txt ? 1 : strtol(txt,(char **)&txt,0);
+       if( *txt ) return 1;
+       push(alias);
+       return 0;
+}
+
 int TitleCurSuper::set(const char *txt)
 {
        int super = !*txt ? 1 : strtol(txt,(char **)&txt,0);
@@ -1600,18 +1645,19 @@ int TitleCurNudge::set(const char *txt)
 
 int TitleParser::set_attributes(int ret)
 {
-        if( !strcmp(id,KW_NUDGE) )  return ret>1 ? cur_nudge.unset(text)  : cur_nudge.set(text);
-        if( !strcmp(id,KW_COLOR) )  return ret>1 ? cur_color.unset(text)  : cur_color.set(text);
-        if( !strcmp(id,KW_ALPHA) )  return ret>1 ? cur_alpha.unset(text)  : cur_alpha.set(text);
-        if( !strcmp(id,KW_FONT) )   return ret>1 ? cur_font.unset(text)   : cur_font.set(text);
-        if( !strcmp(id,KW_SIZE) )   return ret>1 ? cur_size.unset(text)   : cur_size.set(text);
-        if( !strcmp(id,KW_BOLD) )   return ret>1 ? cur_bold.unset(text)   : cur_bold.set(text);
-        if( !strcmp(id,KW_ITALIC) ) return ret>1 ? cur_italic.unset(text) : cur_italic.set(text);
-        if( !strcmp(id,KW_CAPS) )   return ret>1 ? cur_caps.unset(text)   : cur_caps.set(text);
-        if( !strcmp(id,KW_UL) )     return ret>1 ? cur_under.unset(text)  : cur_under.set(text);
-        if( !strcmp(id,KW_BLINK) )  return ret>1 ? cur_blink.unset(text)  : cur_blink.set(text);
-        if( !strcmp(id,KW_FIXED) )  return ret>1 ? cur_fixed.unset(text)  : cur_fixed.set(text);
-        if( !strcmp(id,KW_SUP) )    return ret>1 ? cur_super.unset(text)  : cur_super.set(text);
+        if( !kw_strcmp(id,KW_NUDGE) )  return ret>1 ? cur_nudge.unset(text)  : cur_nudge.set(text);
+        if( !kw_strcmp(id,KW_COLOR) )  return ret>1 ? cur_color.unset(text)  : cur_color.set(text);
+        if( !kw_strcmp(id,KW_ALPHA) )  return ret>1 ? cur_alpha.unset(text)  : cur_alpha.set(text);
+        if( !kw_strcmp(id,KW_FONT) )   return ret>1 ? cur_font.unset(text)   : cur_font.set(text);
+        if( !kw_strcmp(id,KW_SIZE) )   return ret>1 ? cur_size.unset(text)   : cur_size.set(text);
+        if( !kw_strcmp(id,KW_BOLD) )   return ret>1 ? cur_bold.unset(text)   : cur_bold.set(text);
+        if( !kw_strcmp(id,KW_ITALIC) ) return ret>1 ? cur_italic.unset(text) : cur_italic.set(text);
+        if( !kw_strcmp(id,KW_CAPS) )   return ret>1 ? cur_caps.unset(text)   : cur_caps.set(text);
+        if( !kw_strcmp(id,KW_UL) )     return ret>1 ? cur_under.unset(text)  : cur_under.set(text);
+        if( !kw_strcmp(id,KW_BLINK) )  return ret>1 ? cur_blink.unset(text)  : cur_blink.set(text);
+        if( !kw_strcmp(id,KW_FIXED) )  return ret>1 ? cur_fixed.unset(text)  : cur_fixed.set(text);
+        if( !kw_strcmp(id,KW_ALIAS) )  return ret>1 ? cur_alias.unset(text)  : cur_alias.set(text);
+        if( !kw_strcmp(id,KW_SUP) )    return ret>1 ? cur_super.unset(text)  : cur_super.set(text);
        return 1;
 }
 
@@ -1628,7 +1674,7 @@ void TitleMain::load_glyphs()
                int ret = wchrs.tget(wch);
                if( ret > 0 ) {
                        if( !wchrs.set_attributes(ret) ) continue;
-                       if( !strcmp(wchrs.id,KW_PNG) && add_image(wchrs.text) ) continue;
+                       if( !kw_strcmp(wchrs.id,KW_PNG) && add_image(wchrs.text) ) continue;
                        wch = wch1;  wchrs.seek(ipos+1);
                        ret = 0;
                }
@@ -1644,6 +1690,8 @@ void TitleMain::load_glyphs()
                if( cur_bold ) cur_style |= BC_FONT_BOLD;
                int cur_italic  = wchrs.cur_italic;
                if( cur_italic ) cur_style |= BC_FONT_ITALIC;
+               int cur_alias  = wchrs.cur_alias;
+               if( cur_alias ) cur_style |= FONT_ALIAS;
                int cur_super = wchrs.cur_super;
                if( cur_super ) cur_size /= 2;
                int exists = 0;
@@ -1758,6 +1806,8 @@ int TitleMain::get_text()
                int cur_style = 0;
                int cur_bold  = wchrs.cur_bold;
                if( cur_bold ) cur_style |= BC_FONT_BOLD;
+               int cur_alias   = wchrs.cur_alias;
+               if( cur_alias ) cur_style |= FONT_ALIAS;
                int cur_italic  = wchrs.cur_italic;
                if( cur_italic ) cur_style |= BC_FONT_ITALIC;
                short nx = cur_nudge >> 16, ny = cur_nudge;
@@ -1765,7 +1815,7 @@ int TitleMain::get_text()
                if( ret > 0 ) {
                        if( !wchrs.set_attributes(ret) ) continue;
                        ret = -1;
-                       if( !strcmp(wchrs.id,KW_PNG) ) {
+                       if( !kw_strcmp(wchrs.id,KW_PNG) ) {
                                VFrame *png_image = get_image(wchrs.text);
                                if( png_image ) {
                                        chr = title_chars.add(CHAR_IMAGE, png_image);
@@ -2188,25 +2238,29 @@ TitleTranslateUnit::TitleTranslateUnit(TitleMain *plugin, TitleTranslate *server
 
 #define TRANSLATE(type, max, comps, ofs) { \
        type **out_rows = (type**)output->get_rows(); \
-       float fs = 1./(256.-max); \
+       float fr = 1./(256.-max), fs = max/255.; \
        float r = max > 1 ? 0.5 : 0; \
-       for( int y=y1; y<y2; ++y ) { \
-               float fy = y+yofs;  int iy = fy; \
-               float yf1 = fy>=iy ? fy - iy : fy+1-iy; \
+       int ix1= x1, iy1 = y1, ix2= x2, iy2 = y2; \
+       float fy = y1 + yofs; \
+       for( int y=iy1; y<iy2; ++y,++fy ) { \
+               int iy = fy;  float yf1 = fy - iy; \
+               if( yf1 < 0 ) ++yf1; \
                float yf0 = 1. - yf1; \
                unsigned char *in_row0 = in_rows[iy<0 ? 0 : iy]; \
                unsigned char *in_row1 = in_rows[iy<ih1 ? iy+1 : ih1]; \
-               for( int x=x1; x<x2; ++x ) { \
+               float fx = x1 + xofs; \
+               for( int x=ix1; x<ix2; ++x,++fx ) { \
                        type *op = out_rows[y] + x*comps; \
-                       float fx = x+xofs;  int ix = fx; \
-                       float xf1 = fx - ix, xf0 = 1. - xf1; \
+                       int ix = fx;  float xf1 = fx - ix; \
+                       if( xf1 < 0 ) ++xf1; \
+                       float xf0 = 1. - xf1; \
                        int i0 = (ix<0 ? 0 : ix)*4, i1 = (ix<iw1 ? ix+1 : iw1)*4; \
                        uint8_t *cp00 = in_row0 + i0, *cp01 = in_row0 + i1; \
                        uint8_t *cp10 = in_row1 + i0, *cp11 = in_row1 + i1; \
                        float a00 = yf0 * xf0 * cp00[3], a01 = yf0 * xf1 * cp01[3]; \
                        float a10 = yf1 * xf0 * cp10[3], a11 = yf1 * xf1 * cp11[3]; \
-                       float fa = a00 + a01 + a10 + a11;  if( !fa ) continue;  fa *= fs; \
-                       type in_a = fa + r;  float s = 1./fa; \
+                       float fa = a00 + a01 + a10 + a11;  if( !fa ) continue;  \
+                       type in_a = fa*fr + r;  float s = fs/fa; \
                        type in_r = (cp00[0]*a00 + cp01[0]*a01 + cp10[0]*a10 + cp11[0]*a11)*s + r; \
                        type in_g = (cp00[1]*a00 + cp01[1]*a01 + cp10[1]*a10 + cp11[1]*a11)*s + r; \
                        type in_b = (cp00[2]*a00 + cp01[2]*a01 + cp10[2]*a10 + cp11[2]*a11)*s + r; \
@@ -2300,7 +2354,7 @@ void TitleMain::reset_render()
        title_glyphs.clear();
        title_images.clear();
        if( freetype_face ) {
-               FT_Done_Face(freetype_face);
+               ft_Done_Face(freetype_face);
                freetype_face = 0;
        }
 }
@@ -2308,52 +2362,15 @@ void TitleMain::reset_render()
 int TitleMain::init_freetype()
 {
        if( !freetype_library )
-               FT_Init_FreeType(&freetype_library);
+               ft_Init_FreeType(&freetype_library);
        return 0;
 }
 
 void TitleMain::draw_boundry()
 {
-       VFrame &out = *output;
-       int iw = output->get_w(), ih = output->get_h();
-       int mr = MIN(iw, ih)/200 + 2, rr = 2*mr;
-       int x = title_x, y = title_y, w = title_w, h = title_h;
-       int r2 = (rr+1)/2;
-       int x0 = x-r2, x1 = x+(w+1)/2, x2 = x+w+r2;
-       int y0 = y-r2, y1 = y+(h+1)/2, y2 = y+h+r2;
-       int st = 1;
-       for( int r=2; r<mr; r<<=1 ) st = r;
-       out.set_stiple(st);
-
-       for( int r=mr/2; --r>=0; ) { // bbox
-               int lft = x+r, rgt = x+w-1-r;
-               int top = y+r, bot = y+h-1-r;
-               out.draw_line(lft,top, rgt,top);
-               out.draw_line(rgt,top, rgt,bot);
-               out.draw_line(rgt,bot, lft,bot);
-               out.draw_line(lft,bot, lft,top);
-       }
-
-       for( int r=mr; r<rr; ++r ) { // center
-               out.draw_smooth(x1-r,y1, x1-r,y1+r, x1,y1+r);
-               out.draw_smooth(x1,y1+r, x1+r,y1+r, x1+r,y1);
-               out.draw_smooth(x1+r,y1, x1+r,y1-r, x1,y1-r);
-               out.draw_smooth(x1,y1-r, x1-r,y1-r, x1-r,y1);
-       }
-
-       for( int r=rr; --r>=0; ) { // edge arrows
-               out.draw_line(x1-r,y0+r, x1+r,y0+r);
-               out.draw_line(x2-r,y1-r, x2-r,y1+r);
-               out.draw_line(x1-r,y2-r, x1+r,y2-r);
-               out.draw_line(x0+r,y1+r, x0+r,y1-r);
-       }
-       x0 += r2;  y0 += r2;  x2 -= r2;  y2 -= r2;
-       for( int r=2*mr; --r>=0; ) { // corner arrows
-               out.draw_line(x0,y0+r, x0+r,y0);
-               out.draw_line(x2,y0+r, x2-r,y0);
-               out.draw_line(x2,y2-r, x2-r,y2);
-               out.draw_line(x0,y2-r, x0+r,y2);
-       }
+       if( !gui_open() ) return;
+       DragCheckBox::draw_boundary(output,
+               title_x, title_y, title_w, title_h);
 }
 
 
@@ -2498,7 +2515,7 @@ void TitleMain::save_data(KeyFrame *keyframe)
 {
        FileXML output;
 
-       output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
+       output.set_shared_output(keyframe->xbuf);
        output.tag.set_title("TITLE");
        output.tag.set_property("FONT", config.font);
        output.tag.set_property("ENCODING", config.encoding);
@@ -2534,19 +2551,12 @@ void TitleMain::save_data(KeyFrame *keyframe)
        output.tag.set_property("LOOP_PLAYBACK", config.loop_playback);
        output.append_tag();
        output.append_newline();
-       char text[2*sizeof(config.wtext)];
+       long tsz = 2*config.wsize + 0x1000;
+       char text[tsz];
        int text_len = BC_Resources::encode(
                BC_Resources::wide_encoding, DEFAULT_ENCODING,
                (char*)config.wtext, config.wlen*sizeof(wchar_t),
-               text, sizeof(text));
-       int len = output.length(), avail = MESSAGESIZE-16 - len;
-       if( text_len >= avail ) { // back off last utf8 char
-               text_len = avail;
-               while( text_len > 0 && (text[text_len-1] & 0xc0) == 0x80 )
-                       text[--text_len] = 0;
-               if( text_len > 0 )
-                       text[--text_len] = 0;
-       }
+               text, tsz);
        output.append_text(text, text_len);
        output.tag.set_title("/TITLE");
        output.append_tag();
@@ -2560,7 +2570,7 @@ void TitleMain::read_data(KeyFrame *keyframe)
 {
        FileXML input;
 
-       input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
+       input.set_shared_input(keyframe->xbuf);
 
        int result = 0;
 
@@ -2615,22 +2625,22 @@ void TitleMain::read_data(KeyFrame *keyframe)
 void TitleMain::insert_text(const wchar_t *wtxt, int pos)
 {
        int len = wcslen(wtxt);
-       wchar_t *wtext = config.wtext;
-       int wsize = sizeof(config.wtext)-1;
        int wlen = config.wlen;
        if( pos < 0 ) pos = 0;
        if( pos > wlen ) pos = wlen;
-
-       for( int i=wlen-1, j=wlen+len-1; i>=pos; --i,--j ) {
-               if( j >= wsize ) continue;
+       config.demand(wlen + len);
+       int wsize1 = config.wsize-1;
+       wchar_t *wtext = config.wtext;
+       for( int i=wlen, j=wlen+len; --i>=pos; ) {
+               if( --j >= wsize1 ) continue;
                wtext[j] = wtext[i];
        }
        for( int i=pos, j=0; j<len; ++i,++j ) {
-               if( i >= wsize ) break;
+               if( i >= wsize1 ) break;
                wtext[i] = wtxt[j];
        }
 
-       if( (wlen+=len) > wsize ) wlen = wsize;
+       if( (wlen+=len) > wsize1 ) wlen = wsize1;
        wtext[wlen] = 0;
        config.wlen = wlen;
 }