comparison libass/ass_render.c @ 19873:98d32b832c3a

Reduce code duplication in init_render_context(). Don't use glyph stroker for borderless glyphs.
author eugeni
date Sun, 17 Sep 2006 15:32:01 +0000
parents 07be98a5dd5f
children 55a39486f4a8
comparison
equal deleted inserted replaced
19872:8e50cba9fe03 19873:98d32b832c3a
377 text_info->glyphs[i].glyph, text_info->glyphs[i].outline_glyph, 377 text_info->glyphs[i].glyph, text_info->glyphs[i].outline_glyph,
378 &text_info->glyphs[i].bm, &text_info->glyphs[i].bm_o, text_info->glyphs[i].be); 378 &text_info->glyphs[i].bm, &text_info->glyphs[i].bm_o, text_info->glyphs[i].be);
379 if (error) 379 if (error)
380 text_info->glyphs[i].symbol = 0; 380 text_info->glyphs[i].symbol = 0;
381 FT_Done_Glyph(text_info->glyphs[i].glyph); 381 FT_Done_Glyph(text_info->glyphs[i].glyph);
382 FT_Done_Glyph(text_info->glyphs[i].outline_glyph); 382 if (text_info->glyphs[i].outline_glyph)
383 FT_Done_Glyph(text_info->glyphs[i].outline_glyph);
383 384
384 // cache 385 // cache
385 hash_val.bbox_scaled = text_info->glyphs[i].bbox; 386 hash_val.bbox_scaled = text_info->glyphs[i].bbox;
386 hash_val.bm_o = text_info->glyphs[i].bm_o; 387 hash_val.bm_o = text_info->glyphs[i].bm_o;
387 hash_val.bm = text_info->glyphs[i].bm; 388 hash_val.bm = text_info->glyphs[i].bm;
392 } 393 }
393 } 394 }
394 395
395 for (i = 0; i < text_info->length; ++i) { 396 for (i = 0; i < text_info->length; ++i) {
396 glyph_info_t* info = text_info->glyphs + i; 397 glyph_info_t* info = text_info->glyphs + i;
397 if ((info->symbol == 0) || (info->symbol == '\n')) 398 if ((info->symbol == 0) || (info->symbol == '\n') || !info->bm_o)
398 continue; 399 continue;
399 400
400 pen_x = dst_x + info->pos.x; 401 pen_x = dst_x + info->pos.x;
401 pen_y = dst_y + info->pos.y; 402 pen_y = dst_y + info->pos.y;
402 bm = info->bm_o; 403 bm = info->bm_o;
406 } else 407 } else
407 tail = render_glyph(bm, pen_x, pen_y, info->c[2], 0, 1000000, tail); 408 tail = render_glyph(bm, pen_x, pen_y, info->c[2], 0, 1000000, tail);
408 } 409 }
409 for (i = 0; i < text_info->length; ++i) { 410 for (i = 0; i < text_info->length; ++i) {
410 glyph_info_t* info = text_info->glyphs + i; 411 glyph_info_t* info = text_info->glyphs + i;
411 if ((info->symbol == 0) || (info->symbol == '\n')) 412 if ((info->symbol == 0) || (info->symbol == '\n') || !info->bm)
412 continue; 413 continue;
413 414
414 pen_x = dst_x + info->pos.x; 415 pen_x = dst_x + info->pos.x;
415 pen_y = dst_y + info->pos.y; 416 pen_y = dst_y + info->pos.y;
416 bm = info->bm; 417 bm = info->bm;
557 } 558 }
558 559
559 if (render_context.face) 560 if (render_context.face)
560 { 561 {
561 change_font_size(render_context.font_size); 562 change_font_size(render_context.font_size);
563
564 if (render_context.stroker != 0) {
565 FT_Stroker_Done(render_context.stroker);
566 render_context.stroker = 0;
567 }
568 #if (FREETYPE_MAJOR > 2) || ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR > 1))
569 error = FT_Stroker_New( ass_instance->library, &render_context.stroker );
570 #else // < 2.2
571 error = FT_Stroker_New( render_context.face->memory, &render_context.stroker );
572 #endif
573 if ( error ) {
574 mp_msg(MSGT_GLOBAL, MSGL_V, "failed to get stroker\n");
575 render_context.stroker = 0;
576 }
562 } 577 }
563 } 578 }
564 579
565 /** 580 /**
566 * \brief Change border width 581 * \brief Change border width
582 * negative value resets border to style value
567 */ 583 */
568 static void change_border(double border) 584 static void change_border(double border)
569 { 585 {
570 if (!render_context.stroker) { 586 if (!render_context.stroker) {
571 if (!no_more_font_messages) 587 if (!no_more_font_messages)
572 mp_msg(MSGT_GLOBAL, MSGL_WARN, "No stroker!\n"); 588 mp_msg(MSGT_GLOBAL, MSGL_WARN, "No stroker!\n");
573 } else { 589 } else {
590 int b;
591 if (border < 0) {
592 if (render_context.style->BorderStyle == 1) {
593 if (render_context.style->Outline == 0 && render_context.style->Shadow > 0)
594 border = 1.;
595 else
596 border = render_context.style->Outline;
597 } else
598 border = 1.;
599 }
574 render_context.border = border; 600 render_context.border = border;
575 FT_Stroker_Set( render_context.stroker, 601
576 (int)(64 * border * frame_context.font_scale), 602 b = 64 * border * frame_context.font_scale;
603 if (b > 0)
604 FT_Stroker_Set( render_context.stroker, b,
577 FT_STROKER_LINECAP_ROUND, 605 FT_STROKER_LINECAP_ROUND,
578 FT_STROKER_LINEJOIN_ROUND, 606 FT_STROKER_LINEJOIN_ROUND,
579 0 ); 607 0 );
608 else {
609 FT_Stroker_Done(render_context.stroker);
610 render_context.stroker = 0;
611 }
580 } 612 }
581 } 613 }
582 614
583 #define _r(c) ((c)>>24) 615 #define _r(c) ((c)>>24)
584 #define _g(c) (((c)>>16)&0xFF) 616 #define _g(c) (((c)>>16)&0xFF)
639 a = a2; 671 a = a2;
640 } 672 }
641 673
642 return a; 674 return a;
643 } 675 }
676
677 static void reset_render_context();
644 678
645 /** 679 /**
646 * \brief Parse style override tag. 680 * \brief Parse style override tag.
647 * \param p string to parse 681 * \param p string to parse
648 * \param pwr multiplier for some tag effects (comes from \t tags) 682 * \param pwr multiplier for some tag effects (comes from \t tags)
689 } else if (mystrcmp(&p, "bord")) { 723 } else if (mystrcmp(&p, "bord")) {
690 double val; 724 double val;
691 if (mystrtod(&p, &val)) 725 if (mystrtod(&p, &val))
692 val = render_context.border * ( 1 - pwr ) + val * pwr; 726 val = render_context.border * ( 1 - pwr ) + val * pwr;
693 else 727 else
694 val = (render_context.style->BorderStyle == 1) ? render_context.style->Outline : 1.; 728 val = -1.; // reset to default
695 change_border(val); 729 change_border(val);
696 } else if (mystrcmp(&p, "move")) { 730 } else if (mystrcmp(&p, "move")) {
697 int x1, x2, y1, y2; 731 int x1, x2, y1, y2;
698 long long t1, t2, delta_t, t; 732 long long t1, t2, delta_t, t;
699 int x, y; 733 int x, y;
921 case 'a': change_alpha(render_context.c + cidx, val >> 24, pwr); break; 955 case 'a': change_alpha(render_context.c + cidx, val >> 24, pwr); break;
922 default: mp_msg(MSGT_GLOBAL, MSGL_WARN, "Bad command: %c%c\n", n, cmd); break; 956 default: mp_msg(MSGT_GLOBAL, MSGL_WARN, "Bad command: %c%c\n", n, cmd); break;
923 } 957 }
924 mp_msg(MSGT_GLOBAL, MSGL_DBG2, "single c/a at %f: %c%c = %X \n", pwr, n, cmd, render_context.c[cidx]); 958 mp_msg(MSGT_GLOBAL, MSGL_DBG2, "single c/a at %f: %c%c = %X \n", pwr, n, cmd, render_context.c[cidx]);
925 } else if (mystrcmp(&p, "r")) { 959 } else if (mystrcmp(&p, "r")) {
926 render_context.c[0] = render_context.style->PrimaryColour; 960 reset_render_context();
927 render_context.c[1] = render_context.style->SecondaryColour;
928 render_context.c[2] = render_context.style->OutlineColour;
929 render_context.c[3] = render_context.style->BackColour;
930 render_context.font_size = render_context.style->FontSize;
931
932 if (render_context.family)
933 free(render_context.family);
934 render_context.family = strdup(render_context.style->FontName);
935 render_context.bold = - render_context.style->Bold;
936 render_context.italic = - render_context.style->Italic;
937 update_font();
938
939 if (render_context.stroker) {
940 double border = (render_context.style->BorderStyle == 1) ? render_context.style->Outline : 1.;
941 change_border(border);
942 }
943 render_context.scale_x = render_context.style->ScaleX;
944 render_context.scale_y = render_context.style->ScaleY;
945 render_context.hspacing = 0; // FIXME
946
947 // FIXME: does not reset unsupported attributes.
948 } else if (mystrcmp(&p, "be")) { 961 } else if (mystrcmp(&p, "be")) {
949 int val; 962 int val;
950 if (mystrtoi(&p, 10, &val)) 963 if (mystrtoi(&p, 10, &val))
951 render_context.be = val ? 1 : 0; 964 render_context.be = val ? 1 : 0;
952 else 965 else
1104 } 1117 }
1105 1118
1106 } 1119 }
1107 1120
1108 /** 1121 /**
1122 * \brief partially reset render_context to style values
1123 * Works like {\r}: resets some style overrides
1124 */
1125 static void reset_render_context(void)
1126 {
1127 render_context.c[0] = render_context.style->PrimaryColour;
1128 render_context.c[1] = render_context.style->SecondaryColour;
1129 render_context.c[2] = render_context.style->OutlineColour;
1130 render_context.c[3] = render_context.style->BackColour;
1131 render_context.font_size = render_context.style->FontSize;
1132
1133 if (render_context.family)
1134 free(render_context.family);
1135 render_context.family = strdup(render_context.style->FontName);
1136 render_context.bold = - render_context.style->Bold;
1137 render_context.italic = - render_context.style->Italic;
1138 update_font();
1139
1140 change_border(-1.);
1141 render_context.scale_x = render_context.style->ScaleX;
1142 render_context.scale_y = render_context.style->ScaleY;
1143 render_context.hspacing = 0; // FIXME
1144 render_context.be = 0;
1145
1146 // FIXME: does not reset unsupported attributes.
1147 }
1148
1149 /**
1109 * \brief Start new event. Reset render_context. 1150 * \brief Start new event. Reset render_context.
1110 */ 1151 */
1111 static int init_render_context(ass_event_t* event) 1152 static void init_render_context(ass_event_t* event)
1112 { 1153 {
1113 int error;
1114
1115 // init render_context
1116 render_context.event = event; 1154 render_context.event = event;
1117 render_context.style = frame_context.track->styles + event->Style; 1155 render_context.style = frame_context.track->styles + event->Style;
1118 1156
1119 render_context.font_size = render_context.style->FontSize; 1157 reset_render_context();
1158
1120 render_context.evt_type = EVENT_NORMAL; 1159 render_context.evt_type = EVENT_NORMAL;
1121 render_context.alignment = 0; 1160 render_context.alignment = 0;
1122 render_context.rotation = M_PI * render_context.style->Angle / 180.; 1161 render_context.rotation = M_PI * render_context.style->Angle / 180.;
1123 render_context.pos_x = 0; 1162 render_context.pos_x = 0;
1124 render_context.pos_y = 0; 1163 render_context.pos_y = 0;
1125 render_context.org_x = 0; 1164 render_context.org_x = 0;
1126 render_context.org_y = 0; 1165 render_context.org_y = 0;
1127 render_context.scale_x = render_context.style->ScaleX;
1128 render_context.scale_y = render_context.style->ScaleY;
1129 render_context.hspacing = 0;
1130 render_context.c[0] = render_context.style->PrimaryColour;
1131 render_context.c[1] = render_context.style->SecondaryColour;
1132 render_context.c[2] = render_context.style->OutlineColour;
1133 render_context.c[3] = render_context.style->BackColour;
1134 render_context.clip_x0 = 0; 1166 render_context.clip_x0 = 0;
1135 render_context.clip_y0 = 0; 1167 render_context.clip_y0 = 0;
1136 render_context.clip_x1 = frame_context.track->PlayResX; 1168 render_context.clip_x1 = frame_context.track->PlayResX;
1137 render_context.clip_y1 = frame_context.track->PlayResY; 1169 render_context.clip_y1 = frame_context.track->PlayResY;
1138 render_context.detect_collisions = 1; 1170 render_context.detect_collisions = 1;
1139 render_context.fade = 0; 1171 render_context.fade = 0;
1140 render_context.effect_type = EF_NONE; 1172 render_context.effect_type = EF_NONE;
1141 render_context.effect_timing = 0; 1173 render_context.effect_timing = 0;
1142 render_context.effect_skip_timing = 0; 1174 render_context.effect_skip_timing = 0;
1143 render_context.be = 0; 1175
1144
1145 if (render_context.family)
1146 free(render_context.family);
1147 render_context.family = strdup(render_context.style->FontName);
1148 render_context.bold = - render_context.style->Bold; // style value for bold text is -1
1149 render_context.italic = - render_context.style->Italic;
1150
1151 update_font();
1152
1153 if (render_context.face) {
1154 #if (FREETYPE_MAJOR > 2) || ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR > 1))
1155 error = FT_Stroker_New( ass_instance->library, &render_context.stroker );
1156 #else // < 2.2
1157 error = FT_Stroker_New( render_context.face->memory, &render_context.stroker );
1158 #endif
1159 if ( error ) {
1160 mp_msg(MSGT_GLOBAL, MSGL_V, "failed to get stroker\n");
1161 render_context.stroker = 0;
1162 } else {
1163 // FIXME: probably wrong when render_context.Border == 3
1164 double border = (render_context.style->BorderStyle == 1) ? render_context.style->Outline : 1.;
1165 change_border(border);
1166 }
1167 }
1168
1169 apply_transition_effects(event); 1176 apply_transition_effects(event);
1170 1177 }
1171 return 0; 1178
1172 } 1179 static void free_render_context(void)
1173
1174 static int free_render_context(void)
1175 { 1180 {
1176 if (render_context.stroker != 0) { 1181 if (render_context.stroker != 0) {
1177 FT_Stroker_Done(render_context.stroker); 1182 FT_Stroker_Done(render_context.stroker);
1178 render_context.stroker = 0; 1183 render_context.stroker = 0;
1179 } 1184 }
1180 return 0;
1181 } 1185 }
1182 1186
1183 /** 1187 /**
1184 * \brief Get normal and outline glyphs from cache (if possible) or font face 1188 * \brief Get normal and outline glyphs from cache (if possible) or font face
1185 * \param index face glyph index 1189 * \param index face glyph index
1245 } 1249 }
1246 1250
1247 info->advance.x = info->glyph->advance.x >> 10; 1251 info->advance.x = info->glyph->advance.x >> 10;
1248 info->advance.y = info->glyph->advance.y >> 10; 1252 info->advance.y = info->glyph->advance.y >> 10;
1249 1253
1250 info->outline_glyph = info->glyph; 1254 if (render_context.stroker) {
1251 error = FT_Glyph_Stroke( &(info->outline_glyph), render_context.stroker, 0 ); // don't destroy original 1255 info->outline_glyph = info->glyph;
1252 if (error) { 1256 error = FT_Glyph_Stroke( &(info->outline_glyph), render_context.stroker, 0 ); // don't destroy original
1253 mp_msg(MSGT_GLOBAL, MSGL_WARN, "FT_Glyph_Stroke error %d \n", error); 1257 if (error) {
1254 FT_Glyph_Copy(info->glyph, &info->outline_glyph); 1258 mp_msg(MSGT_GLOBAL, MSGL_WARN, "FT_Glyph_Stroke error %d \n", error);
1259 }
1260 } else {
1261 info->outline_glyph = 0;
1255 } 1262 }
1256 1263
1257 info->bm = info->bm_o = 0; 1264 info->bm = info->bm_o = 0;
1258 1265
1259 return 0; 1266 return 0;
1817 1824
1818 info->pos.x += start.x >> 6; 1825 info->pos.x += start.x >> 6;
1819 info->pos.y -= start.y >> 6; 1826 info->pos.y -= start.y >> 6;
1820 1827
1821 // mp_msg(MSGT_GLOBAL, MSGL_DBG2, "shift: %d, %d\n", start.x / 64, start.y / 64); 1828 // mp_msg(MSGT_GLOBAL, MSGL_DBG2, "shift: %d, %d\n", start.x / 64, start.y / 64);
1822 if (info->glyph) { 1829 if (info->glyph)
1823 FT_Glyph_Transform( info->glyph, &matrix_rotate, 0 ); 1830 FT_Glyph_Transform( info->glyph, &matrix_rotate, 0 );
1831 if (info->outline_glyph)
1824 FT_Glyph_Transform( info->outline_glyph, &matrix_rotate, 0 ); 1832 FT_Glyph_Transform( info->outline_glyph, &matrix_rotate, 0 );
1825 }
1826 } 1833 }
1827 } 1834 }
1828 1835
1829 event_images->top = device_y - (text_info.lines[0].asc >> 6); 1836 event_images->top = device_y - (text_info.lines[0].asc >> 6);
1830 event_images->height = text_info.height >> 6; 1837 event_images->height = text_info.height >> 6;