(root)/
freetype-2.13.2/
src/
smooth/
ftsmooth.c
       1  /****************************************************************************
       2   *
       3   * ftsmooth.c
       4   *
       5   *   Anti-aliasing renderer interface (body).
       6   *
       7   * Copyright (C) 2000-2023 by
       8   * David Turner, Robert Wilhelm, and Werner Lemberg.
       9   *
      10   * This file is part of the FreeType project, and may only be used,
      11   * modified, and distributed under the terms of the FreeType project
      12   * license, LICENSE.TXT.  By continuing to use, modify, or distribute
      13   * this file you indicate that you have read the license and
      14   * understand and accept it fully.
      15   *
      16   */
      17  
      18  
      19  #include <freetype/internal/ftdebug.h>
      20  #include <freetype/internal/ftobjs.h>
      21  #include <freetype/ftoutln.h>
      22  #include "ftsmooth.h"
      23  #include "ftgrays.h"
      24  
      25  #include "ftsmerrs.h"
      26  
      27  
      28    /* sets render-specific mode */
      29    static FT_Error
      30    ft_smooth_set_mode( FT_Renderer  render,
      31                        FT_ULong     mode_tag,
      32                        FT_Pointer   data )
      33    {
      34      /* we simply pass it to the raster */
      35      return render->clazz->raster_class->raster_set_mode( render->raster,
      36                                                           mode_tag,
      37                                                           data );
      38    }
      39  
      40    /* transform a given glyph image */
      41    static FT_Error
      42    ft_smooth_transform( FT_Renderer       render,
      43                         FT_GlyphSlot      slot,
      44                         const FT_Matrix*  matrix,
      45                         const FT_Vector*  delta )
      46    {
      47      FT_Error  error = FT_Err_Ok;
      48  
      49  
      50      if ( slot->format != render->glyph_format )
      51      {
      52        error = FT_THROW( Invalid_Argument );
      53        goto Exit;
      54      }
      55  
      56      if ( matrix )
      57        FT_Outline_Transform( &slot->outline, matrix );
      58  
      59      if ( delta )
      60        FT_Outline_Translate( &slot->outline, delta->x, delta->y );
      61  
      62    Exit:
      63      return error;
      64    }
      65  
      66  
      67    /* return the glyph's control box */
      68    static void
      69    ft_smooth_get_cbox( FT_Renderer   render,
      70                        FT_GlyphSlot  slot,
      71                        FT_BBox*      cbox )
      72    {
      73      FT_ZERO( cbox );
      74  
      75      if ( slot->format == render->glyph_format )
      76        FT_Outline_Get_CBox( &slot->outline, cbox );
      77    }
      78  
      79    typedef struct TOrigin_
      80    {
      81      unsigned char*  origin;  /* pixmap origin at the bottom-left */
      82      int             pitch;   /* pitch to go down one row */
      83  
      84    } TOrigin;
      85  
      86  #ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
      87  
      88    /* initialize renderer -- init its raster */
      89    static FT_Error
      90    ft_smooth_init( FT_Module  module )   /* FT_Renderer */
      91    {
      92      FT_Renderer  render = (FT_Renderer)module;
      93  
      94      FT_Vector*  sub = render->root.library->lcd_geometry;
      95  
      96  
      97      /* set up default subpixel geometry for striped RGB panels. */
      98      sub[0].x = -21;
      99      sub[0].y = 0;
     100      sub[1].x = 0;
     101      sub[1].y = 0;
     102      sub[2].x = 21;
     103      sub[2].y = 0;
     104  
     105      render->clazz->raster_class->raster_reset( render->raster, NULL, 0 );
     106  
     107      return 0;
     108    }
     109  
     110  
     111    /* This function writes every third byte in direct rendering mode */
     112    static void
     113    ft_smooth_lcd_spans( int             y,
     114                         int             count,
     115                         const FT_Span*  spans,
     116                         void*           target_ )   /* TOrigin* */
     117    {
     118      TOrigin*  target = (TOrigin*)target_;
     119  
     120      unsigned char*  dst_line = target->origin - y * target->pitch;
     121      unsigned char*  dst;
     122      unsigned short  w;
     123  
     124  
     125      for ( ; count--; spans++ )
     126        for ( dst = dst_line + spans->x * 3, w = spans->len; w--; dst += 3 )
     127          *dst = spans->coverage;
     128    }
     129  
     130  
     131    static FT_Error
     132    ft_smooth_raster_lcd( FT_Renderer  render,
     133                          FT_Outline*  outline,
     134                          FT_Bitmap*   bitmap )
     135    {
     136      FT_Error      error = FT_Err_Ok;
     137      FT_Vector*    sub   = render->root.library->lcd_geometry;
     138      FT_Pos        x, y;
     139  
     140      FT_Raster_Params   params;
     141      TOrigin            target;
     142  
     143  
     144      /* Render 3 separate coverage bitmaps, shifting the outline.  */
     145      /* Set up direct rendering to record them on each third byte. */
     146      params.source     = outline;
     147      params.flags      = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT;
     148      params.gray_spans = ft_smooth_lcd_spans;
     149      params.user       = &target;
     150  
     151      params.clip_box.xMin = 0;
     152      params.clip_box.yMin = 0;
     153      params.clip_box.xMax = bitmap->width;
     154      params.clip_box.yMax = bitmap->rows;
     155  
     156      if ( bitmap->pitch < 0 )
     157        target.origin = bitmap->buffer;
     158      else
     159        target.origin = bitmap->buffer
     160                        + ( bitmap->rows - 1 ) * (unsigned int)bitmap->pitch;
     161  
     162      target.pitch = bitmap->pitch;
     163  
     164      FT_Outline_Translate( outline,
     165                            -sub[0].x,
     166                            -sub[0].y );
     167      error = render->raster_render( render->raster, &params );
     168      x = sub[0].x;
     169      y = sub[0].y;
     170      if ( error )
     171        goto Exit;
     172  
     173      target.origin++;
     174      FT_Outline_Translate( outline,
     175                            sub[0].x - sub[1].x,
     176                            sub[0].y - sub[1].y );
     177      error = render->raster_render( render->raster, &params );
     178      x = sub[1].x;
     179      y = sub[1].y;
     180      if ( error )
     181        goto Exit;
     182  
     183      target.origin++;
     184      FT_Outline_Translate( outline,
     185                            sub[1].x - sub[2].x,
     186                            sub[1].y - sub[2].y );
     187      error = render->raster_render( render->raster, &params );
     188      x = sub[2].x;
     189      y = sub[2].y;
     190  
     191    Exit:
     192      FT_Outline_Translate( outline, x, y );
     193  
     194      return error;
     195    }
     196  
     197  
     198    static FT_Error
     199    ft_smooth_raster_lcdv( FT_Renderer  render,
     200                           FT_Outline*  outline,
     201                           FT_Bitmap*   bitmap )
     202    {
     203      FT_Error     error = FT_Err_Ok;
     204      int          pitch = bitmap->pitch;
     205      FT_Vector*   sub   = render->root.library->lcd_geometry;
     206      FT_Pos       x, y;
     207  
     208      FT_Raster_Params  params;
     209  
     210  
     211      params.target = bitmap;
     212      params.source = outline;
     213      params.flags  = FT_RASTER_FLAG_AA;
     214  
     215      /* Render 3 separate coverage bitmaps, shifting the outline. */
     216      /* Notice that the subpixel geometry vectors are rotated.    */
     217      /* Triple the pitch to render on each third row.            */
     218      bitmap->pitch *= 3;
     219      bitmap->rows  /= 3;
     220  
     221      FT_Outline_Translate( outline,
     222                            -sub[0].y,
     223                            sub[0].x );
     224      error = render->raster_render( render->raster, &params );
     225      x = sub[0].y;
     226      y = -sub[0].x;
     227      if ( error )
     228        goto Exit;
     229  
     230      bitmap->buffer += pitch;
     231      FT_Outline_Translate( outline,
     232                            sub[0].y - sub[1].y,
     233                            sub[1].x - sub[0].x );
     234      error = render->raster_render( render->raster, &params );
     235      x = sub[1].y;
     236      y = -sub[1].x;
     237      bitmap->buffer -= pitch;
     238      if ( error )
     239        goto Exit;
     240  
     241      bitmap->buffer += 2 * pitch;
     242      FT_Outline_Translate( outline,
     243                            sub[1].y - sub[2].y,
     244                            sub[2].x - sub[1].x );
     245      error = render->raster_render( render->raster, &params );
     246      x = sub[2].y;
     247      y = -sub[2].x;
     248      bitmap->buffer -= 2 * pitch;
     249  
     250    Exit:
     251      FT_Outline_Translate( outline, x, y );
     252  
     253      bitmap->pitch /= 3;
     254      bitmap->rows  *= 3;
     255  
     256      return error;
     257    }
     258  
     259  #else   /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
     260  
     261    /* initialize renderer -- init its raster */
     262    static FT_Error
     263    ft_smooth_init( FT_Module  module )   /* FT_Renderer */
     264    {
     265      FT_Renderer  render = (FT_Renderer)module;
     266  
     267  
     268      /* set up default LCD filtering */
     269      FT_Library_SetLcdFilter( render->root.library, FT_LCD_FILTER_DEFAULT );
     270  
     271      render->clazz->raster_class->raster_reset( render->raster, NULL, 0 );
     272  
     273      return 0;
     274    }
     275  
     276  
     277    static FT_Error
     278    ft_smooth_raster_lcd( FT_Renderer  render,
     279                          FT_Outline*  outline,
     280                          FT_Bitmap*   bitmap )
     281    {
     282      FT_Error    error      = FT_Err_Ok;
     283      FT_Vector*  points     = outline->points;
     284      FT_Vector*  points_end = FT_OFFSET( points, outline->n_points );
     285      FT_Vector*  vec;
     286  
     287      FT_Raster_Params  params;
     288  
     289  
     290      params.target = bitmap;
     291      params.source = outline;
     292      params.flags  = FT_RASTER_FLAG_AA;
     293  
     294      /* implode outline */
     295      for ( vec = points; vec < points_end; vec++ )
     296        vec->x *= 3;
     297  
     298      /* render outline into the bitmap */
     299      error = render->raster_render( render->raster, &params );
     300  
     301      /* deflate outline */
     302      for ( vec = points; vec < points_end; vec++ )
     303        vec->x /= 3;
     304  
     305      return error;
     306    }
     307  
     308  
     309    static FT_Error
     310    ft_smooth_raster_lcdv( FT_Renderer  render,
     311                           FT_Outline*  outline,
     312                           FT_Bitmap*   bitmap )
     313    {
     314      FT_Error    error      = FT_Err_Ok;
     315      FT_Vector*  points     = outline->points;
     316      FT_Vector*  points_end = FT_OFFSET( points, outline->n_points );
     317      FT_Vector*  vec;
     318  
     319      FT_Raster_Params  params;
     320  
     321  
     322      params.target = bitmap;
     323      params.source = outline;
     324      params.flags  = FT_RASTER_FLAG_AA;
     325  
     326      /* implode outline */
     327      for ( vec = points; vec < points_end; vec++ )
     328        vec->y *= 3;
     329  
     330      /* render outline into the bitmap */
     331      error = render->raster_render( render->raster, &params );
     332  
     333      /* deflate outline */
     334      for ( vec = points; vec < points_end; vec++ )
     335        vec->y /= 3;
     336  
     337      return error;
     338    }
     339  
     340  #endif  /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
     341  
     342  /* Oversampling scale to be used in rendering overlaps */
     343  #define SCALE  ( 1 << 2 )
     344  
     345    /* This function averages inflated spans in direct rendering mode */
     346    static void
     347    ft_smooth_overlap_spans( int             y,
     348                             int             count,
     349                             const FT_Span*  spans,
     350                             void*           target_ )
     351    {
     352      TOrigin*  target = (TOrigin*)target_;
     353  
     354  
     355      unsigned char*  dst = target->origin - ( y / SCALE ) * target->pitch;
     356      unsigned short  x;
     357      unsigned int    cover, sum;
     358  
     359  
     360      /* When accumulating the oversampled spans we need to assure that  */
     361      /* fully covered pixels are equal to 255 and do not overflow.      */
     362      /* It is important that the SCALE is a power of 2, each subpixel   */
     363      /* cover can also reach a power of 2 after rounding, and the total */
     364      /* is clamped to 255 when it adds up to 256.                       */
     365      for ( ; count--; spans++ )
     366      {
     367        cover = ( spans->coverage + SCALE * SCALE / 2 ) / ( SCALE * SCALE );
     368        for ( x = 0; x < spans->len; x++ )
     369        {
     370          sum                           = dst[( spans->x + x ) / SCALE] + cover;
     371          dst[( spans->x + x ) / SCALE] = (unsigned char)( sum - ( sum >> 8 ) );
     372        }
     373      }
     374    }
     375  
     376  
     377    static FT_Error
     378    ft_smooth_raster_overlap( FT_Renderer  render,
     379                              FT_Outline*  outline,
     380                              FT_Bitmap*   bitmap )
     381    {
     382      FT_Error    error      = FT_Err_Ok;
     383      FT_Vector*  points     = outline->points;
     384      FT_Vector*  points_end = FT_OFFSET( points, outline->n_points );
     385      FT_Vector*  vec;
     386  
     387      FT_Raster_Params   params;
     388      TOrigin            target;
     389  
     390  
     391      /* Reject outlines that are too wide for 16-bit FT_Span.       */
     392      /* Other limits are applied upstream with the same error code. */
     393      if ( bitmap->width * SCALE > 0x7FFF )
     394        return FT_THROW( Raster_Overflow );
     395  
     396      /* Set up direct rendering to average oversampled spans. */
     397      params.source     = outline;
     398      params.flags      = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT;
     399      params.gray_spans = ft_smooth_overlap_spans;
     400      params.user       = &target;
     401  
     402      params.clip_box.xMin = 0;
     403      params.clip_box.yMin = 0;
     404      params.clip_box.xMax = bitmap->width * SCALE;
     405      params.clip_box.yMax = bitmap->rows  * SCALE;
     406  
     407      if ( bitmap->pitch < 0 )
     408        target.origin = bitmap->buffer;
     409      else
     410        target.origin = bitmap->buffer
     411                        + ( bitmap->rows - 1 ) * (unsigned int)bitmap->pitch;
     412  
     413      target.pitch = bitmap->pitch;
     414  
     415      /* inflate outline */
     416      for ( vec = points; vec < points_end; vec++ )
     417      {
     418        vec->x *= SCALE;
     419        vec->y *= SCALE;
     420      }
     421  
     422      /* render outline into the bitmap */
     423      error = render->raster_render( render->raster, &params );
     424  
     425      /* deflate outline */
     426      for ( vec = points; vec < points_end; vec++ )
     427      {
     428        vec->x /= SCALE;
     429        vec->y /= SCALE;
     430      }
     431  
     432      return error;
     433    }
     434  
     435  #undef SCALE
     436  
     437    static FT_Error
     438    ft_smooth_render( FT_Renderer       render,
     439                      FT_GlyphSlot      slot,
     440                      FT_Render_Mode    mode,
     441                      const FT_Vector*  origin )
     442    {
     443      FT_Error     error   = FT_Err_Ok;
     444      FT_Outline*  outline = &slot->outline;
     445      FT_Bitmap*   bitmap  = &slot->bitmap;
     446      FT_Memory    memory  = render->root.memory;
     447      FT_Pos       x_shift = 0;
     448      FT_Pos       y_shift = 0;
     449  
     450  
     451      /* check glyph image format */
     452      if ( slot->format != render->glyph_format )
     453      {
     454        error = FT_THROW( Invalid_Argument );
     455        goto Exit;
     456      }
     457  
     458      /* check mode */
     459      if ( mode != FT_RENDER_MODE_NORMAL &&
     460           mode != FT_RENDER_MODE_LIGHT  &&
     461           mode != FT_RENDER_MODE_LCD    &&
     462           mode != FT_RENDER_MODE_LCD_V  )
     463      {
     464        error = FT_THROW( Cannot_Render_Glyph );
     465        goto Exit;
     466      }
     467  
     468      /* release old bitmap buffer */
     469      if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
     470      {
     471        FT_FREE( bitmap->buffer );
     472        slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
     473      }
     474  
     475      if ( ft_glyphslot_preset_bitmap( slot, mode, origin ) )
     476      {
     477        error = FT_THROW( Raster_Overflow );
     478        goto Exit;
     479      }
     480  
     481      if ( !bitmap->rows || !bitmap->pitch )
     482        goto Exit;
     483  
     484      /* allocate new one */
     485      if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) )
     486        goto Exit;
     487  
     488      slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
     489  
     490      x_shift = 64 * -slot->bitmap_left;
     491      y_shift = 64 * -slot->bitmap_top;
     492      if ( bitmap->pixel_mode == FT_PIXEL_MODE_LCD_V )
     493        y_shift += 64 * (FT_Int)bitmap->rows / 3;
     494      else
     495        y_shift += 64 * (FT_Int)bitmap->rows;
     496  
     497      if ( origin )
     498      {
     499        x_shift += origin->x;
     500        y_shift += origin->y;
     501      }
     502  
     503      /* translate outline to render it into the bitmap */
     504      if ( x_shift || y_shift )
     505        FT_Outline_Translate( outline, x_shift, y_shift );
     506  
     507      if ( mode == FT_RENDER_MODE_NORMAL ||
     508           mode == FT_RENDER_MODE_LIGHT  )
     509      {
     510        if ( outline->flags & FT_OUTLINE_OVERLAP )
     511          error = ft_smooth_raster_overlap( render, outline, bitmap );
     512        else
     513        {
     514          FT_Raster_Params  params;
     515  
     516  
     517          params.target = bitmap;
     518          params.source = outline;
     519          params.flags  = FT_RASTER_FLAG_AA;
     520  
     521          error = render->raster_render( render->raster, &params );
     522        }
     523      }
     524      else
     525      {
     526        if ( mode == FT_RENDER_MODE_LCD )
     527          error = ft_smooth_raster_lcd ( render, outline, bitmap );
     528        else if ( mode == FT_RENDER_MODE_LCD_V )
     529          error = ft_smooth_raster_lcdv( render, outline, bitmap );
     530  
     531  #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
     532  
     533        /* finally apply filtering */
     534        {
     535          FT_Byte*                 lcd_weights;
     536          FT_Bitmap_LcdFilterFunc  lcd_filter_func;
     537  
     538  
     539          /* Per-face LCD filtering takes priority if set up. */
     540          if ( slot->face && slot->face->internal->lcd_filter_func )
     541          {
     542            lcd_weights     = slot->face->internal->lcd_weights;
     543            lcd_filter_func = slot->face->internal->lcd_filter_func;
     544          }
     545          else
     546          {
     547            lcd_weights     = slot->library->lcd_weights;
     548            lcd_filter_func = slot->library->lcd_filter_func;
     549          }
     550  
     551          if ( lcd_filter_func )
     552            lcd_filter_func( bitmap, lcd_weights );
     553        }
     554  
     555  #endif /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
     556  
     557      }
     558  
     559    Exit:
     560      if ( !error )
     561      {
     562        /* everything is fine; the glyph is now officially a bitmap */
     563        slot->format = FT_GLYPH_FORMAT_BITMAP;
     564      }
     565      else if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
     566      {
     567        FT_FREE( bitmap->buffer );
     568        slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
     569      }
     570  
     571      if ( x_shift || y_shift )
     572        FT_Outline_Translate( outline, -x_shift, -y_shift );
     573  
     574      return error;
     575    }
     576  
     577  
     578    FT_DEFINE_RENDERER(
     579      ft_smooth_renderer_class,
     580  
     581        FT_MODULE_RENDERER,
     582        sizeof ( FT_RendererRec ),
     583  
     584        "smooth",
     585        0x10000L,
     586        0x20000L,
     587  
     588        NULL,    /* module specific interface */
     589  
     590        (FT_Module_Constructor)ft_smooth_init,  /* module_init   */
     591        (FT_Module_Destructor) NULL,            /* module_done   */
     592        (FT_Module_Requester)  NULL,            /* get_interface */
     593  
     594      FT_GLYPH_FORMAT_OUTLINE,
     595  
     596      (FT_Renderer_RenderFunc)   ft_smooth_render,     /* render_glyph    */
     597      (FT_Renderer_TransformFunc)ft_smooth_transform,  /* transform_glyph */
     598      (FT_Renderer_GetCBoxFunc)  ft_smooth_get_cbox,   /* get_glyph_cbox  */
     599      (FT_Renderer_SetModeFunc)  ft_smooth_set_mode,   /* set_mode        */
     600  
     601      (FT_Raster_Funcs*)&ft_grays_raster               /* raster_class    */
     602    )
     603  
     604  
     605  /* END */