(root)/
freetype-2.13.2/
src/
sdf/
ftsdfrend.c
       1  /****************************************************************************
       2   *
       3   * ftsdfrend.c
       4   *
       5   *   Signed Distance Field renderer interface (body).
       6   *
       7   * Copyright (C) 2020-2023 by
       8   * David Turner, Robert Wilhelm, and Werner Lemberg.
       9   *
      10   * Written by Anuj Verma.
      11   *
      12   * This file is part of the FreeType project, and may only be used,
      13   * modified, and distributed under the terms of the FreeType project
      14   * license, LICENSE.TXT.  By continuing to use, modify, or distribute
      15   * this file you indicate that you have read the license and
      16   * understand and accept it fully.
      17   *
      18   */
      19  
      20  
      21  #include <freetype/internal/ftdebug.h>
      22  #include <freetype/internal/ftobjs.h>
      23  #include <freetype/internal/services/svprop.h>
      24  #include <freetype/ftoutln.h>
      25  #include <freetype/ftbitmap.h>
      26  #include "ftsdfrend.h"
      27  #include "ftsdf.h"
      28  
      29  #include "ftsdferrs.h"
      30  
      31  
      32    /**************************************************************************
      33     *
      34     * The macro FT_COMPONENT is used in trace mode.  It is an implicit
      35     * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
      36     * messages during execution.
      37     */
      38  #undef  FT_COMPONENT
      39  #define FT_COMPONENT  sdf
      40  
      41  
      42    /**************************************************************************
      43     *
      44     * macros and default property values
      45     *
      46     */
      47  #define SDF_RENDERER( rend )  ( (SDF_Renderer)rend )
      48  
      49  
      50    /**************************************************************************
      51     *
      52     * for setting properties
      53     *
      54     */
      55  
      56    /* property setter function */
      57    static FT_Error
      58    sdf_property_set( FT_Module    module,
      59                      const char*  property_name,
      60                      const void*  value,
      61                      FT_Bool      value_is_string )
      62    {
      63      FT_Error      error  = FT_Err_Ok;
      64      SDF_Renderer  render = SDF_RENDERER( FT_RENDERER( module ) );
      65  
      66      FT_UNUSED( value_is_string );
      67  
      68  
      69      if ( ft_strcmp( property_name, "spread" ) == 0 )
      70      {
      71        FT_Int  val = *(const FT_Int*)value;
      72  
      73  
      74        if ( val > MAX_SPREAD || val < MIN_SPREAD )
      75        {
      76          FT_TRACE0(( "[sdf] sdf_property_set:"
      77                      " the `spread' property can have a value\n" ));
      78          FT_TRACE0(( "                       "
      79                      " within range [%d, %d] (value provided: %d)\n",
      80                      MIN_SPREAD, MAX_SPREAD, val ));
      81  
      82          error = FT_THROW( Invalid_Argument );
      83          goto Exit;
      84        }
      85  
      86        render->spread = (FT_UInt)val;
      87        FT_TRACE7(( "[sdf] sdf_property_set:"
      88                    " updated property `spread' to %d\n", val ));
      89      }
      90  
      91      else if ( ft_strcmp( property_name, "flip_sign" ) == 0 )
      92      {
      93        FT_Int  val = *(const FT_Int*)value;
      94  
      95  
      96        render->flip_sign = val ? 1 : 0;
      97        FT_TRACE7(( "[sdf] sdf_property_set:"
      98                    " updated property `flip_sign' to %d\n", val ));
      99      }
     100  
     101      else if ( ft_strcmp( property_name, "flip_y" ) == 0 )
     102      {
     103        FT_Int  val = *(const FT_Int*)value;
     104  
     105  
     106        render->flip_y = val ? 1 : 0;
     107        FT_TRACE7(( "[sdf] sdf_property_set:"
     108                    " updated property `flip_y' to %d\n", val ));
     109      }
     110  
     111      else if ( ft_strcmp( property_name, "overlaps" ) == 0 )
     112      {
     113        FT_Bool  val = *(const FT_Bool*)value;
     114  
     115  
     116        render->overlaps = val;
     117        FT_TRACE7(( "[sdf] sdf_property_set:"
     118                    " updated property `overlaps' to %d\n", val ));
     119      }
     120  
     121      else
     122      {
     123        FT_TRACE0(( "[sdf] sdf_property_set:"
     124                    " missing property `%s'\n", property_name ));
     125        error = FT_THROW( Missing_Property );
     126      }
     127  
     128    Exit:
     129      return error;
     130    }
     131  
     132  
     133    /* property getter function */
     134    static FT_Error
     135    sdf_property_get( FT_Module    module,
     136                      const char*  property_name,
     137                      void*        value )
     138    {
     139      FT_Error      error  = FT_Err_Ok;
     140      SDF_Renderer  render = SDF_RENDERER( FT_RENDERER( module ) );
     141  
     142  
     143      if ( ft_strcmp( property_name, "spread" ) == 0 )
     144      {
     145        FT_UInt*  val = (FT_UInt*)value;
     146  
     147  
     148        *val = render->spread;
     149      }
     150  
     151      else if ( ft_strcmp( property_name, "flip_sign" ) == 0 )
     152      {
     153        FT_Int*  val = (FT_Int*)value;
     154  
     155  
     156        *val = render->flip_sign;
     157      }
     158  
     159      else if ( ft_strcmp( property_name, "flip_y" ) == 0 )
     160      {
     161        FT_Int*  val = (FT_Int*)value;
     162  
     163  
     164        *val = render->flip_y;
     165      }
     166  
     167      else if ( ft_strcmp( property_name, "overlaps" ) == 0 )
     168      {
     169        FT_Int*  val = (FT_Int*)value;
     170  
     171  
     172        *val = render->overlaps;
     173      }
     174  
     175      else
     176      {
     177        FT_TRACE0(( "[sdf] sdf_property_get:"
     178                    " missing property `%s'\n", property_name ));
     179        error = FT_THROW( Missing_Property );
     180      }
     181  
     182      return error;
     183    }
     184  
     185  
     186    FT_DEFINE_SERVICE_PROPERTIESREC(
     187      sdf_service_properties,
     188  
     189      (FT_Properties_SetFunc)sdf_property_set,        /* set_property */
     190      (FT_Properties_GetFunc)sdf_property_get )       /* get_property */
     191  
     192  
     193    FT_DEFINE_SERVICEDESCREC1(
     194      sdf_services,
     195  
     196      FT_SERVICE_ID_PROPERTIES, &sdf_service_properties )
     197  
     198  
     199    static FT_Module_Interface
     200    ft_sdf_requester( FT_Module    module,
     201                      const char*  module_interface )
     202    {
     203      FT_UNUSED( module );
     204  
     205      return ft_service_list_lookup( sdf_services, module_interface );
     206    }
     207  
     208  
     209    /*************************************************************************/
     210    /*************************************************************************/
     211    /**                                                                     **/
     212    /**  OUTLINE TO SDF CONVERTER                                           **/
     213    /**                                                                     **/
     214    /*************************************************************************/
     215    /*************************************************************************/
     216  
     217    /**************************************************************************
     218     *
     219     * interface functions
     220     *
     221     */
     222  
     223    static FT_Error
     224    ft_sdf_init( FT_Module  module )   /* SDF_Renderer */
     225    {
     226      SDF_Renderer  sdf_render = SDF_RENDERER( module );
     227  
     228  
     229      sdf_render->spread    = DEFAULT_SPREAD;
     230      sdf_render->flip_sign = 0;
     231      sdf_render->flip_y    = 0;
     232      sdf_render->overlaps  = 0;
     233  
     234      return FT_Err_Ok;
     235    }
     236  
     237  
     238    static void
     239    ft_sdf_done( FT_Module  module )
     240    {
     241      FT_UNUSED( module );
     242    }
     243  
     244  
     245    /* generate signed distance field from a glyph's slot image */
     246    static FT_Error
     247    ft_sdf_render( FT_Renderer       module,
     248                   FT_GlyphSlot      slot,
     249                   FT_Render_Mode    mode,
     250                   const FT_Vector*  origin )
     251    {
     252      FT_Error     error   = FT_Err_Ok;
     253      FT_Outline*  outline = &slot->outline;
     254      FT_Bitmap*   bitmap  = &slot->bitmap;
     255      FT_Memory    memory  = NULL;
     256      FT_Renderer  render  = NULL;
     257  
     258      FT_Pos  x_shift = 0;
     259      FT_Pos  y_shift = 0;
     260  
     261      FT_Pos  x_pad = 0;
     262      FT_Pos  y_pad = 0;
     263  
     264      SDF_Raster_Params  params;
     265      SDF_Renderer       sdf_module = SDF_RENDERER( module );
     266  
     267  
     268      render = &sdf_module->root;
     269      memory = render->root.memory;
     270  
     271      /* check whether slot format is correct before rendering */
     272      if ( slot->format != render->glyph_format )
     273      {
     274        error = FT_THROW( Invalid_Glyph_Format );
     275        goto Exit;
     276      }
     277  
     278      /* check whether render mode is correct */
     279      if ( mode != FT_RENDER_MODE_SDF )
     280      {
     281        error = FT_THROW( Cannot_Render_Glyph );
     282        goto Exit;
     283      }
     284  
     285      /* deallocate the previously allocated bitmap */
     286      if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
     287      {
     288        FT_FREE( bitmap->buffer );
     289        slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
     290      }
     291  
     292      /* preset the bitmap using the glyph's outline;         */
     293      /* the sdf bitmap is similar to an anti-aliased bitmap  */
     294      /* with a slightly bigger size and different pixel mode */
     295      if ( ft_glyphslot_preset_bitmap( slot, FT_RENDER_MODE_NORMAL, origin ) )
     296      {
     297        error = FT_THROW( Raster_Overflow );
     298        goto Exit;
     299      }
     300  
     301      /* nothing to render */
     302      if ( !bitmap->rows || !bitmap->pitch )
     303        goto Exit;
     304  
     305      /* the padding will simply be equal to the `spread' */
     306      x_pad = sdf_module->spread;
     307      y_pad = sdf_module->spread;
     308  
     309      /* apply the padding; will be in all the directions */
     310      bitmap->rows  += y_pad * 2;
     311      bitmap->width += x_pad * 2;
     312  
     313      /* ignore the pitch, pixel mode and set custom */
     314      bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
     315      bitmap->pitch      = (int)( bitmap->width );
     316      bitmap->num_grays  = 255;
     317  
     318      /* allocate new buffer */
     319      if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) )
     320        goto Exit;
     321  
     322      slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
     323  
     324      slot->bitmap_top  += y_pad;
     325      slot->bitmap_left -= x_pad;
     326  
     327      x_shift  = 64 * -slot->bitmap_left;
     328      y_shift  = 64 * -slot->bitmap_top;
     329      y_shift += 64 * (FT_Int)bitmap->rows;
     330  
     331      if ( origin )
     332      {
     333        x_shift += origin->x;
     334        y_shift += origin->y;
     335      }
     336  
     337      /* translate outline to render it into the bitmap */
     338      if ( x_shift || y_shift )
     339        FT_Outline_Translate( outline, x_shift, y_shift );
     340  
     341      /* set up parameters */
     342      params.root.target = bitmap;
     343      params.root.source = outline;
     344      params.root.flags  = FT_RASTER_FLAG_SDF;
     345      params.spread      = sdf_module->spread;
     346      params.flip_sign   = sdf_module->flip_sign;
     347      params.flip_y      = sdf_module->flip_y;
     348      params.overlaps    = sdf_module->overlaps;
     349  
     350      /* render the outline */
     351      error = render->raster_render( render->raster,
     352                                     (const FT_Raster_Params*)&params );
     353  
     354      /* transform the outline back to the original state */
     355      if ( x_shift || y_shift )
     356        FT_Outline_Translate( outline, -x_shift, -y_shift );
     357  
     358    Exit:
     359      if ( !error )
     360      {
     361        /* the glyph is successfully rendered to a bitmap */
     362        slot->format = FT_GLYPH_FORMAT_BITMAP;
     363      }
     364      else if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
     365      {
     366        FT_FREE( bitmap->buffer );
     367        slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
     368      }
     369  
     370      return error;
     371    }
     372  
     373  
     374    /* transform the glyph using matrix and/or delta */
     375    static FT_Error
     376    ft_sdf_transform( FT_Renderer       render,
     377                      FT_GlyphSlot      slot,
     378                      const FT_Matrix*  matrix,
     379                      const FT_Vector*  delta )
     380    {
     381      FT_Error  error = FT_Err_Ok;
     382  
     383  
     384      if ( slot->format != render->glyph_format )
     385      {
     386        error = FT_THROW( Invalid_Argument );
     387        goto Exit;
     388      }
     389  
     390      if ( matrix )
     391        FT_Outline_Transform( &slot->outline, matrix );
     392  
     393      if ( delta )
     394        FT_Outline_Translate( &slot->outline, delta->x, delta->y );
     395  
     396    Exit:
     397      return error;
     398    }
     399  
     400  
     401    /* return the control box of a glyph's outline */
     402    static void
     403    ft_sdf_get_cbox( FT_Renderer   render,
     404                     FT_GlyphSlot  slot,
     405                     FT_BBox*      cbox )
     406    {
     407      FT_ZERO( cbox );
     408  
     409      if ( slot->format == render->glyph_format )
     410        FT_Outline_Get_CBox( &slot->outline, cbox );
     411    }
     412  
     413  
     414    /* set render specific modes or attributes */
     415    static FT_Error
     416    ft_sdf_set_mode( FT_Renderer  render,
     417                     FT_ULong     mode_tag,
     418                     FT_Pointer   data )
     419    {
     420      /* pass it to the rasterizer */
     421      return render->clazz->raster_class->raster_set_mode( render->raster,
     422                                                           mode_tag,
     423                                                           data );
     424    }
     425  
     426  
     427    FT_DEFINE_RENDERER(
     428      ft_sdf_renderer_class,
     429  
     430      FT_MODULE_RENDERER,
     431      sizeof ( SDF_Renderer_Module ),
     432  
     433      "sdf",
     434      0x10000L,
     435      0x20000L,
     436  
     437      NULL,
     438  
     439      (FT_Module_Constructor)ft_sdf_init,
     440      (FT_Module_Destructor) ft_sdf_done,
     441      (FT_Module_Requester)  ft_sdf_requester,
     442  
     443      FT_GLYPH_FORMAT_OUTLINE,
     444  
     445      (FT_Renderer_RenderFunc)   ft_sdf_render,     /* render_glyph    */
     446      (FT_Renderer_TransformFunc)ft_sdf_transform,  /* transform_glyph */
     447      (FT_Renderer_GetCBoxFunc)  ft_sdf_get_cbox,   /* get_glyph_cbox  */
     448      (FT_Renderer_SetModeFunc)  ft_sdf_set_mode,   /* set_mode        */
     449  
     450      (FT_Raster_Funcs*)&ft_sdf_raster              /* raster_class    */
     451    )
     452  
     453  
     454    /*************************************************************************/
     455    /*************************************************************************/
     456    /**                                                                     **/
     457    /**  BITMAP TO SDF CONVERTER                                            **/
     458    /**                                                                     **/
     459    /*************************************************************************/
     460    /*************************************************************************/
     461  
     462    /* generate signed distance field from glyph's bitmap */
     463    static FT_Error
     464    ft_bsdf_render( FT_Renderer       module,
     465                    FT_GlyphSlot      slot,
     466                    FT_Render_Mode    mode,
     467                    const FT_Vector*  origin )
     468    {
     469      FT_Error   error  = FT_Err_Ok;
     470      FT_Memory  memory = NULL;
     471  
     472      FT_Bitmap*   bitmap  = &slot->bitmap;
     473      FT_Renderer  render  = NULL;
     474      FT_Bitmap    target;
     475  
     476      FT_Pos  x_pad = 0;
     477      FT_Pos  y_pad = 0;
     478  
     479      SDF_Raster_Params  params;
     480      SDF_Renderer       sdf_module = SDF_RENDERER( module );
     481  
     482  
     483      /* initialize the bitmap in case any error occurs */
     484      FT_Bitmap_Init( &target );
     485  
     486      render = &sdf_module->root;
     487      memory = render->root.memory;
     488  
     489      /* check whether slot format is correct before rendering */
     490      if ( slot->format != render->glyph_format )
     491      {
     492        error = FT_THROW( Invalid_Glyph_Format );
     493        goto Exit;
     494      }
     495  
     496      /* check whether render mode is correct */
     497      if ( mode != FT_RENDER_MODE_SDF )
     498      {
     499        error = FT_THROW( Cannot_Render_Glyph );
     500        goto Exit;
     501      }
     502  
     503      if ( origin )
     504      {
     505        FT_ERROR(( "ft_bsdf_render: can't translate the bitmap\n" ));
     506  
     507        error = FT_THROW( Unimplemented_Feature );
     508        goto Exit;
     509      }
     510  
     511      /* nothing to render */
     512      if ( !bitmap->rows || !bitmap->pitch )
     513        goto Exit;
     514  
     515      /* Do not generate SDF if the bitmap is not owned by the       */
     516      /* glyph: it might be that the source buffer is already freed. */
     517      if ( !( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) )
     518      {
     519        FT_ERROR(( "ft_bsdf_render: can't generate SDF from"
     520                   " unowned source bitmap\n" ));
     521  
     522        error = FT_THROW( Invalid_Argument );
     523        goto Exit;
     524      }
     525  
     526      FT_Bitmap_New( &target );
     527  
     528      /* padding will simply be equal to `spread` */
     529      x_pad = sdf_module->spread;
     530      y_pad = sdf_module->spread;
     531  
     532      /* apply padding, which extends to all directions */
     533      target.rows  = bitmap->rows  + y_pad * 2;
     534      target.width = bitmap->width + x_pad * 2;
     535  
     536      /* set up the target bitmap */
     537      target.pixel_mode = FT_PIXEL_MODE_GRAY;
     538      target.pitch      = (int)( target.width );
     539      target.num_grays  = 255;
     540  
     541      if ( FT_ALLOC_MULT( target.buffer, target.rows, target.pitch ) )
     542        goto Exit;
     543  
     544      /* set up parameters */
     545      params.root.target = &target;
     546      params.root.source = bitmap;
     547      params.root.flags  = FT_RASTER_FLAG_SDF;
     548      params.spread      = sdf_module->spread;
     549      params.flip_sign   = sdf_module->flip_sign;
     550      params.flip_y      = sdf_module->flip_y;
     551  
     552      error = render->raster_render( render->raster,
     553                                     (const FT_Raster_Params*)&params );
     554  
     555    Exit:
     556      if ( !error )
     557      {
     558        /* the glyph is successfully converted to a SDF */
     559        if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
     560          FT_FREE( bitmap->buffer );
     561  
     562        slot->bitmap       = target;
     563        slot->bitmap_top  += y_pad;
     564        slot->bitmap_left -= x_pad;
     565  
     566        if ( target.buffer )
     567          slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
     568      }
     569      else if ( target.buffer )
     570        FT_FREE( target.buffer );
     571  
     572      return error;
     573    }
     574  
     575  
     576    FT_DEFINE_RENDERER(
     577      ft_bitmap_sdf_renderer_class,
     578  
     579      FT_MODULE_RENDERER,
     580      sizeof ( SDF_Renderer_Module ),
     581  
     582      "bsdf",
     583      0x10000L,
     584      0x20000L,
     585  
     586      NULL,
     587  
     588      (FT_Module_Constructor)ft_sdf_init,
     589      (FT_Module_Destructor) ft_sdf_done,
     590      (FT_Module_Requester)  ft_sdf_requester,
     591  
     592      FT_GLYPH_FORMAT_BITMAP,
     593  
     594      (FT_Renderer_RenderFunc)   ft_bsdf_render,    /* render_glyph    */
     595      (FT_Renderer_TransformFunc)ft_sdf_transform,  /* transform_glyph */
     596      (FT_Renderer_GetCBoxFunc)  ft_sdf_get_cbox,   /* get_glyph_cbox  */
     597      (FT_Renderer_SetModeFunc)  ft_sdf_set_mode,   /* set_mode        */
     598  
     599      (FT_Raster_Funcs*)&ft_bitmap_sdf_raster       /* raster_class    */
     600    )
     601  
     602  
     603  /* END */