Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/gfx/cairo/libpixman/src/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 35 kB image not shown  

Quelle  pixman-bits-image.c   Sprache: C

 
/*
 * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
 *             2005 Lars Knoll & Zack Rusin, Trolltech
 *             2008 Aaron Plattner, NVIDIA Corporation
 * Copyright © 2000 SuSE, Inc.
 * Copyright © 2007, 2009 Red Hat, Inc.
 * Copyright © 2008 André Tupinambá <andrelrt@gmail.com>
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of Keith Packard not be used in
 * advertising or publicity pertaining to distribution of the software without
 * specific, written prior permission.  Keith Packard makes no
 * representations about the suitability of this software for any purpose.  It
 * is provided "as is" without express or implied warranty.
 *
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 */


#ifdef HAVE_CONFIG_H
#include <pixman-config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pixman-private.h"
#include "pixman-combine32.h"
#include "pixman-inlines.h"
#include "dither/blue-noise-64x64.h"

/* Fetch functions */

static force_inline void
fetch_pixel_no_alpha_32 (bits_image_t *image,
    int x, int y, pixman_bool_t check_bounds,
    void *out)
{
    uint32_t *ret = out;

    if (check_bounds &&
 (x < 0 || x >= image->width || y < 0 || y >= image->height))
 *ret = 0;
    else
 *ret = image->fetch_pixel_32 (image, x, y);
}

static force_inline void
fetch_pixel_no_alpha_float (bits_image_t *image,
       int x, int y, pixman_bool_t check_bounds,
       void *out)
{
    argb_t *ret = out;

    if (check_bounds &&
 (x < 0 || x >= image->width || y < 0 || y >= image->height))
 ret->a = ret->r = ret->g = ret->b = 0.f;
    else
 *ret = image->fetch_pixel_float (image, x, y);
}

typedef void (* get_pixel_t) (bits_image_t *image,
         int x, int y, pixman_bool_t check_bounds, void *out);

static force_inline void
bits_image_fetch_pixel_nearest (bits_image_t   *image,
    pixman_fixed_t  x,
    pixman_fixed_t  y,
    get_pixel_t get_pixel,
    void        *out)
{
    int x0 = pixman_fixed_to_int (x - pixman_fixed_e);
    int y0 = pixman_fixed_to_int (y - pixman_fixed_e);

    if (image->common.repeat != PIXMAN_REPEAT_NONE)
    {
 repeat (image->common.repeat, &x0, image->width);
 repeat (image->common.repeat, &y0, image->height);

 get_pixel (image, x0, y0, FALSE, out);
    }
    else
    {
 get_pixel (image, x0, y0, TRUE, out);
    }
}

static force_inline void
bits_image_fetch_pixel_bilinear_32 (bits_image_t   *image,
        pixman_fixed_t  x,
        pixman_fixed_t  y,
        get_pixel_t     get_pixel,
        void    *out)
{
    pixman_repeat_t repeat_mode = image->common.repeat;
    int width = image->width;
    int height = image->height;
    int x1, y1, x2, y2;
    uint32_t tl, tr, bl, br;
    int32_t distx, disty;
    uint32_t *ret = out;

    x1 = x - pixman_fixed_1 / 2;
    y1 = y - pixman_fixed_1 / 2;

    distx = pixman_fixed_to_bilinear_weight (x1);
    disty = pixman_fixed_to_bilinear_weight (y1);

    x1 = pixman_fixed_to_int (x1);
    y1 = pixman_fixed_to_int (y1);
    x2 = x1 + 1;
    y2 = y1 + 1;

    if (repeat_mode != PIXMAN_REPEAT_NONE)
    {
 repeat (repeat_mode, &x1, width);
 repeat (repeat_mode, &y1, height);
 repeat (repeat_mode, &x2, width);
 repeat (repeat_mode, &y2, height);

 get_pixel (image, x1, y1, FALSE, &tl);
 get_pixel (image, x2, y1, FALSE, &tr);
 get_pixel (image, x1, y2, FALSE, &bl);
 get_pixel (image, x2, y2, FALSE, &br);
    }
    else
    {
 get_pixel (image, x1, y1, TRUE, &tl);
 get_pixel (image, x2, y1, TRUE, &tr);
 get_pixel (image, x1, y2, TRUE, &bl);
 get_pixel (image, x2, y2, TRUE, &br);
    }

    *ret = bilinear_interpolation (tl, tr, bl, br, distx, disty);
}

static force_inline void
bits_image_fetch_pixel_bilinear_float (bits_image_t   *image,
           pixman_fixed_t  x,
           pixman_fixed_t  y,
           get_pixel_t     get_pixel,
           void       *out)
{
    pixman_repeat_t repeat_mode = image->common.repeat;
    int width = image->width;
    int height = image->height;
    int x1, y1, x2, y2;
    argb_t tl, tr, bl, br;
    float distx, disty;
    argb_t *ret = out;

    x1 = x - pixman_fixed_1 / 2;
    y1 = y - pixman_fixed_1 / 2;

    distx = ((float)pixman_fixed_fraction(x1)) / 65536.f;
    disty = ((float)pixman_fixed_fraction(y1)) / 65536.f;

    x1 = pixman_fixed_to_int (x1);
    y1 = pixman_fixed_to_int (y1);
    x2 = x1 + 1;
    y2 = y1 + 1;

    if (repeat_mode != PIXMAN_REPEAT_NONE)
    {
 repeat (repeat_mode, &x1, width);
 repeat (repeat_mode, &y1, height);
 repeat (repeat_mode, &x2, width);
 repeat (repeat_mode, &y2, height);

 get_pixel (image, x1, y1, FALSE, &tl);
 get_pixel (image, x2, y1, FALSE, &tr);
 get_pixel (image, x1, y2, FALSE, &bl);
 get_pixel (image, x2, y2, FALSE, &br);
    }
    else
    {
 get_pixel (image, x1, y1, TRUE, &tl);
 get_pixel (image, x2, y1, TRUE, &tr);
 get_pixel (image, x1, y2, TRUE, &bl);
 get_pixel (image, x2, y2, TRUE, &br);
    }

    *ret = bilinear_interpolation_float (tl, tr, bl, br, distx, disty);
}

static force_inline void accum_32(unsigned int *satot, unsigned int *srtot,
      unsigned int *sgtot, unsigned int *sbtot,
      const void *p, pixman_fixed_t f)
{
    uint32_t pixel = *(uint32_t *)p;

    *srtot += (int)RED_8 (pixel) * f;
    *sgtot += (int)GREEN_8 (pixel) * f;
    *sbtot += (int)BLUE_8 (pixel) * f;
    *satot += (int)ALPHA_8 (pixel) * f;
}

static force_inline void reduce_32(unsigned int satot, unsigned int srtot,
       unsigned int sgtot, unsigned int sbtot,
                                   void *p)
{
    uint32_t *ret = p;

    satot = (int32_t)(satot + 0x8000) / 65536;
    srtot = (int32_t)(srtot + 0x8000) / 65536;
    sgtot = (int32_t)(sgtot + 0x8000) / 65536;
    sbtot = (int32_t)(sbtot + 0x8000) / 65536;

    satot = CLIP ((int32_t)satot, 0, 0xff);
    srtot = CLIP ((int32_t)srtot, 0, 0xff);
    sgtot = CLIP ((int32_t)sgtot, 0, 0xff);
    sbtot = CLIP ((int32_t)sbtot, 0, 0xff);

    *ret = ((satot << 24) | (srtot << 16) | (sgtot <<  8) | (sbtot));
}

static force_inline void accum_float(unsigned int *satot, unsigned int *srtot,
         unsigned int *sgtot, unsigned int *sbtot,
         const void *p, pixman_fixed_t f)
{
    const argb_t *pixel = p;

    *satot += pixel->a * f;
    *srtot += pixel->r * f;
    *sgtot += pixel->g * f;
    *sbtot += pixel->b * f;
}

static force_inline void reduce_float(unsigned int satot, unsigned int srtot,
          unsigned int sgtot, unsigned int sbtot,
          void *p)
{
    argb_t *ret = p;

    ret->a = CLIP ((int32_t)satot / 65536.f, 0.f, 1.f);
    ret->r = CLIP ((int32_t)srtot / 65536.f, 0.f, 1.f);
    ret->g = CLIP ((int32_t)sgtot / 65536.f, 0.f, 1.f);
    ret->b = CLIP ((int32_t)sbtot / 65536.f, 0.f, 1.f);
}

typedef void (* accumulate_pixel_t) (unsigned int *satot, unsigned int *srtot,
         unsigned int *sgtot, unsigned int *sbtot,
         const void *pixel, pixman_fixed_t f);

typedef void (* reduce_pixel_t) (unsigned int satot, unsigned int srtot,
     unsigned int sgtot, unsigned int sbtot,
                                 void *out);

static force_inline void
bits_image_fetch_pixel_convolution (bits_image_t   *image,
        pixman_fixed_t  x,
        pixman_fixed_t  y,
        get_pixel_t     get_pixel,
        void       *out,
        accumulate_pixel_t accum,
        reduce_pixel_t reduce)
{
    pixman_fixed_t *params = image->common.filter_params;
    int x_off = (params[0] - pixman_fixed_1) >> 1;
    int y_off = (params[1] - pixman_fixed_1) >> 1;
    int32_t cwidth = pixman_fixed_to_int (params[0]);
    int32_t cheight = pixman_fixed_to_int (params[1]);
    int32_t i, j, x1, x2, y1, y2;
    pixman_repeat_t repeat_mode = image->common.repeat;
    int width = image->width;
    int height = image->height;
    unsigned int srtot, sgtot, sbtot, satot;

    params += 2;

    x1 = pixman_fixed_to_int (x - pixman_fixed_e - x_off);
    y1 = pixman_fixed_to_int (y - pixman_fixed_e - y_off);
    x2 = x1 + cwidth;
    y2 = y1 + cheight;

    srtot = sgtot = sbtot = satot = 0;

    for (i = y1; i < y2; ++i)
    {
 for (j = x1; j < x2; ++j)
 {
     int rx = j;
     int ry = i;

     pixman_fixed_t f = *params;

     if (f)
     {
  /* Must be big enough to hold a argb_t */
  argb_t pixel;

  if (repeat_mode != PIXMAN_REPEAT_NONE)
  {
      repeat (repeat_mode, &rx, width);
      repeat (repeat_mode, &ry, height);

      get_pixel (image, rx, ry, FALSE, &pixel);
  }
  else
  {
      get_pixel (image, rx, ry, TRUE, &pixel);
  }

  accum (&satot, &srtot, &sgtot, &sbtot, &pixel, f);
     }

     params++;
 }
    }

    reduce (satot, srtot, sgtot, sbtot, out);
}

static void
bits_image_fetch_pixel_separable_convolution (bits_image_t  *image,
           pixman_fixed_t x,
           pixman_fixed_t y,
           get_pixel_t    get_pixel,
           void     *out,
           accumulate_pixel_t accum,
           reduce_pixel_t     reduce)
{
    pixman_fixed_t *params = image->common.filter_params;
    pixman_repeat_t repeat_mode = image->common.repeat;
    int width = image->width;
    int height = image->height;
    int cwidth = pixman_fixed_to_int (params[0]);
    int cheight = pixman_fixed_to_int (params[1]);
    int x_phase_bits = pixman_fixed_to_int (params[2]);
    int y_phase_bits = pixman_fixed_to_int (params[3]);
    int x_phase_shift = 16 - x_phase_bits;
    int y_phase_shift = 16 - y_phase_bits;
    int x_off = ((cwidth << 16) - pixman_fixed_1) >> 1;
    int y_off = ((cheight << 16) - pixman_fixed_1) >> 1;
    pixman_fixed_t *y_params;
    unsigned int srtot, sgtot, sbtot, satot;
    int32_t x1, x2, y1, y2;
    int32_t px, py;
    int i, j;

    /* Round x and y to the middle of the closest phase before continuing. This
     * ensures that the convolution matrix is aligned right, since it was
     * positioned relative to a particular phase (and not relative to whatever
     * exact fraction we happen to get here).
     */

    x = ((x >> x_phase_shift) << x_phase_shift) + ((1 << x_phase_shift) >> 1);
    y = ((y >> y_phase_shift) << y_phase_shift) + ((1 << y_phase_shift) >> 1);

    px = (x & 0xffff) >> x_phase_shift;
    py = (y & 0xffff) >> y_phase_shift;

    y_params = params + 4 + (1 << x_phase_bits) * cwidth + py * cheight;

    x1 = pixman_fixed_to_int (x - pixman_fixed_e - x_off);
    y1 = pixman_fixed_to_int (y - pixman_fixed_e - y_off);
    x2 = x1 + cwidth;
    y2 = y1 + cheight;

    srtot = sgtot = sbtot = satot = 0;

    for (i = y1; i < y2; ++i)
    {
        pixman_fixed_48_16_t fy = *y_params++;
        pixman_fixed_t *x_params = params + 4 + px * cwidth;

        if (fy)
        {
            for (j = x1; j < x2; ++j)
            {
                pixman_fixed_t fx = *x_params++;
  int rx = j;
  int ry = i;

                if (fx)
                {
                    /* Must be big enough to hold a argb_t */
                    argb_t pixel;
                    pixman_fixed_t f;

                    if (repeat_mode != PIXMAN_REPEAT_NONE)
                    {
                        repeat (repeat_mode, &rx, width);
                        repeat (repeat_mode, &ry, height);

                        get_pixel (image, rx, ry, FALSE, &pixel);
                    }
                    else
                    {
                        get_pixel (image, rx, ry, TRUE, &pixel);
      }

                    f = (fy * fx + 0x8000) >> 16;

      accum(&satot, &srtot, &sgtot, &sbtot, &pixel, f);
                }
            }
 }
    }


    reduce(satot, srtot, sgtot, sbtot, out);
}

static force_inline void
bits_image_fetch_pixel_filtered (bits_image_t  *image,
     pixman_bool_t  wide,
     pixman_fixed_t x,
     pixman_fixed_t y,
     get_pixel_t    get_pixel,
     void          *out)
{
    switch (image->common.filter)
    {
    case PIXMAN_FILTER_NEAREST:
    case PIXMAN_FILTER_FAST:
 bits_image_fetch_pixel_nearest (image, x, y, get_pixel, out);
 break;

    case PIXMAN_FILTER_BILINEAR:
    case PIXMAN_FILTER_GOOD:
    case PIXMAN_FILTER_BEST:
 if (wide)
     bits_image_fetch_pixel_bilinear_float (image, x, y, get_pixel, out);
 else
     bits_image_fetch_pixel_bilinear_32 (image, x, y, get_pixel, out);
 break;

    case PIXMAN_FILTER_CONVOLUTION:
 if (wide)
 {
     bits_image_fetch_pixel_convolution (image, x, y,
      get_pixel, out,
      accum_float,
      reduce_float);
 }
 else
 {
     bits_image_fetch_pixel_convolution (image, x, y,
      get_pixel, out,
      accum_32, reduce_32);
 }
 break;

    case PIXMAN_FILTER_SEPARABLE_CONVOLUTION:
 if (wide)
 {
     bits_image_fetch_pixel_separable_convolution (image, x, y,
         get_pixel, out,
         accum_float,
         reduce_float);
 }
 else
 {
     bits_image_fetch_pixel_separable_convolution (image, x, y,
         get_pixel, out,
         accum_32, reduce_32);
 }
        break;

    default:
 assert (0);
        break;
    }
}

static uint32_t *
__bits_image_fetch_affine_no_alpha (pixman_iter_t *  iter,
        pixman_bool_t    wide,
        const uint32_t * mask)
{
    pixman_image_t *image  = iter->image;
    int             offset = iter->x;
    int             line   = iter->y++;
    int             width  = iter->width;
    uint32_t *      buffer = iter->buffer;

    const uint32_t wide_zero[4] = {0};
    pixman_fixed_t x, y;
    pixman_fixed_t ux, uy;
    pixman_vector_t v;
    int i;
    get_pixel_t get_pixel =
 wide ? fetch_pixel_no_alpha_float : fetch_pixel_no_alpha_32;

    /* reference point is the center of the pixel */
    v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2;
    v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2;
    v.vector[2] = pixman_fixed_1;

    if (image->common.transform)
    {
 if (!pixman_transform_point_3d (image->common.transform, &v))
     return iter->buffer;

 ux = image->common.transform->matrix[0][0];
 uy = image->common.transform->matrix[1][0];
    }
    else
    {
 ux = pixman_fixed_1;
 uy = 0;
    }

    x = v.vector[0];
    y = v.vector[1];

    for (i = 0; i < width; ++i)
    {
 if (!mask || (!wide && mask[i]) ||
     (wide && memcmp(&mask[4 * i], wide_zero, 16) != 0))
 {
     bits_image_fetch_pixel_filtered (
  &image->bits, wide, x, y, get_pixel, buffer);
 }

 x += ux;
 y += uy;
 buffer += wide ? 4 : 1;
    }

    return iter->buffer;
}

static uint32_t *
bits_image_fetch_affine_no_alpha_32 (pixman_iter_t  *iter,
         const uint32_t *mask)
{
    return __bits_image_fetch_affine_no_alpha(iter, FALSE, mask);
}

static uint32_t *
bits_image_fetch_affine_no_alpha_float (pixman_iter_t  *iter,
     const uint32_t *mask)
{
    return __bits_image_fetch_affine_no_alpha(iter, TRUE, mask);
}

/* General fetcher */
static force_inline void
fetch_pixel_general_32 (bits_image_t *image,
   int x, int y, pixman_bool_t check_bounds,
   void *out)
{
    uint32_t pixel, *ret = out;

    if (check_bounds &&
 (x < 0 || x >= image->width || y < 0 || y >= image->height))
    {
 *ret = 0;
 return;
    }

    pixel = image->fetch_pixel_32 (image, x, y);

    if (image->common.alpha_map)
    {
 uint32_t pixel_a;

 x -= image->common.alpha_origin_x;
 y -= image->common.alpha_origin_y;

 if (x < 0 || x >= image->common.alpha_map->width ||
     y < 0 || y >= image->common.alpha_map->height)
 {
     pixel_a = 0;
 }
 else
 {
     pixel_a = image->common.alpha_map->fetch_pixel_32 (
  image->common.alpha_map, x, y);

     pixel_a = ALPHA_8 (pixel_a);
 }

 pixel &= 0x00ffffff;
 pixel |= (pixel_a << 24);
    }

    *ret = pixel;
}

static force_inline void
fetch_pixel_general_float (bits_image_t *image,
   int x, int y, pixman_bool_t check_bounds,
   void *out)
{
    argb_t *ret = out;

    if (check_bounds &&
 (x < 0 || x >= image->width || y < 0 || y >= image->height))
    {
 ret->a = ret->r = ret->g = ret->b = 0;
 return;
    }

    *ret = image->fetch_pixel_float (image, x, y);

    if (image->common.alpha_map)
    {
 x -= image->common.alpha_origin_x;
 y -= image->common.alpha_origin_y;

 if (x < 0 || x >= image->common.alpha_map->width ||
     y < 0 || y >= image->common.alpha_map->height)
 {
     ret->a = 0.f;
 }
 else
 {
     argb_t alpha;

     alpha = image->common.alpha_map->fetch_pixel_float (
      image->common.alpha_map, x, y);

     ret->a = alpha.a;
 }
    }
}

static uint32_t *
__bits_image_fetch_general (pixman_iter_t  *iter,
       pixman_bool_t wide,
       const uint32_t *mask)
{
    pixman_image_t *image  = iter->image;
    int             offset = iter->x;
    int             line   = iter->y++;
    int             width  = iter->width;
    uint32_t *      buffer = iter->buffer;
    get_pixel_t     get_pixel =
 wide ? fetch_pixel_general_float : fetch_pixel_general_32;

    const uint32_t wide_zero[4] = {0};
    pixman_fixed_t x, y, w;
    pixman_fixed_t ux, uy, uw;
    pixman_vector_t v;
    int i;

    /* reference point is the center of the pixel */
    v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2;
    v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2;
    v.vector[2] = pixman_fixed_1;

    if (image->common.transform)
    {
 if (!pixman_transform_point_3d (image->common.transform, &v))
     return buffer;

 ux = image->common.transform->matrix[0][0];
 uy = image->common.transform->matrix[1][0];
 uw = image->common.transform->matrix[2][0];
    }
    else
    {
 ux = pixman_fixed_1;
 uy = 0;
 uw = 0;
    }

    x = v.vector[0];
    y = v.vector[1];
    w = v.vector[2];

    for (i = 0; i < width; ++i)
    {
 pixman_fixed_t x0, y0;

 if (!mask || (!wide && mask[i]) ||
     (wide && memcmp(&mask[4 * i], wide_zero, 16) != 0))
 {
     if (w != 0)
     {
  x0 = ((uint64_t)x << 16) / w;
  y0 = ((uint64_t)y << 16) / w;
     }
     else
     {
  x0 = 0;
  y0 = 0;
     }

     bits_image_fetch_pixel_filtered (
  &image->bits, wide, x0, y0, get_pixel, buffer);
 }

 x += ux;
 y += uy;
 w += uw;
 buffer += wide ? 4 : 1;
    }

    return iter->buffer;
}

static uint32_t *
bits_image_fetch_general_32 (pixman_iter_t  *iter,
        const uint32_t *mask)
{
    return __bits_image_fetch_general(iter, FALSE, mask);
}

static uint32_t *
bits_image_fetch_general_float (pixman_iter_t  *iter,
    const uint32_t *mask)
{
    return __bits_image_fetch_general(iter, TRUE, mask);
}

static void
replicate_pixel_32 (bits_image_t *   bits,
      int              x,
      int              y,
      int              width,
      uint32_t *       buffer)
{
    uint32_t color;
    uint32_t *end;

    color = bits->fetch_pixel_32 (bits, x, y);

    end = buffer + width;
    while (buffer < end)
 *(buffer++) = color;
}

static void
replicate_pixel_float (bits_image_t *   bits,
         int              x,
         int              y,
         int              width,
         uint32_t *       b)
{
    argb_t color;
    argb_t *buffer = (argb_t *)b;
    argb_t *end;

    color = bits->fetch_pixel_float (bits, x, y);

    end = buffer + width;
    while (buffer < end)
 *(buffer++) = color;
}

static void
bits_image_fetch_untransformed_repeat_none (bits_image_t *image,
                                            pixman_bool_t wide,
                                            int           x,
                                            int           y,
                                            int           width,
                                            uint32_t *    buffer)
{
    uint32_t w;

    if (y < 0 || y >= image->height)
    {
 memset (buffer, 0, width * (wide? sizeof (argb_t) : 4));
 return;
    }

    if (x < 0)
    {
 w = MIN (width, -x);

 memset (buffer, 0, w * (wide ? sizeof (argb_t) : 4));

 width -= w;
 buffer += w * (wide? 4 : 1);
 x += w;
    }

    if (x < image->width)
    {
 w = MIN (width, image->width - x);

 if (wide)
     image->fetch_scanline_float (image, x, y, w, buffer, NULL);
 else
     image->fetch_scanline_32 (image, x, y, w, buffer, NULL);

 width -= w;
 buffer += w * (wide? 4 : 1);
 x += w;
    }

    memset (buffer, 0, width * (wide ? sizeof (argb_t) : 4));
}

static void
bits_image_fetch_untransformed_repeat_normal (bits_image_t *image,
                                              pixman_bool_t wide,
                                              int           x,
                                              int           y,
                                              int           width,
                                              uint32_t *    buffer)
{
    uint32_t w;

    while (y < 0)
 y += image->height;

    while (y >= image->height)
 y -= image->height;

    if (image->width == 1)
    {
 if (wide)
     replicate_pixel_float (image, 0, y, width, buffer);
 else
     replicate_pixel_32 (image, 0, y, width, buffer);

 return;
    }

    while (width)
    {
 while (x < 0)
     x += image->width;
 while (x >= image->width)
     x -= image->width;

 w = MIN (width, image->width - x);

 if (wide)
     image->fetch_scanline_float (image, x, y, w, buffer, NULL);
 else
     image->fetch_scanline_32 (image, x, y, w, buffer, NULL);

 buffer += w * (wide? 4 : 1);
 x += w;
 width -= w;
    }
}

static uint32_t *
bits_image_fetch_untransformed_32 (pixman_iter_t * iter,
       const uint32_t *mask)
{
    pixman_image_t *image  = iter->image;
    int             x      = iter->x;
    int             y      = iter->y;
    int             width  = iter->width;
    uint32_t *      buffer = iter->buffer;

    if (image->common.repeat == PIXMAN_REPEAT_NONE)
    {
 bits_image_fetch_untransformed_repeat_none (
     &image->bits, FALSE, x, y, width, buffer);
    }
    else
    {
 bits_image_fetch_untransformed_repeat_normal (
     &image->bits, FALSE, x, y, width, buffer);
    }

    iter->y++;
    return buffer;
}

static uint32_t *
bits_image_fetch_untransformed_float (pixman_iter_t * iter,
          const uint32_t *mask)
{
    pixman_image_t *image  = iter->image;
    int             x      = iter->x;
    int             y      = iter->y;
    int             width  = iter->width;
    uint32_t *      buffer = iter->buffer;

    if (image->common.repeat == PIXMAN_REPEAT_NONE)
    {
 bits_image_fetch_untransformed_repeat_none (
     &image->bits, TRUE, x, y, width, buffer);
    }
    else
    {
 bits_image_fetch_untransformed_repeat_normal (
     &image->bits, TRUE, x, y, width, buffer);
    }

    iter->y++;
    return buffer;
}

typedef struct
{
    pixman_format_code_t format;
    uint32_t   flags;
    pixman_iter_get_scanline_t get_scanline_32;
    pixman_iter_get_scanline_t  get_scanline_float;
} fetcher_info_t;

static const fetcher_info_t fetcher_info[] =
{
    { PIXMAN_any,
      (FAST_PATH_NO_ALPHA_MAP   |
       FAST_PATH_ID_TRANSFORM   |
       FAST_PATH_NO_CONVOLUTION_FILTER  |
       FAST_PATH_NO_PAD_REPEAT   |
       FAST_PATH_NO_REFLECT_REPEAT),
      bits_image_fetch_untransformed_32,
      bits_image_fetch_untransformed_float
    },

    /* Affine, no alpha */
    { PIXMAN_any,
      (FAST_PATH_NO_ALPHA_MAP | FAST_PATH_HAS_TRANSFORM | FAST_PATH_AFFINE_TRANSFORM),
      bits_image_fetch_affine_no_alpha_32,
      bits_image_fetch_affine_no_alpha_float,
    },

    /* General */
    { PIXMAN_any,
      0,
      bits_image_fetch_general_32,
      bits_image_fetch_general_float,
    },

    { PIXMAN_null },
};

static void
bits_image_property_changed (pixman_image_t *image)
{
    _pixman_bits_image_setup_accessors (&image->bits);
}

void
_pixman_bits_image_src_iter_init (pixman_image_t *image, pixman_iter_t *iter)
{
    pixman_format_code_t format = image->common.extended_format_code;
    uint32_t flags = image->common.flags;
    const fetcher_info_t *info;

    for (info = fetcher_info; info->format != PIXMAN_null; ++info)
    {
 if ((info->format == format || info->format == PIXMAN_any) &&
     (info->flags & flags) == info->flags)
 {
     if (iter->iter_flags & ITER_NARROW)
     {
  iter->get_scanline = info->get_scanline_32;
     }
     else
     {
  iter->get_scanline = info->get_scanline_float;
     }
     return;
 }
    }

    /* Just in case we somehow didn't find a scanline function */
    iter->get_scanline = _pixman_iter_get_scanline_noop;
}

static uint32_t *
dest_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
{
    pixman_image_t *image  = iter->image;
    int             x      = iter->x;
    int             y      = iter->y;
    int             width  = iter->width;
    uint32_t *     buffer = iter->buffer;

    image->bits.fetch_scanline_32 (&image->bits, x, y, width, buffer, mask);
    if (image->common.alpha_map)
    {
 uint32_t *alpha;

 if ((alpha = malloc (width * sizeof (uint32_t))))
 {
     int i;

     x -= image->common.alpha_origin_x;
     y -= image->common.alpha_origin_y;

     image->common.alpha_map->fetch_scanline_32 (
  image->common.alpha_map, x, y, width, alpha, mask);

     for (i = 0; i < width; ++i)
     {
  buffer[i] &= ~0xff000000;
  buffer[i] |= (alpha[i] & 0xff000000);
     }

     free (alpha);
 }
    }

    return iter->buffer;
}

static uint32_t *
dest_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
{
    bits_image_t *  image  = &iter->image->bits;
    int             x      = iter->x;
    int             y      = iter->y;
    int             width  = iter->width;
    argb_t *     buffer = (argb_t *)iter->buffer;

    image->fetch_scanline_float (
 image, x, y, width, (uint32_t *)buffer, mask);
    if (image->common.alpha_map)
    {
 argb_t *alpha;

 if ((alpha = malloc (width * sizeof (argb_t))))
 {
     int i;

     x -= image->common.alpha_origin_x;
     y -= image->common.alpha_origin_y;

     image->common.alpha_map->fetch_scanline_float (
  image->common.alpha_map, x, y, width, (uint32_t *)alpha, mask);

     for (i = 0; i < width; ++i)
  buffer[i].a = alpha[i].a;

     free (alpha);
 }
    }

    return iter->buffer;
}

static void
dest_write_back_narrow (pixman_iter_t *iter)
{
    bits_image_t *  image  = &iter->image->bits;
    int             x      = iter->x;
    int             y      = iter->y;
    int             width  = iter->width;
    const uint32_t *buffer = iter->buffer;

    image->store_scanline_32 (image, x, y, width, buffer);

    if (image->common.alpha_map)
    {
 x -= image->common.alpha_origin_x;
 y -= image->common.alpha_origin_y;

 image->common.alpha_map->store_scanline_32 (
     image->common.alpha_map, x, y, width, buffer);
    }

    iter->y++;
}

static float
dither_factor_blue_noise_64 (int x, int y)
{
    float m = dither_blue_noise_64x64[((y & 0x3f) << 6) | (x & 0x3f)];
    return m * (1. / 4096.f) + (1. / 8192.f);
}

static float
dither_factor_bayer_8 (int x, int y)
{
    uint32_t m;

    y ^= x;

    /* Compute reverse(interleave(xor(x mod n, y mod n), x mod n))
     * Here n = 8 and `mod n` is the bottom 3 bits.
     */

    m = ((y & 0x1) << 5) | ((x & 0x1) << 4) |
 ((y & 0x2) << 2) | ((x & 0x2) << 1) |
 ((y & 0x4) >> 1) | ((x & 0x4) >> 2);

    /* m is in range [0, 63].  We scale it to [0, 63.0f/64.0f], then
     * shift it to to [1.0f/128.0f, 127.0f/128.0f] so that 0 < d < 1.
     * This ensures exact values are not changed by dithering.
     */

    return (float)(m) * (1 / 64.0f) + (1.0f / 128.0f);
}

typedef float (* dither_factor_t)(int x, int y);

static force_inline float
dither_apply_channel (float f, float d, float s)
{
    /* float_to_unorm splits the [0, 1] segment in (1 << n_bits)
     * subsections of equal length; however unorm_to_float does not
     * map to the center of those sections.  In fact, pixel value u is
     * mapped to:
     *
     *       u              u              u               1
     * -------------- = ---------- + -------------- * ----------
     *  2^n_bits - 1     2^n_bits     2^n_bits - 1     2^n_bits
     *
     * Hence if f = u / (2^n_bits - 1) is exactly representable on a
     * n_bits palette, all the numbers between
     *
     *     u
     * ----------  =  f - f * 2^n_bits = f + (0 - f) * 2^n_bits
     *  2^n_bits
     *
     *  and
     *
     *    u + 1
     * ---------- = f - (f - 1) * 2^n_bits = f + (1 - f) * 2^n_bits
     *  2^n_bits
     *
     * are also mapped back to u.
     *
     * Hence the following calculation ensures that we add as much
     * noise as possible without perturbing values which are exactly
     * representable in the target colorspace.  Note that this corresponds to
     * mixing the original color with noise with a ratio of `1 / 2^n_bits`.
     */

    return f + (d - f) * s;
}

static force_inline float
dither_compute_scale (int n_bits)
{
    // No dithering for wide formats
    if (n_bits == 0 || n_bits >= 32)
 return 0.f;

    return 1.f / (float)(1 << n_bits);
}

static const uint32_t *
dither_apply_ordered (pixman_iter_t *iter, dither_factor_t factor)
{
    bits_image_t        *image  = &iter->image->bits;
    int                  x      = iter->x + image->dither_offset_x;
    int                  y      = iter->y + image->dither_offset_y;
    int                  width  = iter->width;
    argb_t              *buffer = (argb_t *)iter->buffer;

    pixman_format_code_t format = image->format;
    int                  a_size = PIXMAN_FORMAT_A (format);
    int                  r_size = PIXMAN_FORMAT_R (format);
    int                  g_size = PIXMAN_FORMAT_G (format);
    int                  b_size = PIXMAN_FORMAT_B (format);

    float a_scale = dither_compute_scale (a_size);
    float r_scale = dither_compute_scale (r_size);
    float g_scale = dither_compute_scale (g_size);
    float b_scale = dither_compute_scale (b_size);

    int   i;
    float d;

    for (i = 0; i < width; ++i)
    {
 d = factor (x + i, y);

 buffer->a = dither_apply_channel (buffer->a, d, a_scale);
 buffer->r = dither_apply_channel (buffer->r, d, r_scale);
 buffer->g = dither_apply_channel (buffer->g, d, g_scale);
 buffer->b = dither_apply_channel (buffer->b, d, b_scale);

 buffer++;
    }

    return iter->buffer;
}

static void
dest_write_back_wide (pixman_iter_t *iter)
{
    bits_image_t *  image  = &iter->image->bits;
    int             x      = iter->x;
    int             y      = iter->y;
    int             width  = iter->width;
    const uint32_t *buffer = iter->buffer;

    switch (image->dither)
    {
    case PIXMAN_DITHER_NONE:
 break;

    case PIXMAN_DITHER_GOOD:
    case PIXMAN_DITHER_BEST:
    case PIXMAN_DITHER_ORDERED_BLUE_NOISE_64:
 buffer = dither_apply_ordered (iter, dither_factor_blue_noise_64);
 break;

    case PIXMAN_DITHER_FAST:
    case PIXMAN_DITHER_ORDERED_BAYER_8:
 buffer = dither_apply_ordered (iter, dither_factor_bayer_8);
 break;
    }

    image->store_scanline_float (image, x, y, width, buffer);

    if (image->common.alpha_map)
    {
 x -= image->common.alpha_origin_x;
 y -= image->common.alpha_origin_y;

 image->common.alpha_map->store_scanline_float (
     image->common.alpha_map, x, y, width, buffer);
    }

    iter->y++;
}

void
_pixman_bits_image_dest_iter_init (pixman_image_t *image, pixman_iter_t *iter)
{
    if (iter->iter_flags & ITER_NARROW)
    {
 if ((iter->iter_flags & (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA)) ==
     (ITER_IGNORE_RGB | ITER_IGNORE_ALPHA))
 {
     iter->get_scanline = _pixman_iter_get_scanline_noop;
 }
 else
 {
     iter->get_scanline = dest_get_scanline_narrow;
 }
 
 iter->write_back = dest_write_back_narrow;
    }
    else
    {
 iter->get_scanline = dest_get_scanline_wide;
 iter->write_back = dest_write_back_wide;
    }
}

static uint32_t *
create_bits (pixman_format_code_t format,
             int                  width,
             int                  height,
             int *    rowstride_bytes,
      pixman_bool_t   clear)
{
    int stride;
    size_t buf_size;
    int bpp;

    /* what follows is a long-winded way, avoiding any possibility of integer
     * overflows, of saying:
     * stride = ((width * bpp + 0x1f) >> 5) * sizeof (uint32_t);
     */


    bpp = PIXMAN_FORMAT_BPP (format);
    if (_pixman_multiply_overflows_int (width, bpp))
 return NULL;

    stride = width * bpp;
    if (_pixman_addition_overflows_int (stride, 0x1f))
 return NULL;

    stride += 0x1f;
    stride >>= 5;

    stride *= sizeof (uint32_t);

    if (_pixman_multiply_overflows_size (height, stride))
 return NULL;

    buf_size = (size_t)height * stride;

    if (rowstride_bytes)
 *rowstride_bytes = stride;

    if (clear)
 return calloc (1, buf_size);
    else
 return malloc (buf_size);
}

pixman_bool_t
_pixman_bits_image_init (pixman_image_t *     image,
                         pixman_format_code_t format,
                         int                  width,
                         int                  height,
                         uint32_t *           bits,
                         int                  rowstride,
    pixman_bool_t       clear)
{
    uint32_t *free_me = NULL;

    if (PIXMAN_FORMAT_BPP (format) == 128)
 return_val_if_fail(!(rowstride % 4), FALSE);

    if (!bits && width && height)
    {
 int rowstride_bytes;

 free_me = bits = create_bits (format, width, height, &rowstride_bytes, clear);

 if (!bits)
     return FALSE;

 rowstride = rowstride_bytes / (intsizeof (uint32_t);
    }

    _pixman_image_init (image);

    image->type = BITS;
    image->bits.format = format;
    image->bits.width = width;
    image->bits.height = height;
    image->bits.bits = bits;
    image->bits.free_me = free_me;
    image->bits.dither = PIXMAN_DITHER_NONE;
    image->bits.dither_offset_x = 0;
    image->bits.dither_offset_y = 0;
    image->bits.read_func = NULL;
    image->bits.write_func = NULL;
    image->bits.rowstride = rowstride;
    image->bits.indexed = NULL;

    image->common.property_changed = bits_image_property_changed;

    _pixman_image_reset_clip_region (image);

    return TRUE;
}

static pixman_image_t *
create_bits_image_internal (pixman_format_code_t format,
       int                  width,
       int                  height,
       uint32_t *           bits,
       int                  rowstride_bytes,
       pixman_bool_t  clear)
{
    pixman_image_t *image;

    /* must be a whole number of uint32_t's
     */

    return_val_if_fail (
 bits == NULL || (rowstride_bytes % sizeof (uint32_t)) == 0, NULL);

    return_val_if_fail (PIXMAN_FORMAT_BPP (format) >= PIXMAN_FORMAT_DEPTH (format), NULL);

    image = _pixman_image_allocate ();

    if (!image)
 return NULL;

    if (!_pixman_bits_image_init (image, format, width, height, bits,
      rowstride_bytes / (intsizeof (uint32_t),
      clear))
    {
 free (image);
 return NULL;
    }

    return image;
}

/* If bits is NULL, a buffer will be allocated and initialized to 0 */
PIXMAN_EXPORT pixman_image_t *
pixman_image_create_bits (pixman_format_code_t format,
                          int                  width,
                          int                  height,
                          uint32_t *           bits,
                          int                  rowstride_bytes)
{
    return create_bits_image_internal (
 format, width, height, bits, rowstride_bytes, TRUE);
}


/* If bits is NULL, a buffer will be allocated and _not_ initialized */
PIXMAN_EXPORT pixman_image_t *
pixman_image_create_bits_no_clear (pixman_format_code_t format,
       int                  width,
       int                  height,
       uint32_t *           bits,
       int                  rowstride_bytes)
{
    return create_bits_image_internal (
 format, width, height, bits, rowstride_bytes, FALSE);
}

Messung V0.5
C=99 H=94 G=96

¤ Dauer der Verarbeitung: 0.18 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.