emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master b257a7894b: Implement "flip" image transforms on Haiku


From: Po Lu
Subject: master b257a7894b: Implement "flip" image transforms on Haiku
Date: Sat, 25 Jun 2022 02:23:38 -0400 (EDT)

branch: master
commit b257a7894b6b8536ee16e6b334207c8f5c887280
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Implement "flip" image transforms on Haiku
    
    * src/dispextern.h (struct image): New field `transform',
    `original_width' and `original_height'.
    * src/haiku_draw_support.cc (BView_DrawMask): Rename to
    `be_draw_image_mask' and fix coding style.
    (rotate_bitmap_270, BBitmap_transform_bitmap, rotate_bitmap_90):
    Delete functions.
    (be_apply_affine_transform): New function.
    (be_apply_inverse_transform): New function.
    
    * src/haiku_support.h: Update prototypes.
    
    * src/haikuterm.c (haiku_translate_transform): New function.
    (haiku_draw_image_glyph_string): Use affine transforms to
    implement images.
    
    * src/image.c (image_set_transform): Implement using affine
    transforms on Haiku too.
---
 src/dispextern.h          |  11 ++--
 src/haiku_draw_support.cc | 132 +++++++++++-----------------------------------
 src/haiku_support.h       |  11 ++--
 src/haikuterm.c           |  74 +++++++++++++++++---------
 src/image.c               | 104 +++++++++++++++++++++++-------------
 5 files changed, 159 insertions(+), 173 deletions(-)

diff --git a/src/dispextern.h b/src/dispextern.h
index 8bcd13dbb6..797b4730cd 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -3070,7 +3070,7 @@ struct image
      Non-NULL means it and its Pixmap counterpart may be out of sync
      and the latter is outdated.  NULL means the X image has been
      synchronized to Pixmap.  */
-  XImage *ximg, *mask_img;
+v  XImage *ximg, *mask_img;
 
 # if !defined USE_CAIRO && defined HAVE_XRENDER
   /* Picture versions of pixmap and mask for compositing.  */
@@ -3085,12 +3085,11 @@ struct image
   XFORM xform;
 #endif
 #ifdef HAVE_HAIKU
-  /* Non-zero if the image has not yet been transformed for display.  */
-  int have_be_transforms_p;
+  /* The affine transformation to apply to this image.  */
+  double transform[3][3];
 
-  double be_rotate;
-  double be_scale_x;
-  double be_scale_y;
+  /* The original width and height of the image.  */
+  int original_width, original_height;
 #endif
 
   /* Colors allocated for this image, if any.  Allocated via xmalloc.  */
diff --git a/src/haiku_draw_support.cc b/src/haiku_draw_support.cc
index f0cc084bb3..768ffdabf8 100644
--- a/src/haiku_draw_support.cc
+++ b/src/haiku_draw_support.cc
@@ -357,134 +357,64 @@ BView_DrawBitmapWithEraseOp (void *view, void *bitmap, 
int x,
 }
 
 void
-BView_DrawMask (void *src, void *view,
-               int x, int y, int width, int height,
-               int vx, int vy, int vwidth, int vheight,
-               uint32_t color)
+be_draw_image_mask (void *src, void *view, int x, int y, int width,
+                   int height, int vx, int vy, int vwidth, int vheight,
+                   uint32_t color)
 {
   BBitmap *source = (BBitmap *) src;
   BBitmap bm (source->Bounds (), B_RGBA32);
   BRect bounds = bm.Bounds ();
+  int bx, by, bit;
+  BView *vw;
 
   if (bm.InitCheck () != B_OK)
     return;
-  for (int y = 0; y < BE_RECT_HEIGHT (bounds); ++y)
+
+  /* Fill the background color or transparency into the bitmap,
+     depending on the value of the mask.  */
+  for (by = 0; by < BE_RECT_HEIGHT (bounds); ++by)
     {
-      for (int x = 0; x < BE_RECT_WIDTH (bounds); ++x)
+      for (bx = 0; bx < BE_RECT_WIDTH (bounds); ++bx)
        {
-         int bit = haiku_get_pixel ((void *) source, x, y);
+         bit = haiku_get_pixel ((void *) source, bx, by);
 
          if (!bit)
-           haiku_put_pixel ((void *) &bm, x, y, ((uint32_t) 255 << 24) | 
color);
+           haiku_put_pixel ((void *) &bm, bx, by,
+                            ((uint32_t) 255 << 24) | color);
          else
-           haiku_put_pixel ((void *) &bm, x, y, 0);
+           haiku_put_pixel ((void *) &bm, bx, by, 0);
        }
     }
-  BView *vw = get_view (view);
+
+  vw = get_view (view);
   vw->SetDrawingMode (B_OP_OVER);
   vw->DrawBitmap (&bm, BRect (x, y, x + width - 1, y + height - 1),
                  BRect (vx, vy, vx + vwidth - 1, vy + vheight - 1));
   vw->SetDrawingMode (B_OP_COPY);
 }
 
-static BBitmap *
-rotate_bitmap_270 (BBitmap *bmp)
-{
-  BRect r = bmp->Bounds ();
-  BBitmap *bm = new BBitmap (BRect (r.top, r.left, r.bottom, r.right),
-                            bmp->ColorSpace (), true);
-  if (bm->InitCheck () != B_OK)
-    gui_abort ("Failed to init bitmap for rotate");
-  int w = BE_RECT_WIDTH (r);
-  int h = BE_RECT_HEIGHT (r);
-
-  for (int y = 0; y < h; ++y)
-    for (int x = 0; x < w; ++x)
-      haiku_put_pixel ((void *) bm, y, w - x - 1,
-                      haiku_get_pixel ((void *) bmp, x, y));
-
-  return bm;
-}
-
-static BBitmap *
-rotate_bitmap_90 (BBitmap *bmp)
+void
+be_apply_affine_transform (void *view, double m0, double m1, double tx,
+                          double m2, double m3, double ty)
 {
-  BRect r = bmp->Bounds ();
-  BBitmap *bm = new BBitmap (BRect (r.top, r.left, r.bottom, r.right),
-                            bmp->ColorSpace (), true);
-  if (bm->InitCheck () != B_OK)
-    gui_abort ("Failed to init bitmap for rotate");
-  int w = BE_RECT_WIDTH (r);
-  int h = BE_RECT_HEIGHT (r);
+  BAffineTransform transform (m0, m2, m1, m3, tx, ty);
 
-  for (int y = 0; y < h; ++y)
-    for (int x = 0; x < w; ++x)
-      haiku_put_pixel ((void *) bm, h - y - 1, x,
-                      haiku_get_pixel ((void *) bmp, x, y));
-
-  return bm;
+  get_view (view)->SetTransform (transform);
 }
 
-void *
-BBitmap_transform_bitmap (void *bitmap, void *mask, uint32_t m_color,
-                         double rot, int desw, int desh)
+void
+be_apply_inverse_transform (double (*matrix3x3)[3], int x, int y,
+                           int *x_out, int *y_out)
 {
-  BBitmap *bm = (BBitmap *) bitmap;
-  BBitmap *mk = (BBitmap *) mask;
-  int copied_p = 0;
+  BAffineTransform transform (matrix3x3[0][0], matrix3x3[1][0],
+                             matrix3x3[0][1], matrix3x3[1][1],
+                             matrix3x3[0][2], matrix3x3[1][2]);
+  BPoint point (x, y);
 
-  if (rot == 90)
-    {
-      copied_p = 1;
-      bm = rotate_bitmap_90 (bm);
-      if (mk)
-       mk = rotate_bitmap_90 (mk);
-    }
-
-  if (rot == 270)
-    {
-      copied_p = 1;
-      bm = rotate_bitmap_270 (bm);
-      if (mk)
-       mk = rotate_bitmap_270 (mk);
-    }
-
-  BRect n = BRect (0, 0, desw - 1, desh - 1);
-  BView vw (n, NULL, B_FOLLOW_NONE, 0);
-  BBitmap *dst = new BBitmap (n, bm->ColorSpace (), true);
-  if (dst->InitCheck () != B_OK)
-    if (bm->InitCheck () != B_OK)
-      gui_abort ("Failed to init bitmap for scale");
-  dst->AddChild (&vw);
+  transform.ApplyInverse (&point);
 
-  if (!vw.LockLooper ())
-    gui_abort ("Failed to lock offscreen view for scale");
-
-  if (rot != 90 && rot != 270)
-    {
-      BAffineTransform tr;
-      tr.RotateBy (BPoint (desw / 2, desh / 2), rot * M_PI / 180.0);
-      vw.SetTransform (tr);
-    }
-
-  vw.MovePenTo (0, 0);
-  vw.DrawBitmap (bm, n);
-  if (mk)
-    {
-      BRect k = mk->Bounds ();
-      BView_DrawMask ((void *) mk, (void *) &vw,
-                     0, 0, BE_RECT_WIDTH (k),
-                     BE_RECT_HEIGHT (k),
-                     0, 0, desw, desh, m_color);
-    }
-  vw.Sync ();
-  vw.RemoveSelf ();
-
-  if (copied_p)
-    delete bm;
-  if (copied_p && mk)
-    delete mk;
-  return dst;
+  *x_out = std::floor (point.x);
+  *y_out = std::floor (point.y);
 }
 
 void
diff --git a/src/haiku_support.h b/src/haiku_support.h
index 3484fe0bbe..fcdf6bcb15 100644
--- a/src/haiku_support.h
+++ b/src/haiku_support.h
@@ -560,8 +560,6 @@ extern void BView_InvertRect (void *, int, int, int, int);
 extern void BView_DrawBitmap (void *, void *, int, int, int, int, int, int,
                              int, int);
 extern void BView_DrawBitmapWithEraseOp (void *, void *, int, int, int, int);
-extern void BView_DrawMask (void *, void *, int, int, int, int,        int, 
int,
-                           int, int, uint32_t);
 extern void BView_DrawBitmapTiled (void *, void *, int, int,
                                   int, int, int, int, int, int);
 
@@ -570,8 +568,13 @@ extern void BView_set_view_cursor (void *, void *);
 extern void BView_move_frame (void *, int, int, int, int);
 extern void BView_scroll_bar_update (void *, int, int, int, int, bool);
 
-extern void *BBitmap_transform_bitmap (void *, void *, uint32_t, double,
-                                      int, int);
+extern void *be_transform_bitmap (void *, void *, uint32_t, double,
+                                 int, int, bool);
+extern void be_apply_affine_transform (void *, double, double, double,
+                                      double, double, double);
+extern void be_apply_inverse_transform (double (*)[3], int, int, int *, int *);
+extern void be_draw_image_mask (void *, void *, int, int, int, int, int, int,
+                               int, int, uint32_t);
 
 extern void be_get_display_resolution (double *, double *);
 extern void be_get_screen_dimensions (int *, int *);
diff --git a/src/haikuterm.c b/src/haikuterm.c
index a90955ebe7..7c307afa32 100644
--- a/src/haikuterm.c
+++ b/src/haikuterm.c
@@ -1629,6 +1629,14 @@ haiku_draw_image_relief (struct glyph_string *s)
                          top_p, bot_p, left_p, right_p, &r);
 }
 
+static void
+haiku_translate_transform (double (*transform)[3], double dx,
+                          double dy)
+{
+  transform[0][2] += dx;
+  transform[1][2] += dy;
+}
+
 static void
 haiku_draw_image_glyph_string (struct glyph_string *s)
 {
@@ -1640,6 +1648,7 @@ haiku_draw_image_glyph_string (struct glyph_string *s)
   struct haiku_rect nr;
   Emacs_Rectangle cr, ir, r;
   unsigned long background;
+  double image_transform[3][3];
 
   height = s->height;
   if (s->slice.y == 0)
@@ -1701,34 +1710,51 @@ haiku_draw_image_glyph_string (struct glyph_string *s)
 
       if (gui_intersect_rectangles (&cr, &ir, &r))
        {
-         if (s->img->have_be_transforms_p)
-           {
-             bitmap = BBitmap_transform_bitmap (bitmap,
-                                                s->img->mask,
-                                                face->background,
-                                                s->img->be_rotate,
-                                                s->img->width,
-                                                s->img->height);
-             mask = NULL;
-           }
+         memcpy (&image_transform, &s->img->transform,
+                 sizeof image_transform);
 
-         BView_DrawBitmap (view, bitmap,
-                           s->slice.x + r.x - x,
-                           s->slice.y + r.y - y,
-                           r.width, r.height,
-                           r.x, r.y, r.width, r.height);
-         if (mask)
+         if (s->slice.x != x || s->slice.y != y
+             || s->slice.width != s->img->width
+             || s->slice.height != s->img->height)
            {
-             BView_DrawMask (mask, view,
-                             s->slice.x + r.x - x,
-                             s->slice.y + r.y - y,
-                             r.width, r.height,
-                             r.x, r.y, r.width, r.height,
-                             face->background);
+             BView_StartClip (view);
+             BView_ClipToRect (view, r.x, r.y, r.width, r.height);
            }
 
-         if (s->img->have_be_transforms_p)
-           BBitmap_free (bitmap);
+         haiku_translate_transform (image_transform,
+                                    x - s->slice.x,
+                                    y - s->slice.y);
+
+         be_apply_affine_transform (view,
+                                    image_transform[0][0],
+                                    image_transform[0][1],
+                                    image_transform[0][2],
+                                    image_transform[1][0],
+                                    image_transform[1][1],
+                                    image_transform[1][2]);
+
+         BView_DrawBitmap (view, bitmap, 0, 0,
+                           s->img->original_width,
+                           s->img->original_height,
+                           0, 0,
+                           s->img->original_width,
+                           s->img->original_height);
+
+         if (mask)
+           be_draw_image_mask (mask, view, 0, 0,
+                               s->img->original_width,
+                               s->img->original_height,
+                               0, 0,
+                               s->img->original_width,
+                               s->img->original_height,
+                               face->background);
+
+         if (s->slice.x != x || s->slice.y != y
+             || s->slice.width != s->img->width
+             || s->slice.height != s->img->height)
+           BView_EndClip (view);
+
+         be_apply_affine_transform (view, 1, 0, 0, 0, 1, 0);
        }
 
       if (!s->img->mask)
diff --git a/src/image.c b/src/image.c
index 0e4b2e0f62..5e98945df5 100644
--- a/src/image.c
+++ b/src/image.c
@@ -2503,17 +2503,17 @@ compute_image_size (double width, double height,
    finally move the origin back to the top left of the image, which
    may now be a different corner.
 
-   Note that different GUI backends (X, Cairo, w32, NS) want the
-   transform matrix defined as transform from the original image to
-   the transformed image, while others want the matrix to describe the
-   transform of the space, which boils down to inverting the matrix.
+   Note that different GUI backends (X, Cairo, w32, NS, Haiku) want
+   the transform matrix defined as transform from the original image
+   to the transformed image, while others want the matrix to describe
+   the transform of the space, which boils down to inverting the
+   matrix.
 
    It's possible to pre-calculate the matrix multiplications and just
    generate one transform matrix that will do everything we need in a
    single step, but the maths for each element is much more complex
    and performing the steps separately makes for more readable code.  */
 
-#ifndef HAVE_HAIKU
 typedef double matrix3x3[3][3];
 
 static void
@@ -2528,7 +2528,6 @@ matrix3x3_mult (matrix3x3 a, matrix3x3 b, matrix3x3 
result)
        result[i][j] = sum;
       }
 }
-#endif /* not HAVE_HAIKU */
 
 static void
 compute_image_rotation (struct image *img, double *rotation)
@@ -2553,6 +2552,21 @@ compute_image_rotation (struct image *img, double 
*rotation)
 static void
 image_set_transform (struct frame *f, struct image *img)
 {
+  bool flip;
+
+#if defined HAVE_HAIKU
+  matrix3x3 identity = {
+    { 1, 0, 0 },
+    { 0, 1, 0 },
+    { 0, 0, 1 },
+  };
+
+  img->original_width = img->width;
+  img->original_height = img->height;
+
+  memcpy (&img->transform, identity, sizeof identity);
+#endif
+
 # if (defined HAVE_IMAGEMAGICK \
       && !defined DONT_CREATE_TRANSFORMED_IMAGEMAGICK_IMAGE)
   /* ImageMagick images already have the correct transform.  */
@@ -2588,11 +2602,8 @@ image_set_transform (struct frame *f, struct image *img)
   compute_image_rotation (img, &rotation);
 
   /* Determine flipping.  */
-  bool flip;
-  Lisp_Object m = image_spec_value (img->spec, QCflip, NULL);
-  flip = !NILP (m);
+  flip = !NILP (image_spec_value (img->spec, QCflip, NULL));
 
-#ifndef HAVE_HAIKU
 # if defined USE_CAIRO || defined HAVE_XRENDER || defined HAVE_NS
   /* We want scale up operations to use a nearest neighbor filter to
      show real pixels instead of munging them, but scale down
@@ -2616,7 +2627,7 @@ image_set_transform (struct frame *f, struct image *img)
                  : img->width / (double) width),
        [1][1] = (!IEEE_FLOATING_POINT && height == 0 ? DBL_MAX
                  : img->height / (double) height),
-# elif defined HAVE_NTGUI || defined HAVE_NS
+# elif defined HAVE_NTGUI || defined HAVE_NS || defined HAVE_HAIKU
        [0][0] = (!IEEE_FLOATING_POINT && img->width == 0 ? DBL_MAX
                  : width / (double) img->width),
        [1][1] = (!IEEE_FLOATING_POINT && img->height == 0 ? DBL_MAX
@@ -2631,12 +2642,23 @@ image_set_transform (struct frame *f, struct image *img)
   /* Perform rotation transformation.  */
 
   int rotate_flag = -1;
+
+  /* Haiku needs this, since the transformation is done on the basis
+     of the view, and not the image.  */
+#ifdef HAVE_HAIKU
+  int extra_tx, extra_ty;
+
+  extra_tx = 0;
+  extra_ty = 0;
+#endif
+
   if (rotation == 0 && !flip)
     rotate_flag = 0;
   else
     {
 # if (defined USE_CAIRO || defined HAVE_XRENDER \
-      || defined HAVE_NTGUI || defined HAVE_NS)
+      || defined HAVE_NTGUI || defined HAVE_NS \
+      || defined HAVE_HAIKU)
       int cos_r, sin_r;
       if (rotation == 0)
        {
@@ -2648,6 +2670,11 @@ image_set_transform (struct frame *f, struct image *img)
          cos_r = 1;
          sin_r = 0;
          rotate_flag = 1;
+
+#ifdef HAVE_HAIKU
+         extra_tx = width;
+         extra_ty = 0;
+#endif
        }
       else if (rotation == 90)
        {
@@ -2656,12 +2683,24 @@ image_set_transform (struct frame *f, struct image *img)
          cos_r = 0;
          sin_r = 1;
          rotate_flag = 1;
+
+#ifdef HAVE_HAIKU
+         if (!flip)
+           extra_ty = height;
+         extra_tx = 0;
+#endif
        }
       else if (rotation == 180)
        {
          cos_r = -1;
          sin_r = 0;
          rotate_flag = 1;
+
+#ifdef HAVE_HAIKU
+         if (!flip)
+           extra_tx = width;
+         extra_ty = height;
+#endif
        }
       else if (rotation == 270)
        {
@@ -2670,6 +2709,13 @@ image_set_transform (struct frame *f, struct image *img)
          cos_r = 0;
          sin_r = -1;
          rotate_flag = 1;
+
+#ifdef HAVE_HAIKU
+         extra_tx = width;
+
+         if (flip)
+           extra_ty = height;
+#endif
        }
 
       if (0 < rotate_flag)
@@ -2779,35 +2825,17 @@ image_set_transform (struct frame *f, struct image *img)
   img->xform.eM22 = matrix[1][1];
   img->xform.eDx  = matrix[2][0];
   img->xform.eDy  = matrix[2][1];
-# endif
-#else
-  if (rotation != 0 &&
-      rotation != 90 &&
-      rotation != 180 &&
-      rotation != 270 &&
-      rotation != 360)
-    {
-      image_error ("No native support for rotation by %g degrees",
-                  make_float (rotation));
-      return;
-    }
-
-  rotation = fmod (rotation, 360.0);
+# elif defined HAVE_HAIKU
+  /* Store the transform in the struct image for later.  */
+  memcpy (&img->transform, &matrix, sizeof matrix);
 
-  if (rotation == 90 || rotation == 270)
+  /* Also add the extra translations.   */
+  if (rotate_flag)
     {
-      int w = width;
-      width = height;
-      height = w;
+      img->transform[0][2] = extra_tx;
+      img->transform[1][2] = extra_ty;
     }
-
-  img->have_be_transforms_p = rotation != 0 || (img->width != width) || 
(img->height != height);
-  img->be_rotate = rotation;
-  img->be_scale_x = 1.0 / (img->width / (double) width);
-  img->be_scale_y = 1.0 / (img->height / (double) height);
-  img->width = width;
-  img->height = height;
-#endif /* not HAVE_HAIKU */
+#endif
 }
 
 #endif /* HAVE_IMAGEMAGICK || HAVE_NATIVE_TRANSFORMS */



reply via email to

[Prev in Thread] Current Thread [Next in Thread]