]> granicus.if.org Git - libass/commitdiff
Fix subpixel shadow shift
authorDr.Smile <vabnick@gmail.com>
Wed, 5 Nov 2014 23:57:03 +0000 (02:57 +0300)
committerDr.Smile <vabnick@gmail.com>
Wed, 5 Nov 2014 23:57:03 +0000 (02:57 +0300)
libass/ass_bitmap.c
libass/ass_render.c

index 1f719f8af9b04a4f338580c9d6ee0272718e1c41..9a98f5a7ab5af339867468ab748b5388d9984c17 100644 (file)
@@ -327,45 +327,23 @@ void shift_bitmap(Bitmap *bm, int shift_x, int shift_y)
     int s = bm->stride;
     unsigned char *buf = bm->buffer;
 
+    assert((shift_x & ~63) == 0 && (shift_y & ~63) == 0);
+
     // Shift in x direction
-    if (shift_x > 0) {
-        shift_x &= 0x3F;
-        for (y = 0; y < h; y++) {
-            for (x = w - 1; x > 0; x--) {
-                b = (buf[x + y * s - 1] * shift_x) >> 6;
-                buf[x + y * s - 1] -= b;
-                buf[x + y * s] += b;
-            }
-        }
-    } else if (shift_x < 0) {
-        shift_x = -shift_x & 0x3F;
-        for (y = 0; y < h; y++) {
-            for (x = 0; x < w - 1; x++) {
-                b = (buf[x + y * s + 1] * shift_x) >> 6;
-                buf[x + y * s + 1] -= b;
-                buf[x + y * s] += b;
-            }
+    for (y = 0; y < h; y++) {
+        for (x = w - 1; x > 0; x--) {
+            b = (buf[x + y * s - 1] * shift_x) >> 6;
+            buf[x + y * s - 1] -= b;
+            buf[x + y * s] += b;
         }
     }
 
     // Shift in y direction
-    if (shift_y > 0) {
-        shift_y &= 0x3F;
-        for (x = 0; x < w; x++) {
-            for (y = h - 1; y > 0; y--) {
-                b = (buf[x + (y - 1) * s] * shift_y) >> 6;
-                buf[x + (y - 1) * s] -= b;
-                buf[x + y * s] += b;
-            }
-        }
-    } else if (shift_y < 0) {
-        shift_y = -shift_y & 0x3F;
-        for (x = 0; x < w; x++) {
-            for (y = 0; y < h - 1; y++) {
-                b = (buf[x + (y + 1) * s] * shift_y) >> 6;
-                buf[x + (y + 1) * s] -= b;
-                buf[x + y * s] += b;
-            }
+    for (x = 0; x < w; x++) {
+        for (y = h - 1; y > 0; y--) {
+            b = (buf[x + (y - 1) * s] * shift_y) >> 6;
+            buf[x + (y - 1) * s] -= b;
+            buf[x + y * s] += b;
         }
     }
 }
index 8d942f6a0ed164189e85d57f187673e81e96cdf5..d1a47ee70b561b08278805b2a9ccfed007fa45d3 100644 (file)
@@ -675,12 +675,8 @@ static ASS_Image *render_text(ASS_Renderer *render_priv, int dst_x, int dst_y)
         if (render_priv->state.border_style == 4)
             continue;
 
-        pen_x =
-            dst_x + info->pos.x +
-            (int) (info->shadow_x * render_priv->border_scale);
-        pen_y =
-            dst_y + info->pos.y +
-            (int) (info->shadow_y * render_priv->border_scale);
+        pen_x = dst_x + info->pos.x;
+        pen_y = dst_y + info->pos.y;
         bm = info->bm_s;
 
         tail =
@@ -1724,12 +1720,10 @@ fill_bitmap_hash(ASS_Renderer *priv, GlyphInfo *info,
     hash_key->fay = double_to_d16(info->fay);
     hash_key->be = info->be;
     hash_key->blur = info->blur;
-    hash_key->shadow_offset.x = double_to_d6(
-            info->shadow_x * priv->border_scale -
-            (int) (info->shadow_x * priv->border_scale));
-    hash_key->shadow_offset.y = double_to_d6(
-            info->shadow_y * priv->border_scale -
-            (int) (info->shadow_y * priv->border_scale));
+    hash_key->shadow_offset.x =
+        double_to_d6(info->shadow_x * priv->border_scale) & SUBPIXEL_MASK;
+    hash_key->shadow_offset.y =
+        double_to_d6(info->shadow_y * priv->border_scale) & SUBPIXEL_MASK;
 }
 
 /**
@@ -1869,7 +1863,7 @@ static void apply_blur(CombinedBitmapInfo *info, ASS_Renderer *render_priv)
     }
 }
 
-static void make_shadow_bitmap(CombinedBitmapInfo *info)
+static void make_shadow_bitmap(CombinedBitmapInfo *info, ASS_Renderer *render_priv)
 {
     // VSFilter compatibility: invisible fill and no border?
     // In this case no shadow is supposed to be rendered.
@@ -1891,7 +1885,13 @@ static void make_shadow_bitmap(CombinedBitmapInfo *info)
 
     assert(info->bm_s);
 
-    shift_bitmap(info->bm_s, info->shadow_x, info->shadow_y);
+    // Works right even for negative offsets
+    // '>>' rounds toward negative infinity, '&' returns correct remainder
+    int offset_x = double_to_d6(info->shadow_x * render_priv->border_scale);
+    int offset_y = double_to_d6(info->shadow_y * render_priv->border_scale);
+    info->bm_s->left += offset_x >> 6;
+    info->bm_s->top  += offset_y >> 6;
+    shift_bitmap(info->bm_s, offset_x & SUBPIXEL_MASK, offset_y & SUBPIXEL_MASK);
 }
 
 /**
@@ -2603,7 +2603,7 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event,
             CombinedBitmapInfo *info = &combined_info[i];
             if(info->bm || info->bm_o){
                 apply_blur(info, render_priv);
-                make_shadow_bitmap(info);
+                make_shadow_bitmap(info, render_priv);
             }
 
             fill_composite_hash(&hk, info);