1ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#if !defined(_FXFT_VERSION_) || _FXFT_VERSION_ == 2501
2ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/***************************************************************************/
3ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*                                                                         */
4ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*  ftlcdfil.c                                                             */
5ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*                                                                         */
6ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*    FreeType API for color filtering of subpixel bitmap glyphs (body).   */
7ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*                                                                         */
8ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*  Copyright 2006, 2008-2010, 2013 by                                     */
9ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
10ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*                                                                         */
11ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*  This file is part of the FreeType project, and may only be used,       */
12ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*  modified, and distributed under the terms of the FreeType project      */
13ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
14ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*  this file you indicate that you have read the license and              */
15ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*  understand and accept it fully.                                        */
16ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*                                                                         */
17ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/***************************************************************************/
18ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
19ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define FT2_BUILD_LIBRARY
20ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "../../include/ft2build.h"
21ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "../../include/freetype/internal/ftdebug.h"
22ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
23ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "../../include/freetype/ftlcdfil.h"
24ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "../../include/freetype/ftimage.h"
25ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "../../include/freetype/internal/ftobjs.h"
26ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
27ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
28ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
29ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
30ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* define USE_LEGACY to implement the legacy filter */
31ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define  USE_LEGACY
32ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
33ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* FIR filter used by the default and light filters */
34ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static void
35ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  _ft_lcd_filter_fir( FT_Bitmap*      bitmap,
36ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      FT_Render_Mode  mode,
37ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      FT_Library      library )
38ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
39ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*  weights = library->lcd_weights;
40ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt   width   = (FT_UInt)bitmap->width;
41ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt   height  = (FT_UInt)bitmap->rows;
42ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
43ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
44ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* horizontal in-place FIR filter */
45ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( mode == FT_RENDER_MODE_LCD && width >= 4 )
46ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
47ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Byte*  line = bitmap->buffer;
48ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
49ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
50ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      for ( ; height > 0; height--, line += bitmap->pitch )
51ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
52ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_UInt  fir[5];
53ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_UInt  val1, xx;
54ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
55ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
56ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        val1   = line[0];
57ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        fir[0] = weights[2] * val1;
58ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        fir[1] = weights[3] * val1;
59ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        fir[2] = weights[4] * val1;
60ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        fir[3] = 0;
61ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        fir[4] = 0;
62ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
63ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        val1    = line[1];
64ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        fir[0] += weights[1] * val1;
65ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        fir[1] += weights[2] * val1;
66ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        fir[2] += weights[3] * val1;
67ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        fir[3] += weights[4] * val1;
68ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
69ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        for ( xx = 2; xx < width; xx++ )
70ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
71ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_UInt  val, pix;
72ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
73ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
74ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          val    = line[xx];
75ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          pix    = fir[0] + weights[0] * val;
76ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          fir[0] = fir[1] + weights[1] * val;
77ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          fir[1] = fir[2] + weights[2] * val;
78ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          fir[2] = fir[3] + weights[3] * val;
79ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          fir[3] =          weights[4] * val;
80ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
81ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          pix        >>= 8;
82ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          pix         |= (FT_UInt)-(FT_Int)( pix >> 8 );
83ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          line[xx - 2] = (FT_Byte)pix;
84ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
85ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
86ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
87ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_UInt  pix;
88ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
89ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
90ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          pix          = fir[0] >> 8;
91ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          pix         |= (FT_UInt)-(FT_Int)( pix >> 8 );
92ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          line[xx - 2] = (FT_Byte)pix;
93ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
94ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          pix          = fir[1] >> 8;
95ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          pix         |= (FT_UInt)-(FT_Int)( pix >> 8 );
96ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          line[xx - 1] = (FT_Byte)pix;
97ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
98ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
99ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
100ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
101ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* vertical in-place FIR filter */
102ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else if ( mode == FT_RENDER_MODE_LCD_V && height >= 4 )
103ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
104ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Byte*  column = bitmap->buffer;
105ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Int    pitch  = bitmap->pitch;
106ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
107ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
108ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      for ( ; width > 0; width--, column++ )
109ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
110ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_Byte*  col = column;
111ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_UInt   fir[5];
112ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_UInt   val1, yy;
113ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
114ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
115ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        val1   = col[0];
116ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        fir[0] = weights[2] * val1;
117ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        fir[1] = weights[3] * val1;
118ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        fir[2] = weights[4] * val1;
119ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        fir[3] = 0;
120ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        fir[4] = 0;
121ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        col   += pitch;
122ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
123ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        val1    = col[0];
124ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        fir[0] += weights[1] * val1;
125ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        fir[1] += weights[2] * val1;
126ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        fir[2] += weights[3] * val1;
127ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        fir[3] += weights[4] * val1;
128ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        col    += pitch;
129ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
130ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        for ( yy = 2; yy < height; yy++ )
131ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
132ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_UInt  val, pix;
133ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
134ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
135ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          val    = col[0];
136ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          pix    = fir[0] + weights[0] * val;
137ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          fir[0] = fir[1] + weights[1] * val;
138ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          fir[1] = fir[2] + weights[2] * val;
139ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          fir[2] = fir[3] + weights[3] * val;
140ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          fir[3] =          weights[4] * val;
141ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
142ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          pix           >>= 8;
143ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          pix            |= (FT_UInt)-(FT_Int)( pix >> 8 );
144ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          col[-2 * pitch] = (FT_Byte)pix;
145ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          col            += pitch;
146ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
147ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
148ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
149ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_UInt  pix;
150ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
151ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
152ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          pix             = fir[0] >> 8;
153ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          pix            |= (FT_UInt)-(FT_Int)( pix >> 8 );
154ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          col[-2 * pitch] = (FT_Byte)pix;
155ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
156ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          pix         = fir[1] >> 8;
157ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          pix            |= (FT_UInt)-(FT_Int)( pix >> 8 );
158ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          col[-pitch] = (FT_Byte)pix;
159ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
160ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
161ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
162ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
163ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
164ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
165ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef USE_LEGACY
166ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
167ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* intra-pixel filter used by the legacy filter */
168ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static void
169ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  _ft_lcd_filter_legacy( FT_Bitmap*      bitmap,
170ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                         FT_Render_Mode  mode,
171ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                         FT_Library      library )
172ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
173ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt  width  = (FT_UInt)bitmap->width;
174ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt  height = (FT_UInt)bitmap->rows;
175ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Int   pitch  = bitmap->pitch;
176ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
177ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    static const int  filters[3][3] =
178ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
179ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      { 65538 * 9/13, 65538 * 1/6, 65538 * 1/13 },
180ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      { 65538 * 3/13, 65538 * 4/6, 65538 * 3/13 },
181ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      { 65538 * 1/13, 65538 * 1/6, 65538 * 9/13 }
182ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    };
183ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
184ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UNUSED( library );
185ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
186ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
187ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* horizontal in-place intra-pixel filter */
188ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( mode == FT_RENDER_MODE_LCD && width >= 3 )
189ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
190ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Byte*  line = bitmap->buffer;
191ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
192ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
193ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      for ( ; height > 0; height--, line += pitch )
194ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
195ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_UInt  xx;
196ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
197ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
198ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        for ( xx = 0; xx < width; xx += 3 )
199ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
200ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_UInt  r = 0;
201ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_UInt  g = 0;
202ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_UInt  b = 0;
203ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_UInt  p;
204ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
205ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
206ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          p  = line[xx];
207ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          r += filters[0][0] * p;
208ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          g += filters[0][1] * p;
209ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          b += filters[0][2] * p;
210ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
211ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          p  = line[xx + 1];
212ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          r += filters[1][0] * p;
213ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          g += filters[1][1] * p;
214ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          b += filters[1][2] * p;
215ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
216ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          p  = line[xx + 2];
217ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          r += filters[2][0] * p;
218ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          g += filters[2][1] * p;
219ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          b += filters[2][2] * p;
220ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
221ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          line[xx]     = (FT_Byte)( r / 65536 );
222ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          line[xx + 1] = (FT_Byte)( g / 65536 );
223ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          line[xx + 2] = (FT_Byte)( b / 65536 );
224ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
225ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
226ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
227ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else if ( mode == FT_RENDER_MODE_LCD_V && height >= 3 )
228ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
229ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Byte*  column = bitmap->buffer;
230ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
231ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
232ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      for ( ; width > 0; width--, column++ )
233ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
234ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_Byte*  col     = column;
235ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_Byte*  col_end = col + height * pitch;
236ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
237ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
238ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        for ( ; col < col_end; col += 3 * pitch )
239ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
240ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_UInt  r = 0;
241ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_UInt  g = 0;
242ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_UInt  b = 0;
243ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_UInt  p;
244ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
245ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
246ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          p  = col[0];
247ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          r += filters[0][0] * p;
248ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          g += filters[0][1] * p;
249ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          b += filters[0][2] * p;
250ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
251ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          p  = col[pitch];
252ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          r += filters[1][0] * p;
253ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          g += filters[1][1] * p;
254ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          b += filters[1][2] * p;
255ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
256ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          p  = col[pitch * 2];
257ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          r += filters[2][0] * p;
258ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          g += filters[2][1] * p;
259ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          b += filters[2][2] * p;
260ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
261ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          col[0]         = (FT_Byte)( r / 65536 );
262ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          col[pitch]     = (FT_Byte)( g / 65536 );
263ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          col[2 * pitch] = (FT_Byte)( b / 65536 );
264ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
265ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
266ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
267ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
268ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
269ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* USE_LEGACY */
270ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
271ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
272ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_EXPORT_DEF( FT_Error )
273ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_Library_SetLcdFilterWeights( FT_Library      library,
274ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                  unsigned char  *weights )
275ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
276ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( !library || !weights )
277ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return FT_THROW( Invalid_Argument );
278ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
279ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ft_memcpy( library->lcd_weights, weights, 5 );
280ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
281ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_Err_Ok;
282ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
283ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
284ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
285ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_EXPORT_DEF( FT_Error )
286ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_Library_SetLcdFilter( FT_Library    library,
287ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                           FT_LcdFilter  filter )
288ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
289ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    static const FT_Byte  light_filter[5] =
290ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            { 0x00, 0x55, 0x56, 0x55, 0x00 };
291ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* the values here sum up to a value larger than 256, */
292ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* providing a cheap gamma correction                 */
293ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    static const FT_Byte  default_filter[5] =
294ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            { 0x10, 0x40, 0x70, 0x40, 0x10 };
295ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
296ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
297ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( !library )
298ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return FT_THROW( Invalid_Argument );
299ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
300ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    switch ( filter )
301ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
302ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    case FT_LCD_FILTER_NONE:
303ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      library->lcd_filter_func = NULL;
304ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      library->lcd_extra       = 0;
305ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      break;
306ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
307ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    case FT_LCD_FILTER_DEFAULT:
308ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#if defined( FT_FORCE_LEGACY_LCD_FILTER )
309ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
310ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      library->lcd_filter_func = _ft_lcd_filter_legacy;
311ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      library->lcd_extra       = 0;
312ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
313ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#elif defined( FT_FORCE_LIGHT_LCD_FILTER )
314ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
315ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      ft_memcpy( library->lcd_weights, light_filter, 5 );
316ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      library->lcd_filter_func = _ft_lcd_filter_fir;
317ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      library->lcd_extra       = 2;
318ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
319ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#else
320ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
321ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      ft_memcpy( library->lcd_weights, default_filter, 5 );
322ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      library->lcd_filter_func = _ft_lcd_filter_fir;
323ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      library->lcd_extra       = 2;
324ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
325ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif
326ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
327ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      break;
328ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
329ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    case FT_LCD_FILTER_LIGHT:
330ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      ft_memcpy( library->lcd_weights, light_filter, 5 );
331ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      library->lcd_filter_func = _ft_lcd_filter_fir;
332ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      library->lcd_extra       = 2;
333ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      break;
334ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
335ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef USE_LEGACY
336ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
337ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    case FT_LCD_FILTER_LEGACY:
338ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      library->lcd_filter_func = _ft_lcd_filter_legacy;
339ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      library->lcd_extra       = 0;
340ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      break;
341ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
342ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif
343ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
344ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    default:
345ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return FT_THROW( Invalid_Argument );
346ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
347ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
348ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    library->lcd_filter = filter;
349ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
350ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_Err_Ok;
351ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
352ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
353ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
354ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
355ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_EXPORT_DEF( FT_Error )
356ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_Library_SetLcdFilterWeights( FT_Library      library,
357ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                  unsigned char  *weights )
358ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
359ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UNUSED( library );
360ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UNUSED( weights );
361ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
362ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_THROW( Unimplemented_Feature );
363ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
364ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
365ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
366ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_EXPORT_DEF( FT_Error )
367ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_Library_SetLcdFilter( FT_Library    library,
368ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                           FT_LcdFilter  filter )
369ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
370ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UNUSED( library );
371ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UNUSED( filter );
372ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
373ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_THROW( Unimplemented_Feature );
374ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
375ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
376ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
377ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
378ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
379ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* END */
380ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif
381ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
382