Coverage Report

Created: 2021-08-22 09:07

/src/skia/third_party/externals/freetype/src/base/ftlcdfil.c
Line
Count
Source (jump to first uncovered line)
1
/****************************************************************************
2
 *
3
 * ftlcdfil.c
4
 *
5
 *   FreeType API for color filtering of subpixel bitmap glyphs (body).
6
 *
7
 * Copyright (C) 2006-2021 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
21
#include <freetype/ftlcdfil.h>
22
#include <freetype/ftimage.h>
23
#include <freetype/internal/ftobjs.h>
24
25
26
#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
27
28
/* define USE_LEGACY to implement the legacy filter */
29
#define  USE_LEGACY
30
31
#define FT_SHIFTCLAMP( x )  ( x >>= 8, (FT_Byte)( x > 255 ? 255 : x ) )
32
33
34
  /* add padding according to filter weights */
35
  FT_BASE_DEF( void )
36
  ft_lcd_padding( FT_BBox*        cbox,
37
                  FT_GlyphSlot    slot,
38
                  FT_Render_Mode  mode )
39
  {
40
    FT_Byte*                 lcd_weights;
41
    FT_Bitmap_LcdFilterFunc  lcd_filter_func;
42
43
44
    /* Per-face LCD filtering takes priority if set up. */
45
    if ( slot->face && slot->face->internal->lcd_filter_func )
46
    {
47
      lcd_weights     = slot->face->internal->lcd_weights;
48
      lcd_filter_func = slot->face->internal->lcd_filter_func;
49
    }
50
    else
51
    {
52
      lcd_weights     = slot->library->lcd_weights;
53
      lcd_filter_func = slot->library->lcd_filter_func;
54
    }
55
56
    if ( lcd_filter_func == ft_lcd_filter_fir )
57
    {
58
      if ( mode == FT_RENDER_MODE_LCD )
59
      {
60
        cbox->xMin -= lcd_weights[0] ? 43 :
61
                      lcd_weights[1] ? 22 : 0;
62
        cbox->xMax += lcd_weights[4] ? 43 :
63
                      lcd_weights[3] ? 22 : 0;
64
      }
65
      else if ( mode == FT_RENDER_MODE_LCD_V )
66
      {
67
        cbox->yMin -= lcd_weights[0] ? 43 :
68
                      lcd_weights[1] ? 22 : 0;
69
        cbox->yMax += lcd_weights[4] ? 43 :
70
                      lcd_weights[3] ? 22 : 0;
71
      }
72
    }
73
  }
74
75
76
  /* FIR filter used by the default and light filters */
77
  FT_BASE_DEF( void )
78
  ft_lcd_filter_fir( FT_Bitmap*           bitmap,
79
                     FT_LcdFiveTapFilter  weights )
80
  {
81
    FT_UInt   width  = (FT_UInt)bitmap->width;
82
    FT_UInt   height = (FT_UInt)bitmap->rows;
83
    FT_Int    pitch  = bitmap->pitch;
84
    FT_Byte*  origin = bitmap->buffer;
85
    FT_Byte   mode   = bitmap->pixel_mode;
86
87
88
    /* take care of bitmap flow */
89
    if ( pitch > 0 && height > 0 )
90
      origin += pitch * (FT_Int)( height - 1 );
91
92
    /* horizontal in-place FIR filter */
93
    if ( mode == FT_PIXEL_MODE_LCD && width >= 2 )
94
    {
95
      FT_Byte*  line = origin;
96
97
98
      /* `fir' must be at least 32 bit wide, since the sum of */
99
      /* the values in `weights' can exceed 0xFF              */
100
101
      for ( ; height > 0; height--, line -= pitch )
102
      {
103
        FT_UInt  fir[5];
104
        FT_UInt  val, xx;
105
106
107
        val    = line[0];
108
        fir[2] = weights[2] * val;
109
        fir[3] = weights[3] * val;
110
        fir[4] = weights[4] * val;
111
112
        val    = line[1];
113
        fir[1] = fir[2] + weights[1] * val;
114
        fir[2] = fir[3] + weights[2] * val;
115
        fir[3] = fir[4] + weights[3] * val;
116
        fir[4] =          weights[4] * val;
117
118
        for ( xx = 2; xx < width; xx++ )
119
        {
120
          val    = line[xx];
121
          fir[0] = fir[1] + weights[0] * val;
122
          fir[1] = fir[2] + weights[1] * val;
123
          fir[2] = fir[3] + weights[2] * val;
124
          fir[3] = fir[4] + weights[3] * val;
125
          fir[4] =          weights[4] * val;
126
127
          line[xx - 2] = FT_SHIFTCLAMP( fir[0] );
128
        }
129
130
        line[xx - 2] = FT_SHIFTCLAMP( fir[1] );
131
        line[xx - 1] = FT_SHIFTCLAMP( fir[2] );
132
      }
133
    }
134
135
    /* vertical in-place FIR filter */
136
    else if ( mode == FT_PIXEL_MODE_LCD_V && height >= 2 )
137
    {
138
      FT_Byte*  column = origin;
139
140
141
      for ( ; width > 0; width--, column++ )
142
      {
143
        FT_Byte*  col = column;
144
        FT_UInt   fir[5];
145
        FT_UInt   val, yy;
146
147
148
        val    = col[0];
149
        fir[2] = weights[2] * val;
150
        fir[3] = weights[3] * val;
151
        fir[4] = weights[4] * val;
152
        col   -= pitch;
153
154
        val    = col[0];
155
        fir[1] = fir[2] + weights[1] * val;
156
        fir[2] = fir[3] + weights[2] * val;
157
        fir[3] = fir[4] + weights[3] * val;
158
        fir[4] =          weights[4] * val;
159
        col   -= pitch;
160
161
        for ( yy = 2; yy < height; yy++, col -= pitch )
162
        {
163
          val    = col[0];
164
          fir[0] = fir[1] + weights[0] * val;
165
          fir[1] = fir[2] + weights[1] * val;
166
          fir[2] = fir[3] + weights[2] * val;
167
          fir[3] = fir[4] + weights[3] * val;
168
          fir[4] =          weights[4] * val;
169
170
          col[pitch * 2]  = FT_SHIFTCLAMP( fir[0] );
171
        }
172
173
        col[pitch * 2]  = FT_SHIFTCLAMP( fir[1] );
174
        col[pitch]      = FT_SHIFTCLAMP( fir[2] );
175
      }
176
    }
177
  }
178
179
180
#ifdef USE_LEGACY
181
182
  /* intra-pixel filter used by the legacy filter */
183
  static void
184
  _ft_lcd_filter_legacy( FT_Bitmap*      bitmap,
185
                         FT_Byte*        weights )
186
  {
187
    FT_UInt   width  = (FT_UInt)bitmap->width;
188
    FT_UInt   height = (FT_UInt)bitmap->rows;
189
    FT_Int    pitch  = bitmap->pitch;
190
    FT_Byte*  origin = bitmap->buffer;
191
    FT_Byte   mode   = bitmap->pixel_mode;
192
193
    static const unsigned int  filters[3][3] =
194
    {
195
      { 65538 * 9/13, 65538 * 1/6, 65538 * 1/13 },
196
      { 65538 * 3/13, 65538 * 4/6, 65538 * 3/13 },
197
      { 65538 * 1/13, 65538 * 1/6, 65538 * 9/13 }
198
    };
199
200
    FT_UNUSED( weights );
201
202
203
    /* take care of bitmap flow */
204
    if ( pitch > 0 && height > 0 )
205
      origin += pitch * (FT_Int)( height - 1 );
206
207
    /* horizontal in-place intra-pixel filter */
208
    if ( mode == FT_PIXEL_MODE_LCD && width >= 3 )
209
    {
210
      FT_Byte*  line = origin;
211
212
213
      for ( ; height > 0; height--, line -= pitch )
214
      {
215
        FT_UInt  xx;
216
217
218
        for ( xx = 0; xx < width; xx += 3 )
219
        {
220
          FT_UInt  r, g, b;
221
          FT_UInt  p;
222
223
224
          p  = line[xx];
225
          r  = filters[0][0] * p;
226
          g  = filters[0][1] * p;
227
          b  = filters[0][2] * p;
228
229
          p  = line[xx + 1];
230
          r += filters[1][0] * p;
231
          g += filters[1][1] * p;
232
          b += filters[1][2] * p;
233
234
          p  = line[xx + 2];
235
          r += filters[2][0] * p;
236
          g += filters[2][1] * p;
237
          b += filters[2][2] * p;
238
239
          line[xx]     = (FT_Byte)( r / 65536 );
240
          line[xx + 1] = (FT_Byte)( g / 65536 );
241
          line[xx + 2] = (FT_Byte)( b / 65536 );
242
        }
243
      }
244
    }
245
    else if ( mode == FT_PIXEL_MODE_LCD_V && height >= 3 )
246
    {
247
      FT_Byte*  column = origin;
248
249
250
      for ( ; width > 0; width--, column++ )
251
      {
252
        FT_Byte*  col = column - 2 * pitch;
253
254
255
        for ( ; height > 0; height -= 3, col -= 3 * pitch )
256
        {
257
          FT_UInt  r, g, b;
258
          FT_UInt  p;
259
260
261
          p  = col[0];
262
          r  = filters[0][0] * p;
263
          g  = filters[0][1] * p;
264
          b  = filters[0][2] * p;
265
266
          p  = col[pitch];
267
          r += filters[1][0] * p;
268
          g += filters[1][1] * p;
269
          b += filters[1][2] * p;
270
271
          p  = col[pitch * 2];
272
          r += filters[2][0] * p;
273
          g += filters[2][1] * p;
274
          b += filters[2][2] * p;
275
276
          col[0]         = (FT_Byte)( r / 65536 );
277
          col[pitch]     = (FT_Byte)( g / 65536 );
278
          col[pitch * 2] = (FT_Byte)( b / 65536 );
279
        }
280
      }
281
    }
282
  }
283
284
#endif /* USE_LEGACY */
285
286
287
  /* documentation in ftlcdfil.h */
288
289
  FT_EXPORT_DEF( FT_Error )
290
  FT_Library_SetLcdFilterWeights( FT_Library      library,
291
                                  unsigned char  *weights )
292
  {
293
    if ( !library )
294
      return FT_THROW( Invalid_Library_Handle );
295
296
    if ( !weights )
297
      return FT_THROW( Invalid_Argument );
298
299
    ft_memcpy( library->lcd_weights, weights, FT_LCD_FILTER_FIVE_TAPS );
300
    library->lcd_filter_func = ft_lcd_filter_fir;
301
302
    return FT_Err_Ok;
303
  }
304
305
306
  /* documentation in ftlcdfil.h */
307
308
  FT_EXPORT_DEF( FT_Error )
309
  FT_Library_SetLcdFilter( FT_Library    library,
310
                           FT_LcdFilter  filter )
311
  {
312
    static const FT_LcdFiveTapFilter  default_weights =
313
                   { 0x08, 0x4d, 0x56, 0x4d, 0x08 };
314
    static const FT_LcdFiveTapFilter  light_weights =
315
                   { 0x00, 0x55, 0x56, 0x55, 0x00 };
316
317
318
    if ( !library )
319
      return FT_THROW( Invalid_Library_Handle );
320
321
    switch ( filter )
322
    {
323
    case FT_LCD_FILTER_NONE:
324
      library->lcd_filter_func = NULL;
325
      break;
326
327
    case FT_LCD_FILTER_DEFAULT:
328
      ft_memcpy( library->lcd_weights,
329
                 default_weights,
330
                 FT_LCD_FILTER_FIVE_TAPS );
331
      library->lcd_filter_func = ft_lcd_filter_fir;
332
      break;
333
334
    case FT_LCD_FILTER_LIGHT:
335
      ft_memcpy( library->lcd_weights,
336
                 light_weights,
337
                 FT_LCD_FILTER_FIVE_TAPS );
338
      library->lcd_filter_func = ft_lcd_filter_fir;
339
      break;
340
341
#ifdef USE_LEGACY
342
343
    case FT_LCD_FILTER_LEGACY:
344
    case FT_LCD_FILTER_LEGACY1:
345
      library->lcd_filter_func = _ft_lcd_filter_legacy;
346
      break;
347
348
#endif
349
350
    default:
351
      return FT_THROW( Invalid_Argument );
352
    }
353
354
    return FT_Err_Ok;
355
  }
356
357
358
  FT_EXPORT_DEF( FT_Error )
359
  FT_Library_SetLcdGeometry( FT_Library  library,
360
                             FT_Vector   sub[3] )
361
  {
362
    FT_UNUSED( library );
363
    FT_UNUSED( sub );
364
365
    return FT_THROW( Unimplemented_Feature );
366
  }
367
368
#else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
369
370
  /* add padding to accommodate outline shifts */
371
  FT_BASE_DEF( void )
372
  ft_lcd_padding( FT_BBox*        cbox,
373
                  FT_GlyphSlot    slot,
374
                  FT_Render_Mode  mode )
375
  {
376
    FT_Vector*  sub = slot->library->lcd_geometry;
377
378
    if ( mode == FT_RENDER_MODE_LCD )
379
    {
380
      cbox->xMin -= FT_MAX( FT_MAX( sub[0].x, sub[1].x ), sub[2].x );
381
      cbox->xMax -= FT_MIN( FT_MIN( sub[0].x, sub[1].x ), sub[2].x );
382
      cbox->yMin -= FT_MAX( FT_MAX( sub[0].y, sub[1].y ), sub[2].y );
383
      cbox->yMax -= FT_MIN( FT_MIN( sub[0].y, sub[1].y ), sub[2].y );
384
    }
385
    else if ( mode == FT_RENDER_MODE_LCD_V )
386
    {
387
      cbox->xMin -= FT_MAX( FT_MAX( sub[0].y, sub[1].y ), sub[2].y );
388
      cbox->xMax -= FT_MIN( FT_MIN( sub[0].y, sub[1].y ), sub[2].y );
389
      cbox->yMin += FT_MIN( FT_MIN( sub[0].x, sub[1].x ), sub[2].x );
390
      cbox->yMax += FT_MAX( FT_MAX( sub[0].x, sub[1].x ), sub[2].x );
391
    }
392
  }
393
394
395
  FT_EXPORT_DEF( FT_Error )
396
  FT_Library_SetLcdFilterWeights( FT_Library      library,
397
                                  unsigned char  *weights )
398
0
  {
399
0
    FT_UNUSED( library );
400
0
    FT_UNUSED( weights );
401
402
0
    return FT_THROW( Unimplemented_Feature );
403
0
  }
404
405
406
  FT_EXPORT_DEF( FT_Error )
407
  FT_Library_SetLcdFilter( FT_Library    library,
408
                           FT_LcdFilter  filter )
409
0
  {
410
0
    FT_UNUSED( library );
411
0
    FT_UNUSED( filter );
412
413
0
    return FT_THROW( Unimplemented_Feature );
414
0
  }
415
416
417
  /* documentation in ftlcdfil.h */
418
419
  FT_EXPORT_DEF( FT_Error )
420
  FT_Library_SetLcdGeometry( FT_Library  library,
421
                             FT_Vector   sub[3] )
422
0
  {
423
0
    if ( !library )
424
0
      return FT_THROW( Invalid_Library_Handle );
425
426
0
    if ( !sub )
427
0
      return FT_THROW( Invalid_Argument );
428
429
0
    ft_memcpy( library->lcd_geometry, sub, 3 * sizeof( FT_Vector ) );
430
431
0
    return FT_Err_Ok;
432
0
  }
433
434
#endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
435
436
437
/* END */