xref: /inferno-os/libfreetype/ttsbit.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1*37da2899SCharles.Forsyth /***************************************************************************/
2*37da2899SCharles.Forsyth /*                                                                         */
3*37da2899SCharles.Forsyth /*  ttsbit.c                                                               */
4*37da2899SCharles.Forsyth /*                                                                         */
5*37da2899SCharles.Forsyth /*    TrueType and OpenType embedded bitmap support (body).                */
6*37da2899SCharles.Forsyth /*                                                                         */
7*37da2899SCharles.Forsyth /*  Copyright 1996-2001, 2002 by                                           */
8*37da2899SCharles.Forsyth /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
9*37da2899SCharles.Forsyth /*                                                                         */
10*37da2899SCharles.Forsyth /*  This file is part of the FreeType project, and may only be used,       */
11*37da2899SCharles.Forsyth /*  modified, and distributed under the terms of the FreeType project      */
12*37da2899SCharles.Forsyth /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
13*37da2899SCharles.Forsyth /*  this file you indicate that you have read the license and              */
14*37da2899SCharles.Forsyth /*  understand and accept it fully.                                        */
15*37da2899SCharles.Forsyth /*                                                                         */
16*37da2899SCharles.Forsyth /***************************************************************************/
17*37da2899SCharles.Forsyth 
18*37da2899SCharles.Forsyth 
19*37da2899SCharles.Forsyth #include <ft2build.h>
20*37da2899SCharles.Forsyth #include FT_INTERNAL_DEBUG_H
21*37da2899SCharles.Forsyth #include FT_INTERNAL_STREAM_H
22*37da2899SCharles.Forsyth #include FT_TRUETYPE_TAGS_H
23*37da2899SCharles.Forsyth #include "ttsbit.h"
24*37da2899SCharles.Forsyth 
25*37da2899SCharles.Forsyth #include "sferrors.h"
26*37da2899SCharles.Forsyth 
27*37da2899SCharles.Forsyth 
28*37da2899SCharles.Forsyth   /*************************************************************************/
29*37da2899SCharles.Forsyth   /*                                                                       */
30*37da2899SCharles.Forsyth   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
31*37da2899SCharles.Forsyth   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
32*37da2899SCharles.Forsyth   /* messages during execution.                                            */
33*37da2899SCharles.Forsyth   /*                                                                       */
34*37da2899SCharles.Forsyth #undef  FT_COMPONENT
35*37da2899SCharles.Forsyth #define FT_COMPONENT  trace_ttsbit
36*37da2899SCharles.Forsyth 
37*37da2899SCharles.Forsyth 
38*37da2899SCharles.Forsyth   /*************************************************************************/
39*37da2899SCharles.Forsyth   /*                                                                       */
40*37da2899SCharles.Forsyth   /* <Function>                                                            */
41*37da2899SCharles.Forsyth   /*    blit_sbit                                                          */
42*37da2899SCharles.Forsyth   /*                                                                       */
43*37da2899SCharles.Forsyth   /* <Description>                                                         */
44*37da2899SCharles.Forsyth   /*    Blits a bitmap from an input stream into a given target.  Supports */
45*37da2899SCharles.Forsyth   /*    x and y offsets as well as byte padded lines.                      */
46*37da2899SCharles.Forsyth   /*                                                                       */
47*37da2899SCharles.Forsyth   /* <Input>                                                               */
48*37da2899SCharles.Forsyth   /*    target      :: The target bitmap/pixmap.                           */
49*37da2899SCharles.Forsyth   /*                                                                       */
50*37da2899SCharles.Forsyth   /*    source      :: The input packed bitmap data.                       */
51*37da2899SCharles.Forsyth   /*                                                                       */
52*37da2899SCharles.Forsyth   /*    line_bits   :: The number of bits per line.                        */
53*37da2899SCharles.Forsyth   /*                                                                       */
54*37da2899SCharles.Forsyth   /*    byte_padded :: A flag which is true if lines are byte-padded.      */
55*37da2899SCharles.Forsyth   /*                                                                       */
56*37da2899SCharles.Forsyth   /*    x_offset    :: The horizontal offset.                              */
57*37da2899SCharles.Forsyth   /*                                                                       */
58*37da2899SCharles.Forsyth   /*    y_offset    :: The vertical offset.                                */
59*37da2899SCharles.Forsyth   /*                                                                       */
60*37da2899SCharles.Forsyth   /* <Note>                                                                */
61*37da2899SCharles.Forsyth   /*    IMPORTANT: The x and y offsets are relative to the top corner of   */
62*37da2899SCharles.Forsyth   /*               the target bitmap (unlike the normal TrueType           */
63*37da2899SCharles.Forsyth   /*               convention).  A positive y offset indicates a downwards */
64*37da2899SCharles.Forsyth   /*               direction!                                              */
65*37da2899SCharles.Forsyth   /*                                                                       */
66*37da2899SCharles.Forsyth   static void
blit_sbit(FT_Bitmap * target,FT_Byte * source,FT_Int line_bits,FT_Bool byte_padded,FT_Int x_offset,FT_Int y_offset)67*37da2899SCharles.Forsyth   blit_sbit( FT_Bitmap*  target,
68*37da2899SCharles.Forsyth              FT_Byte*    source,
69*37da2899SCharles.Forsyth              FT_Int      line_bits,
70*37da2899SCharles.Forsyth              FT_Bool     byte_padded,
71*37da2899SCharles.Forsyth              FT_Int      x_offset,
72*37da2899SCharles.Forsyth              FT_Int      y_offset )
73*37da2899SCharles.Forsyth   {
74*37da2899SCharles.Forsyth     FT_Byte*   line_buff;
75*37da2899SCharles.Forsyth     FT_Int     line_incr;
76*37da2899SCharles.Forsyth     FT_Int     height;
77*37da2899SCharles.Forsyth 
78*37da2899SCharles.Forsyth     FT_UShort  acc;
79*37da2899SCharles.Forsyth     FT_UInt    loaded;
80*37da2899SCharles.Forsyth 
81*37da2899SCharles.Forsyth 
82*37da2899SCharles.Forsyth     /* first of all, compute starting write position */
83*37da2899SCharles.Forsyth     line_incr = target->pitch;
84*37da2899SCharles.Forsyth     line_buff = target->buffer;
85*37da2899SCharles.Forsyth 
86*37da2899SCharles.Forsyth     if ( line_incr < 0 )
87*37da2899SCharles.Forsyth       line_buff -= line_incr * ( target->rows - 1 );
88*37da2899SCharles.Forsyth 
89*37da2899SCharles.Forsyth     line_buff += ( x_offset >> 3 ) + y_offset * line_incr;
90*37da2899SCharles.Forsyth 
91*37da2899SCharles.Forsyth     /***********************************************************************/
92*37da2899SCharles.Forsyth     /*                                                                     */
93*37da2899SCharles.Forsyth     /* We use the extra-classic `accumulator' trick to extract the bits    */
94*37da2899SCharles.Forsyth     /* from the source byte stream.                                        */
95*37da2899SCharles.Forsyth     /*                                                                     */
96*37da2899SCharles.Forsyth     /* Namely, the variable `acc' is a 16-bit accumulator containing the   */
97*37da2899SCharles.Forsyth     /* last `loaded' bits from the input stream.  The bits are shifted to  */
98*37da2899SCharles.Forsyth     /* the upmost position in `acc'.                                       */
99*37da2899SCharles.Forsyth     /*                                                                     */
100*37da2899SCharles.Forsyth     /***********************************************************************/
101*37da2899SCharles.Forsyth 
102*37da2899SCharles.Forsyth     acc    = 0;  /* clear accumulator   */
103*37da2899SCharles.Forsyth     loaded = 0;  /* no bits were loaded */
104*37da2899SCharles.Forsyth 
105*37da2899SCharles.Forsyth     for ( height = target->rows; height > 0; height-- )
106*37da2899SCharles.Forsyth     {
107*37da2899SCharles.Forsyth       FT_Byte*  cur   = line_buff;        /* current write cursor          */
108*37da2899SCharles.Forsyth       FT_Int    count = line_bits;        /* # of bits to extract per line */
109*37da2899SCharles.Forsyth       FT_Byte   shift = (FT_Byte)( x_offset & 7 ); /* current write shift  */
110*37da2899SCharles.Forsyth       FT_Byte   space = (FT_Byte)( 8 - shift );
111*37da2899SCharles.Forsyth 
112*37da2899SCharles.Forsyth 
113*37da2899SCharles.Forsyth       /* first of all, read individual source bytes */
114*37da2899SCharles.Forsyth       if ( count >= 8 )
115*37da2899SCharles.Forsyth       {
116*37da2899SCharles.Forsyth         count -= 8;
117*37da2899SCharles.Forsyth         {
118*37da2899SCharles.Forsyth           do
119*37da2899SCharles.Forsyth           {
120*37da2899SCharles.Forsyth             FT_Byte  val;
121*37da2899SCharles.Forsyth 
122*37da2899SCharles.Forsyth 
123*37da2899SCharles.Forsyth             /* ensure that there are at least 8 bits in the accumulator */
124*37da2899SCharles.Forsyth             if ( loaded < 8 )
125*37da2899SCharles.Forsyth             {
126*37da2899SCharles.Forsyth               acc    |= (FT_UShort)((FT_UShort)*source++ << ( 8 - loaded ));
127*37da2899SCharles.Forsyth               loaded += 8;
128*37da2899SCharles.Forsyth             }
129*37da2899SCharles.Forsyth 
130*37da2899SCharles.Forsyth             /* now write one byte */
131*37da2899SCharles.Forsyth             val = (FT_Byte)( acc >> 8 );
132*37da2899SCharles.Forsyth             if ( shift )
133*37da2899SCharles.Forsyth             {
134*37da2899SCharles.Forsyth               cur[0] |= (FT_Byte)( val >> shift );
135*37da2899SCharles.Forsyth               cur[1] |= (FT_Byte)( val << space );
136*37da2899SCharles.Forsyth             }
137*37da2899SCharles.Forsyth             else
138*37da2899SCharles.Forsyth               cur[0] |= val;
139*37da2899SCharles.Forsyth 
140*37da2899SCharles.Forsyth             cur++;
141*37da2899SCharles.Forsyth             acc   <<= 8;  /* remove bits from accumulator */
142*37da2899SCharles.Forsyth             loaded -= 8;
143*37da2899SCharles.Forsyth             count  -= 8;
144*37da2899SCharles.Forsyth 
145*37da2899SCharles.Forsyth           } while ( count >= 0 );
146*37da2899SCharles.Forsyth         }
147*37da2899SCharles.Forsyth 
148*37da2899SCharles.Forsyth         /* restore `count' to correct value */
149*37da2899SCharles.Forsyth         count += 8;
150*37da2899SCharles.Forsyth       }
151*37da2899SCharles.Forsyth 
152*37da2899SCharles.Forsyth       /* now write remaining bits (count < 8) */
153*37da2899SCharles.Forsyth       if ( count > 0 )
154*37da2899SCharles.Forsyth       {
155*37da2899SCharles.Forsyth         FT_Byte  val;
156*37da2899SCharles.Forsyth 
157*37da2899SCharles.Forsyth 
158*37da2899SCharles.Forsyth         /* ensure that there are at least `count' bits in the accumulator */
159*37da2899SCharles.Forsyth         if ( (FT_Int)loaded < count )
160*37da2899SCharles.Forsyth         {
161*37da2899SCharles.Forsyth           acc    |= (FT_UShort)((FT_UShort)*source++ << ( 8 - loaded ));
162*37da2899SCharles.Forsyth           loaded += 8;
163*37da2899SCharles.Forsyth         }
164*37da2899SCharles.Forsyth 
165*37da2899SCharles.Forsyth         /* now write remaining bits */
166*37da2899SCharles.Forsyth         val     = (FT_Byte)( ( (FT_Byte)( acc >> 8 ) ) & ~( 0xFF >> count ) );
167*37da2899SCharles.Forsyth         cur[0] |= (FT_Byte)( val >> shift );
168*37da2899SCharles.Forsyth 
169*37da2899SCharles.Forsyth         if ( count > space )
170*37da2899SCharles.Forsyth           cur[1] |= (FT_Byte)( val << space );
171*37da2899SCharles.Forsyth 
172*37da2899SCharles.Forsyth         acc   <<= count;
173*37da2899SCharles.Forsyth         loaded -= count;
174*37da2899SCharles.Forsyth       }
175*37da2899SCharles.Forsyth 
176*37da2899SCharles.Forsyth       /* now, skip to next line */
177*37da2899SCharles.Forsyth       if ( byte_padded )
178*37da2899SCharles.Forsyth       {
179*37da2899SCharles.Forsyth         acc    = 0;
180*37da2899SCharles.Forsyth         loaded = 0;   /* clear accumulator on byte-padded lines */
181*37da2899SCharles.Forsyth       }
182*37da2899SCharles.Forsyth 
183*37da2899SCharles.Forsyth       line_buff += line_incr;
184*37da2899SCharles.Forsyth     }
185*37da2899SCharles.Forsyth   }
186*37da2899SCharles.Forsyth 
187*37da2899SCharles.Forsyth 
188*37da2899SCharles.Forsyth   const FT_Frame_Field  sbit_metrics_fields[] =
189*37da2899SCharles.Forsyth   {
190*37da2899SCharles.Forsyth #undef  FT_STRUCTURE
191*37da2899SCharles.Forsyth #define FT_STRUCTURE  TT_SBit_MetricsRec
192*37da2899SCharles.Forsyth 
193*37da2899SCharles.Forsyth     FT_FRAME_START( 8 ),
194*37da2899SCharles.Forsyth       FT_FRAME_BYTE( height ),
195*37da2899SCharles.Forsyth       FT_FRAME_BYTE( width ),
196*37da2899SCharles.Forsyth 
197*37da2899SCharles.Forsyth       FT_FRAME_CHAR( horiBearingX ),
198*37da2899SCharles.Forsyth       FT_FRAME_CHAR( horiBearingY ),
199*37da2899SCharles.Forsyth       FT_FRAME_BYTE( horiAdvance ),
200*37da2899SCharles.Forsyth 
201*37da2899SCharles.Forsyth       FT_FRAME_CHAR( vertBearingX ),
202*37da2899SCharles.Forsyth       FT_FRAME_CHAR( vertBearingY ),
203*37da2899SCharles.Forsyth       FT_FRAME_BYTE( vertAdvance ),
204*37da2899SCharles.Forsyth     FT_FRAME_END
205*37da2899SCharles.Forsyth   };
206*37da2899SCharles.Forsyth 
207*37da2899SCharles.Forsyth 
208*37da2899SCharles.Forsyth   /*************************************************************************/
209*37da2899SCharles.Forsyth   /*                                                                       */
210*37da2899SCharles.Forsyth   /* <Function>                                                            */
211*37da2899SCharles.Forsyth   /*    TT_Load_SBit_Const_Metrics                                         */
212*37da2899SCharles.Forsyth   /*                                                                       */
213*37da2899SCharles.Forsyth   /* <Description>                                                         */
214*37da2899SCharles.Forsyth   /*    Loads the metrics for `EBLC' index tables format 2 and 5.          */
215*37da2899SCharles.Forsyth   /*                                                                       */
216*37da2899SCharles.Forsyth   /* <Input>                                                               */
217*37da2899SCharles.Forsyth   /*    range  :: The target range.                                        */
218*37da2899SCharles.Forsyth   /*                                                                       */
219*37da2899SCharles.Forsyth   /*    stream :: The input stream.                                        */
220*37da2899SCharles.Forsyth   /*                                                                       */
221*37da2899SCharles.Forsyth   /* <Return>                                                              */
222*37da2899SCharles.Forsyth   /*    FreeType error code.  0 means success.                             */
223*37da2899SCharles.Forsyth   /*                                                                       */
224*37da2899SCharles.Forsyth   static FT_Error
Load_SBit_Const_Metrics(TT_SBit_Range range,FT_Stream stream)225*37da2899SCharles.Forsyth   Load_SBit_Const_Metrics( TT_SBit_Range  range,
226*37da2899SCharles.Forsyth                            FT_Stream      stream )
227*37da2899SCharles.Forsyth   {
228*37da2899SCharles.Forsyth     FT_Error  error;
229*37da2899SCharles.Forsyth 
230*37da2899SCharles.Forsyth 
231*37da2899SCharles.Forsyth     if ( FT_READ_ULONG( range->image_size ) )
232*37da2899SCharles.Forsyth       return error;
233*37da2899SCharles.Forsyth 
234*37da2899SCharles.Forsyth     return FT_STREAM_READ_FIELDS( sbit_metrics_fields, &range->metrics );
235*37da2899SCharles.Forsyth   }
236*37da2899SCharles.Forsyth 
237*37da2899SCharles.Forsyth 
238*37da2899SCharles.Forsyth   /*************************************************************************/
239*37da2899SCharles.Forsyth   /*                                                                       */
240*37da2899SCharles.Forsyth   /* <Function>                                                            */
241*37da2899SCharles.Forsyth   /*    TT_Load_SBit_Range_Codes                                           */
242*37da2899SCharles.Forsyth   /*                                                                       */
243*37da2899SCharles.Forsyth   /* <Description>                                                         */
244*37da2899SCharles.Forsyth   /*    Loads the range codes for `EBLC' index tables format 4 and 5.      */
245*37da2899SCharles.Forsyth   /*                                                                       */
246*37da2899SCharles.Forsyth   /* <Input>                                                               */
247*37da2899SCharles.Forsyth   /*    range        :: The target range.                                  */
248*37da2899SCharles.Forsyth   /*                                                                       */
249*37da2899SCharles.Forsyth   /*    stream       :: The input stream.                                  */
250*37da2899SCharles.Forsyth   /*                                                                       */
251*37da2899SCharles.Forsyth   /*    load_offsets :: A flag whether to load the glyph offset table.     */
252*37da2899SCharles.Forsyth   /*                                                                       */
253*37da2899SCharles.Forsyth   /* <Return>                                                              */
254*37da2899SCharles.Forsyth   /*    FreeType error code.  0 means success.                             */
255*37da2899SCharles.Forsyth   /*                                                                       */
256*37da2899SCharles.Forsyth   static FT_Error
Load_SBit_Range_Codes(TT_SBit_Range range,FT_Stream stream,FT_Bool load_offsets)257*37da2899SCharles.Forsyth   Load_SBit_Range_Codes( TT_SBit_Range  range,
258*37da2899SCharles.Forsyth                          FT_Stream      stream,
259*37da2899SCharles.Forsyth                          FT_Bool        load_offsets )
260*37da2899SCharles.Forsyth   {
261*37da2899SCharles.Forsyth     FT_Error   error;
262*37da2899SCharles.Forsyth     FT_ULong   count, n, size;
263*37da2899SCharles.Forsyth     FT_Memory  memory = stream->memory;
264*37da2899SCharles.Forsyth 
265*37da2899SCharles.Forsyth 
266*37da2899SCharles.Forsyth     if ( FT_READ_ULONG( count ) )
267*37da2899SCharles.Forsyth       goto Exit;
268*37da2899SCharles.Forsyth 
269*37da2899SCharles.Forsyth     range->num_glyphs = count;
270*37da2899SCharles.Forsyth 
271*37da2899SCharles.Forsyth     /* Allocate glyph offsets table if needed */
272*37da2899SCharles.Forsyth     if ( load_offsets )
273*37da2899SCharles.Forsyth     {
274*37da2899SCharles.Forsyth       if ( FT_NEW_ARRAY( range->glyph_offsets, count ) )
275*37da2899SCharles.Forsyth         goto Exit;
276*37da2899SCharles.Forsyth 
277*37da2899SCharles.Forsyth       size = count * 4L;
278*37da2899SCharles.Forsyth     }
279*37da2899SCharles.Forsyth     else
280*37da2899SCharles.Forsyth       size = count * 2L;
281*37da2899SCharles.Forsyth 
282*37da2899SCharles.Forsyth     /* Allocate glyph codes table and access frame */
283*37da2899SCharles.Forsyth     if ( FT_NEW_ARRAY ( range->glyph_codes, count ) ||
284*37da2899SCharles.Forsyth          FT_FRAME_ENTER( size )                     )
285*37da2899SCharles.Forsyth       goto Exit;
286*37da2899SCharles.Forsyth 
287*37da2899SCharles.Forsyth     for ( n = 0; n < count; n++ )
288*37da2899SCharles.Forsyth     {
289*37da2899SCharles.Forsyth       range->glyph_codes[n] = FT_GET_USHORT();
290*37da2899SCharles.Forsyth 
291*37da2899SCharles.Forsyth       if ( load_offsets )
292*37da2899SCharles.Forsyth         range->glyph_offsets[n] = (FT_ULong)range->image_offset +
293*37da2899SCharles.Forsyth                                   FT_GET_USHORT();
294*37da2899SCharles.Forsyth     }
295*37da2899SCharles.Forsyth 
296*37da2899SCharles.Forsyth     FT_FRAME_EXIT();
297*37da2899SCharles.Forsyth 
298*37da2899SCharles.Forsyth   Exit:
299*37da2899SCharles.Forsyth     return error;
300*37da2899SCharles.Forsyth   }
301*37da2899SCharles.Forsyth 
302*37da2899SCharles.Forsyth 
303*37da2899SCharles.Forsyth   /*************************************************************************/
304*37da2899SCharles.Forsyth   /*                                                                       */
305*37da2899SCharles.Forsyth   /* <Function>                                                            */
306*37da2899SCharles.Forsyth   /*    TT_Load_SBit_Range                                                 */
307*37da2899SCharles.Forsyth   /*                                                                       */
308*37da2899SCharles.Forsyth   /* <Description>                                                         */
309*37da2899SCharles.Forsyth   /*    Loads a given `EBLC' index/range table.                            */
310*37da2899SCharles.Forsyth   /*                                                                       */
311*37da2899SCharles.Forsyth   /* <Input>                                                               */
312*37da2899SCharles.Forsyth   /*    range  :: The target range.                                        */
313*37da2899SCharles.Forsyth   /*                                                                       */
314*37da2899SCharles.Forsyth   /*    stream :: The input stream.                                        */
315*37da2899SCharles.Forsyth   /*                                                                       */
316*37da2899SCharles.Forsyth   /* <Return>                                                              */
317*37da2899SCharles.Forsyth   /*    FreeType error code.  0 means success.                             */
318*37da2899SCharles.Forsyth   /*                                                                       */
319*37da2899SCharles.Forsyth   static FT_Error
Load_SBit_Range(TT_SBit_Range range,FT_Stream stream)320*37da2899SCharles.Forsyth   Load_SBit_Range( TT_SBit_Range  range,
321*37da2899SCharles.Forsyth                    FT_Stream      stream )
322*37da2899SCharles.Forsyth   {
323*37da2899SCharles.Forsyth     FT_Error   error;
324*37da2899SCharles.Forsyth     FT_Memory  memory = stream->memory;
325*37da2899SCharles.Forsyth 
326*37da2899SCharles.Forsyth 
327*37da2899SCharles.Forsyth     switch( range->index_format )
328*37da2899SCharles.Forsyth     {
329*37da2899SCharles.Forsyth     case 1:   /* variable metrics with 4-byte offsets */
330*37da2899SCharles.Forsyth     case 3:   /* variable metrics with 2-byte offsets */
331*37da2899SCharles.Forsyth       {
332*37da2899SCharles.Forsyth         FT_ULong  num_glyphs, n;
333*37da2899SCharles.Forsyth         FT_Int    size_elem;
334*37da2899SCharles.Forsyth         FT_Bool   large = FT_BOOL( range->index_format == 1 );
335*37da2899SCharles.Forsyth 
336*37da2899SCharles.Forsyth 
337*37da2899SCharles.Forsyth         num_glyphs        = range->last_glyph - range->first_glyph + 1L;
338*37da2899SCharles.Forsyth         range->num_glyphs = num_glyphs;
339*37da2899SCharles.Forsyth         num_glyphs++;                       /* XXX: BEWARE - see spec */
340*37da2899SCharles.Forsyth 
341*37da2899SCharles.Forsyth         size_elem = large ? 4 : 2;
342*37da2899SCharles.Forsyth 
343*37da2899SCharles.Forsyth         if ( FT_NEW_ARRAY( range->glyph_offsets, num_glyphs ) ||
344*37da2899SCharles.Forsyth              FT_FRAME_ENTER( num_glyphs * size_elem )         )
345*37da2899SCharles.Forsyth           goto Exit;
346*37da2899SCharles.Forsyth 
347*37da2899SCharles.Forsyth         for ( n = 0; n < num_glyphs; n++ )
348*37da2899SCharles.Forsyth           range->glyph_offsets[n] = (FT_ULong)( range->image_offset +
349*37da2899SCharles.Forsyth                                                 ( large ? FT_GET_ULONG()
350*37da2899SCharles.Forsyth                                                         : FT_GET_USHORT() ) );
351*37da2899SCharles.Forsyth         FT_FRAME_EXIT();
352*37da2899SCharles.Forsyth       }
353*37da2899SCharles.Forsyth       break;
354*37da2899SCharles.Forsyth 
355*37da2899SCharles.Forsyth     case 2:   /* all glyphs have identical metrics */
356*37da2899SCharles.Forsyth       error = Load_SBit_Const_Metrics( range, stream );
357*37da2899SCharles.Forsyth       break;
358*37da2899SCharles.Forsyth 
359*37da2899SCharles.Forsyth     case 4:
360*37da2899SCharles.Forsyth       error = Load_SBit_Range_Codes( range, stream, 1 );
361*37da2899SCharles.Forsyth       break;
362*37da2899SCharles.Forsyth 
363*37da2899SCharles.Forsyth     case 5:
364*37da2899SCharles.Forsyth       error = Load_SBit_Const_Metrics( range, stream )   ||
365*37da2899SCharles.Forsyth               Load_SBit_Range_Codes( range, stream, 0 );
366*37da2899SCharles.Forsyth       break;
367*37da2899SCharles.Forsyth 
368*37da2899SCharles.Forsyth     default:
369*37da2899SCharles.Forsyth       error = SFNT_Err_Invalid_File_Format;
370*37da2899SCharles.Forsyth     }
371*37da2899SCharles.Forsyth 
372*37da2899SCharles.Forsyth   Exit:
373*37da2899SCharles.Forsyth     return error;
374*37da2899SCharles.Forsyth   }
375*37da2899SCharles.Forsyth 
376*37da2899SCharles.Forsyth 
377*37da2899SCharles.Forsyth   /*************************************************************************/
378*37da2899SCharles.Forsyth   /*                                                                       */
379*37da2899SCharles.Forsyth   /* <Function>                                                            */
380*37da2899SCharles.Forsyth   /*    tt_face_load_sbit_strikes                                          */
381*37da2899SCharles.Forsyth   /*                                                                       */
382*37da2899SCharles.Forsyth   /* <Description>                                                         */
383*37da2899SCharles.Forsyth   /*    Loads the table of embedded bitmap sizes for this face.            */
384*37da2899SCharles.Forsyth   /*                                                                       */
385*37da2899SCharles.Forsyth   /* <Input>                                                               */
386*37da2899SCharles.Forsyth   /*    face   :: The target face object.                                  */
387*37da2899SCharles.Forsyth   /*                                                                       */
388*37da2899SCharles.Forsyth   /*    stream :: The input stream.                                        */
389*37da2899SCharles.Forsyth   /*                                                                       */
390*37da2899SCharles.Forsyth   /* <Return>                                                              */
391*37da2899SCharles.Forsyth   /*    FreeType error code.  0 means success.                             */
392*37da2899SCharles.Forsyth   /*                                                                       */
393*37da2899SCharles.Forsyth   FT_LOCAL_DEF( FT_Error )
tt_face_load_sbit_strikes(TT_Face face,FT_Stream stream)394*37da2899SCharles.Forsyth   tt_face_load_sbit_strikes( TT_Face    face,
395*37da2899SCharles.Forsyth                              FT_Stream  stream )
396*37da2899SCharles.Forsyth   {
397*37da2899SCharles.Forsyth     FT_Error   error  = 0;
398*37da2899SCharles.Forsyth     FT_Memory  memory = stream->memory;
399*37da2899SCharles.Forsyth     FT_Fixed   version;
400*37da2899SCharles.Forsyth     FT_ULong   num_strikes;
401*37da2899SCharles.Forsyth     FT_ULong   table_base;
402*37da2899SCharles.Forsyth 
403*37da2899SCharles.Forsyth     const FT_Frame_Field  sbit_line_metrics_fields[] =
404*37da2899SCharles.Forsyth     {
405*37da2899SCharles.Forsyth #undef  FT_STRUCTURE
406*37da2899SCharles.Forsyth #define FT_STRUCTURE  TT_SBit_LineMetricsRec
407*37da2899SCharles.Forsyth 
408*37da2899SCharles.Forsyth       /* no FT_FRAME_START */
409*37da2899SCharles.Forsyth         FT_FRAME_CHAR( ascender ),
410*37da2899SCharles.Forsyth         FT_FRAME_CHAR( descender ),
411*37da2899SCharles.Forsyth         FT_FRAME_BYTE( max_width ),
412*37da2899SCharles.Forsyth 
413*37da2899SCharles.Forsyth         FT_FRAME_CHAR( caret_slope_numerator ),
414*37da2899SCharles.Forsyth         FT_FRAME_CHAR( caret_slope_denominator ),
415*37da2899SCharles.Forsyth         FT_FRAME_CHAR( caret_offset ),
416*37da2899SCharles.Forsyth 
417*37da2899SCharles.Forsyth         FT_FRAME_CHAR( min_origin_SB ),
418*37da2899SCharles.Forsyth         FT_FRAME_CHAR( min_advance_SB ),
419*37da2899SCharles.Forsyth         FT_FRAME_CHAR( max_before_BL ),
420*37da2899SCharles.Forsyth         FT_FRAME_CHAR( min_after_BL ),
421*37da2899SCharles.Forsyth         FT_FRAME_CHAR( pads[0] ),
422*37da2899SCharles.Forsyth         FT_FRAME_CHAR( pads[1] ),
423*37da2899SCharles.Forsyth       FT_FRAME_END
424*37da2899SCharles.Forsyth     };
425*37da2899SCharles.Forsyth 
426*37da2899SCharles.Forsyth     const FT_Frame_Field  strike_start_fields[] =
427*37da2899SCharles.Forsyth     {
428*37da2899SCharles.Forsyth #undef  FT_STRUCTURE
429*37da2899SCharles.Forsyth #define FT_STRUCTURE  TT_SBit_StrikeRec
430*37da2899SCharles.Forsyth 
431*37da2899SCharles.Forsyth       /* no FT_FRAME_START */
432*37da2899SCharles.Forsyth         FT_FRAME_ULONG( ranges_offset ),
433*37da2899SCharles.Forsyth         FT_FRAME_SKIP_LONG,
434*37da2899SCharles.Forsyth         FT_FRAME_ULONG( num_ranges ),
435*37da2899SCharles.Forsyth         FT_FRAME_ULONG( color_ref ),
436*37da2899SCharles.Forsyth       FT_FRAME_END
437*37da2899SCharles.Forsyth     };
438*37da2899SCharles.Forsyth 
439*37da2899SCharles.Forsyth     const FT_Frame_Field  strike_end_fields[] =
440*37da2899SCharles.Forsyth     {
441*37da2899SCharles.Forsyth       /* no FT_FRAME_START */
442*37da2899SCharles.Forsyth         FT_FRAME_USHORT( start_glyph ),
443*37da2899SCharles.Forsyth         FT_FRAME_USHORT( end_glyph ),
444*37da2899SCharles.Forsyth         FT_FRAME_BYTE  ( x_ppem ),
445*37da2899SCharles.Forsyth         FT_FRAME_BYTE  ( y_ppem ),
446*37da2899SCharles.Forsyth         FT_FRAME_BYTE  ( bit_depth ),
447*37da2899SCharles.Forsyth         FT_FRAME_CHAR  ( flags ),
448*37da2899SCharles.Forsyth       FT_FRAME_END
449*37da2899SCharles.Forsyth     };
450*37da2899SCharles.Forsyth 
451*37da2899SCharles.Forsyth 
452*37da2899SCharles.Forsyth     face->num_sbit_strikes = 0;
453*37da2899SCharles.Forsyth 
454*37da2899SCharles.Forsyth     /* this table is optional */
455*37da2899SCharles.Forsyth     error = face->goto_table( face, TTAG_EBLC, stream, 0 );
456*37da2899SCharles.Forsyth     if ( error )
457*37da2899SCharles.Forsyth       error = face->goto_table( face, TTAG_bloc, stream, 0 );
458*37da2899SCharles.Forsyth     if ( error )
459*37da2899SCharles.Forsyth       goto Exit;
460*37da2899SCharles.Forsyth 
461*37da2899SCharles.Forsyth     table_base = FT_STREAM_POS();
462*37da2899SCharles.Forsyth     if ( FT_FRAME_ENTER( 8L ) )
463*37da2899SCharles.Forsyth       goto Exit;
464*37da2899SCharles.Forsyth 
465*37da2899SCharles.Forsyth     version     = FT_GET_LONG();
466*37da2899SCharles.Forsyth     num_strikes = FT_GET_ULONG();
467*37da2899SCharles.Forsyth 
468*37da2899SCharles.Forsyth     FT_FRAME_EXIT();
469*37da2899SCharles.Forsyth 
470*37da2899SCharles.Forsyth     /* check version number and strike count */
471*37da2899SCharles.Forsyth     if ( version     != 0x00020000L ||
472*37da2899SCharles.Forsyth          num_strikes >= 0x10000L    )
473*37da2899SCharles.Forsyth     {
474*37da2899SCharles.Forsyth       FT_ERROR(( "tt_face_load_sbit_strikes: invalid table version!\n" ));
475*37da2899SCharles.Forsyth       error = SFNT_Err_Invalid_File_Format;
476*37da2899SCharles.Forsyth 
477*37da2899SCharles.Forsyth       goto Exit;
478*37da2899SCharles.Forsyth     }
479*37da2899SCharles.Forsyth 
480*37da2899SCharles.Forsyth     /* allocate the strikes table */
481*37da2899SCharles.Forsyth     if ( FT_NEW_ARRAY( face->sbit_strikes, num_strikes ) )
482*37da2899SCharles.Forsyth       goto Exit;
483*37da2899SCharles.Forsyth 
484*37da2899SCharles.Forsyth     face->num_sbit_strikes = num_strikes;
485*37da2899SCharles.Forsyth 
486*37da2899SCharles.Forsyth     /* now read each strike table separately */
487*37da2899SCharles.Forsyth     {
488*37da2899SCharles.Forsyth       TT_SBit_Strike  strike = face->sbit_strikes;
489*37da2899SCharles.Forsyth       FT_ULong        count  = num_strikes;
490*37da2899SCharles.Forsyth 
491*37da2899SCharles.Forsyth 
492*37da2899SCharles.Forsyth       if ( FT_FRAME_ENTER( 48L * num_strikes ) )
493*37da2899SCharles.Forsyth         goto Exit;
494*37da2899SCharles.Forsyth 
495*37da2899SCharles.Forsyth       while ( count > 0 )
496*37da2899SCharles.Forsyth       {
497*37da2899SCharles.Forsyth         if ( FT_STREAM_READ_FIELDS( strike_start_fields, strike )             ||
498*37da2899SCharles.Forsyth              FT_STREAM_READ_FIELDS( sbit_line_metrics_fields, &strike->hori ) ||
499*37da2899SCharles.Forsyth              FT_STREAM_READ_FIELDS( sbit_line_metrics_fields, &strike->vert ) ||
500*37da2899SCharles.Forsyth              FT_STREAM_READ_FIELDS( strike_end_fields, strike )               )
501*37da2899SCharles.Forsyth           break;
502*37da2899SCharles.Forsyth 
503*37da2899SCharles.Forsyth         count--;
504*37da2899SCharles.Forsyth         strike++;
505*37da2899SCharles.Forsyth       }
506*37da2899SCharles.Forsyth 
507*37da2899SCharles.Forsyth       FT_FRAME_EXIT();
508*37da2899SCharles.Forsyth     }
509*37da2899SCharles.Forsyth 
510*37da2899SCharles.Forsyth     /* allocate the index ranges for each strike table */
511*37da2899SCharles.Forsyth     {
512*37da2899SCharles.Forsyth       TT_SBit_Strike  strike = face->sbit_strikes;
513*37da2899SCharles.Forsyth       FT_ULong        count  = num_strikes;
514*37da2899SCharles.Forsyth 
515*37da2899SCharles.Forsyth 
516*37da2899SCharles.Forsyth       while ( count > 0 )
517*37da2899SCharles.Forsyth       {
518*37da2899SCharles.Forsyth         TT_SBit_Range  range;
519*37da2899SCharles.Forsyth         FT_ULong       count2 = strike->num_ranges;
520*37da2899SCharles.Forsyth 
521*37da2899SCharles.Forsyth 
522*37da2899SCharles.Forsyth         if ( FT_NEW_ARRAY( strike->sbit_ranges, strike->num_ranges ) )
523*37da2899SCharles.Forsyth           goto Exit;
524*37da2899SCharles.Forsyth 
525*37da2899SCharles.Forsyth         /* read each range */
526*37da2899SCharles.Forsyth         if ( FT_STREAM_SEEK( table_base + strike->ranges_offset ) ||
527*37da2899SCharles.Forsyth              FT_FRAME_ENTER( strike->num_ranges * 8L )            )
528*37da2899SCharles.Forsyth           goto Exit;
529*37da2899SCharles.Forsyth 
530*37da2899SCharles.Forsyth         range = strike->sbit_ranges;
531*37da2899SCharles.Forsyth         while ( count2 > 0 )
532*37da2899SCharles.Forsyth         {
533*37da2899SCharles.Forsyth           range->first_glyph  = FT_GET_USHORT();
534*37da2899SCharles.Forsyth           range->last_glyph   = FT_GET_USHORT();
535*37da2899SCharles.Forsyth           range->table_offset = table_base + strike->ranges_offset +
536*37da2899SCharles.Forsyth                                   FT_GET_ULONG();
537*37da2899SCharles.Forsyth           count2--;
538*37da2899SCharles.Forsyth           range++;
539*37da2899SCharles.Forsyth         }
540*37da2899SCharles.Forsyth 
541*37da2899SCharles.Forsyth         FT_FRAME_EXIT();
542*37da2899SCharles.Forsyth 
543*37da2899SCharles.Forsyth         /* Now, read each index table */
544*37da2899SCharles.Forsyth         count2 = strike->num_ranges;
545*37da2899SCharles.Forsyth         range  = strike->sbit_ranges;
546*37da2899SCharles.Forsyth         while ( count2 > 0 )
547*37da2899SCharles.Forsyth         {
548*37da2899SCharles.Forsyth           /* Read the header */
549*37da2899SCharles.Forsyth           if ( FT_STREAM_SEEK( range->table_offset ) ||
550*37da2899SCharles.Forsyth                FT_FRAME_ENTER( 8L )                  )
551*37da2899SCharles.Forsyth             goto Exit;
552*37da2899SCharles.Forsyth 
553*37da2899SCharles.Forsyth           range->index_format = FT_GET_USHORT();
554*37da2899SCharles.Forsyth           range->image_format = FT_GET_USHORT();
555*37da2899SCharles.Forsyth           range->image_offset = FT_GET_ULONG();
556*37da2899SCharles.Forsyth 
557*37da2899SCharles.Forsyth           FT_FRAME_EXIT();
558*37da2899SCharles.Forsyth 
559*37da2899SCharles.Forsyth           error = Load_SBit_Range( range, stream );
560*37da2899SCharles.Forsyth           if ( error )
561*37da2899SCharles.Forsyth             goto Exit;
562*37da2899SCharles.Forsyth 
563*37da2899SCharles.Forsyth           count2--;
564*37da2899SCharles.Forsyth           range++;
565*37da2899SCharles.Forsyth         }
566*37da2899SCharles.Forsyth 
567*37da2899SCharles.Forsyth         count--;
568*37da2899SCharles.Forsyth         strike++;
569*37da2899SCharles.Forsyth       }
570*37da2899SCharles.Forsyth     }
571*37da2899SCharles.Forsyth 
572*37da2899SCharles.Forsyth   Exit:
573*37da2899SCharles.Forsyth     return error;
574*37da2899SCharles.Forsyth   }
575*37da2899SCharles.Forsyth 
576*37da2899SCharles.Forsyth 
577*37da2899SCharles.Forsyth   /*************************************************************************/
578*37da2899SCharles.Forsyth   /*                                                                       */
579*37da2899SCharles.Forsyth   /* <Function>                                                            */
580*37da2899SCharles.Forsyth   /*    tt_face_free_sbit_strikes                                          */
581*37da2899SCharles.Forsyth   /*                                                                       */
582*37da2899SCharles.Forsyth   /* <Description>                                                         */
583*37da2899SCharles.Forsyth   /*    Releases the embedded bitmap tables.                               */
584*37da2899SCharles.Forsyth   /*                                                                       */
585*37da2899SCharles.Forsyth   /* <Input>                                                               */
586*37da2899SCharles.Forsyth   /*    face :: The target face object.                                    */
587*37da2899SCharles.Forsyth   /*                                                                       */
588*37da2899SCharles.Forsyth   FT_LOCAL_DEF( void )
tt_face_free_sbit_strikes(TT_Face face)589*37da2899SCharles.Forsyth   tt_face_free_sbit_strikes( TT_Face  face )
590*37da2899SCharles.Forsyth   {
591*37da2899SCharles.Forsyth     FT_Memory       memory       = face->root.memory;
592*37da2899SCharles.Forsyth     TT_SBit_Strike  strike       = face->sbit_strikes;
593*37da2899SCharles.Forsyth     TT_SBit_Strike  strike_limit = strike + face->num_sbit_strikes;
594*37da2899SCharles.Forsyth 
595*37da2899SCharles.Forsyth 
596*37da2899SCharles.Forsyth     if ( strike )
597*37da2899SCharles.Forsyth     {
598*37da2899SCharles.Forsyth       for ( ; strike < strike_limit; strike++ )
599*37da2899SCharles.Forsyth       {
600*37da2899SCharles.Forsyth         TT_SBit_Range  range       = strike->sbit_ranges;
601*37da2899SCharles.Forsyth         TT_SBit_Range  range_limit = range + strike->num_ranges;
602*37da2899SCharles.Forsyth 
603*37da2899SCharles.Forsyth 
604*37da2899SCharles.Forsyth         if ( range )
605*37da2899SCharles.Forsyth         {
606*37da2899SCharles.Forsyth           for ( ; range < range_limit; range++ )
607*37da2899SCharles.Forsyth           {
608*37da2899SCharles.Forsyth             /* release the glyph offsets and codes tables */
609*37da2899SCharles.Forsyth             /* where appropriate                          */
610*37da2899SCharles.Forsyth             FT_FREE( range->glyph_offsets );
611*37da2899SCharles.Forsyth             FT_FREE( range->glyph_codes );
612*37da2899SCharles.Forsyth           }
613*37da2899SCharles.Forsyth         }
614*37da2899SCharles.Forsyth         FT_FREE( strike->sbit_ranges );
615*37da2899SCharles.Forsyth         strike->num_ranges = 0;
616*37da2899SCharles.Forsyth       }
617*37da2899SCharles.Forsyth       FT_FREE( face->sbit_strikes );
618*37da2899SCharles.Forsyth     }
619*37da2899SCharles.Forsyth     face->num_sbit_strikes = 0;
620*37da2899SCharles.Forsyth   }
621*37da2899SCharles.Forsyth 
622*37da2899SCharles.Forsyth 
623*37da2899SCharles.Forsyth   FT_LOCAL_DEF( FT_Error )
tt_face_set_sbit_strike(TT_Face face,FT_Int x_ppem,FT_Int y_ppem,FT_ULong * astrike_index)624*37da2899SCharles.Forsyth   tt_face_set_sbit_strike( TT_Face    face,
625*37da2899SCharles.Forsyth                            FT_Int     x_ppem,
626*37da2899SCharles.Forsyth                            FT_Int     y_ppem,
627*37da2899SCharles.Forsyth                            FT_ULong  *astrike_index )
628*37da2899SCharles.Forsyth   {
629*37da2899SCharles.Forsyth     FT_ULong  i;
630*37da2899SCharles.Forsyth 
631*37da2899SCharles.Forsyth 
632*37da2899SCharles.Forsyth     if ( x_ppem < 0 || x_ppem > 255 ||
633*37da2899SCharles.Forsyth          y_ppem < 1 || y_ppem > 255 )
634*37da2899SCharles.Forsyth       return SFNT_Err_Invalid_PPem;
635*37da2899SCharles.Forsyth 
636*37da2899SCharles.Forsyth     for ( i = 0; i < face->num_sbit_strikes; i++ )
637*37da2899SCharles.Forsyth     {
638*37da2899SCharles.Forsyth       if ( ( face->sbit_strikes[i].y_ppem  == y_ppem )    &&
639*37da2899SCharles.Forsyth            ( ( x_ppem == 0 )                            ||
640*37da2899SCharles.Forsyth              ( face->sbit_strikes[i].x_ppem == x_ppem ) ) )
641*37da2899SCharles.Forsyth       {
642*37da2899SCharles.Forsyth         *astrike_index = i;
643*37da2899SCharles.Forsyth         return SFNT_Err_Ok;
644*37da2899SCharles.Forsyth       }
645*37da2899SCharles.Forsyth     }
646*37da2899SCharles.Forsyth 
647*37da2899SCharles.Forsyth     return SFNT_Err_Invalid_PPem;
648*37da2899SCharles.Forsyth   }
649*37da2899SCharles.Forsyth 
650*37da2899SCharles.Forsyth 
651*37da2899SCharles.Forsyth   /*************************************************************************/
652*37da2899SCharles.Forsyth   /*                                                                       */
653*37da2899SCharles.Forsyth   /* <Function>                                                            */
654*37da2899SCharles.Forsyth   /*    find_sbit_range                                                    */
655*37da2899SCharles.Forsyth   /*                                                                       */
656*37da2899SCharles.Forsyth   /* <Description>                                                         */
657*37da2899SCharles.Forsyth   /*    Scans a given strike's ranges and return, for a given glyph        */
658*37da2899SCharles.Forsyth   /*    index, the corresponding sbit range, and `EBDT' offset.            */
659*37da2899SCharles.Forsyth   /*                                                                       */
660*37da2899SCharles.Forsyth   /* <Input>                                                               */
661*37da2899SCharles.Forsyth   /*    glyph_index   :: The glyph index.                                  */
662*37da2899SCharles.Forsyth   /*                                                                       */
663*37da2899SCharles.Forsyth   /*    strike        :: The source/current sbit strike.                   */
664*37da2899SCharles.Forsyth   /*                                                                       */
665*37da2899SCharles.Forsyth   /* <Output>                                                              */
666*37da2899SCharles.Forsyth   /*    arange        :: The sbit range containing the glyph index.        */
667*37da2899SCharles.Forsyth   /*                                                                       */
668*37da2899SCharles.Forsyth   /*    aglyph_offset :: The offset of the glyph data in `EBDT' table.     */
669*37da2899SCharles.Forsyth   /*                                                                       */
670*37da2899SCharles.Forsyth   /* <Return>                                                              */
671*37da2899SCharles.Forsyth   /*    FreeType error code.  0 means the glyph index was found.           */
672*37da2899SCharles.Forsyth   /*                                                                       */
673*37da2899SCharles.Forsyth   static FT_Error
find_sbit_range(FT_UInt glyph_index,TT_SBit_Strike strike,TT_SBit_Range * arange,FT_ULong * aglyph_offset)674*37da2899SCharles.Forsyth   find_sbit_range( FT_UInt          glyph_index,
675*37da2899SCharles.Forsyth                    TT_SBit_Strike   strike,
676*37da2899SCharles.Forsyth                    TT_SBit_Range   *arange,
677*37da2899SCharles.Forsyth                    FT_ULong        *aglyph_offset )
678*37da2899SCharles.Forsyth   {
679*37da2899SCharles.Forsyth     TT_SBit_RangeRec  *range, *range_limit;
680*37da2899SCharles.Forsyth 
681*37da2899SCharles.Forsyth 
682*37da2899SCharles.Forsyth     /* check whether the glyph index is within this strike's */
683*37da2899SCharles.Forsyth     /* glyph range                                           */
684*37da2899SCharles.Forsyth     if ( glyph_index < (FT_UInt)strike->start_glyph ||
685*37da2899SCharles.Forsyth          glyph_index > (FT_UInt)strike->end_glyph   )
686*37da2899SCharles.Forsyth       goto Fail;
687*37da2899SCharles.Forsyth 
688*37da2899SCharles.Forsyth     /* scan all ranges in strike */
689*37da2899SCharles.Forsyth     range       = strike->sbit_ranges;
690*37da2899SCharles.Forsyth     range_limit = range + strike->num_ranges;
691*37da2899SCharles.Forsyth     if ( !range )
692*37da2899SCharles.Forsyth       goto Fail;
693*37da2899SCharles.Forsyth 
694*37da2899SCharles.Forsyth     for ( ; range < range_limit; range++ )
695*37da2899SCharles.Forsyth     {
696*37da2899SCharles.Forsyth       if ( glyph_index >= (FT_UInt)range->first_glyph &&
697*37da2899SCharles.Forsyth            glyph_index <= (FT_UInt)range->last_glyph  )
698*37da2899SCharles.Forsyth       {
699*37da2899SCharles.Forsyth         FT_UShort  delta = (FT_UShort)( glyph_index - range->first_glyph );
700*37da2899SCharles.Forsyth 
701*37da2899SCharles.Forsyth 
702*37da2899SCharles.Forsyth         switch ( range->index_format )
703*37da2899SCharles.Forsyth         {
704*37da2899SCharles.Forsyth         case 1:
705*37da2899SCharles.Forsyth         case 3:
706*37da2899SCharles.Forsyth           *aglyph_offset = range->glyph_offsets[delta];
707*37da2899SCharles.Forsyth           break;
708*37da2899SCharles.Forsyth 
709*37da2899SCharles.Forsyth         case 2:
710*37da2899SCharles.Forsyth           *aglyph_offset = range->image_offset +
711*37da2899SCharles.Forsyth                            range->image_size * delta;
712*37da2899SCharles.Forsyth           break;
713*37da2899SCharles.Forsyth 
714*37da2899SCharles.Forsyth         case 4:
715*37da2899SCharles.Forsyth         case 5:
716*37da2899SCharles.Forsyth           {
717*37da2899SCharles.Forsyth             FT_ULong  n;
718*37da2899SCharles.Forsyth 
719*37da2899SCharles.Forsyth 
720*37da2899SCharles.Forsyth             for ( n = 0; n < range->num_glyphs; n++ )
721*37da2899SCharles.Forsyth             {
722*37da2899SCharles.Forsyth               if ( (FT_UInt)range->glyph_codes[n] == glyph_index )
723*37da2899SCharles.Forsyth               {
724*37da2899SCharles.Forsyth                 if ( range->index_format == 4 )
725*37da2899SCharles.Forsyth                   *aglyph_offset = range->glyph_offsets[n];
726*37da2899SCharles.Forsyth                 else
727*37da2899SCharles.Forsyth                   *aglyph_offset = range->image_offset +
728*37da2899SCharles.Forsyth                                    n * range->image_size;
729*37da2899SCharles.Forsyth                 goto Found;
730*37da2899SCharles.Forsyth               }
731*37da2899SCharles.Forsyth             }
732*37da2899SCharles.Forsyth           }
733*37da2899SCharles.Forsyth 
734*37da2899SCharles.Forsyth         /* fall-through */
735*37da2899SCharles.Forsyth         default:
736*37da2899SCharles.Forsyth           goto Fail;
737*37da2899SCharles.Forsyth         }
738*37da2899SCharles.Forsyth 
739*37da2899SCharles.Forsyth       Found:
740*37da2899SCharles.Forsyth         /* return successfully! */
741*37da2899SCharles.Forsyth         *arange  = range;
742*37da2899SCharles.Forsyth         return 0;
743*37da2899SCharles.Forsyth       }
744*37da2899SCharles.Forsyth     }
745*37da2899SCharles.Forsyth 
746*37da2899SCharles.Forsyth   Fail:
747*37da2899SCharles.Forsyth     *arange        = 0;
748*37da2899SCharles.Forsyth     *aglyph_offset = 0;
749*37da2899SCharles.Forsyth 
750*37da2899SCharles.Forsyth     return SFNT_Err_Invalid_Argument;
751*37da2899SCharles.Forsyth   }
752*37da2899SCharles.Forsyth 
753*37da2899SCharles.Forsyth 
754*37da2899SCharles.Forsyth   /*************************************************************************/
755*37da2899SCharles.Forsyth   /*                                                                       */
756*37da2899SCharles.Forsyth   /* <Function>                                                            */
757*37da2899SCharles.Forsyth   /*    find_sbit_image                                                    */
758*37da2899SCharles.Forsyth   /*                                                                       */
759*37da2899SCharles.Forsyth   /* <Description>                                                         */
760*37da2899SCharles.Forsyth   /*    Checks whether an embedded bitmap (an `sbit') exists for a given   */
761*37da2899SCharles.Forsyth   /*    glyph, at a given strike.                                          */
762*37da2899SCharles.Forsyth   /*                                                                       */
763*37da2899SCharles.Forsyth   /* <Input>                                                               */
764*37da2899SCharles.Forsyth   /*    face          :: The target face object.                           */
765*37da2899SCharles.Forsyth   /*                                                                       */
766*37da2899SCharles.Forsyth   /*    glyph_index   :: The glyph index.                                  */
767*37da2899SCharles.Forsyth   /*                                                                       */
768*37da2899SCharles.Forsyth   /*    strike_index  :: The current strike index.                         */
769*37da2899SCharles.Forsyth   /*                                                                       */
770*37da2899SCharles.Forsyth   /* <Output>                                                              */
771*37da2899SCharles.Forsyth   /*    arange        :: The SBit range containing the glyph index.        */
772*37da2899SCharles.Forsyth   /*                                                                       */
773*37da2899SCharles.Forsyth   /*    astrike       :: The SBit strike containing the glyph index.       */
774*37da2899SCharles.Forsyth   /*                                                                       */
775*37da2899SCharles.Forsyth   /*    aglyph_offset :: The offset of the glyph data in `EBDT' table.     */
776*37da2899SCharles.Forsyth   /*                                                                       */
777*37da2899SCharles.Forsyth   /* <Return>                                                              */
778*37da2899SCharles.Forsyth   /*    FreeType error code.  0 means success.  Returns                    */
779*37da2899SCharles.Forsyth   /*    SFNT_Err_Invalid_Argument if no sbit exists for the requested      */
780*37da2899SCharles.Forsyth   /*    glyph.                                                             */
781*37da2899SCharles.Forsyth   /*                                                                       */
782*37da2899SCharles.Forsyth   static FT_Error
find_sbit_image(TT_Face face,FT_UInt glyph_index,FT_ULong strike_index,TT_SBit_Range * arange,TT_SBit_Strike * astrike,FT_ULong * aglyph_offset)783*37da2899SCharles.Forsyth   find_sbit_image( TT_Face          face,
784*37da2899SCharles.Forsyth                    FT_UInt          glyph_index,
785*37da2899SCharles.Forsyth                    FT_ULong         strike_index,
786*37da2899SCharles.Forsyth                    TT_SBit_Range   *arange,
787*37da2899SCharles.Forsyth                    TT_SBit_Strike  *astrike,
788*37da2899SCharles.Forsyth                    FT_ULong        *aglyph_offset )
789*37da2899SCharles.Forsyth   {
790*37da2899SCharles.Forsyth     FT_Error        error;
791*37da2899SCharles.Forsyth     TT_SBit_Strike  strike;
792*37da2899SCharles.Forsyth 
793*37da2899SCharles.Forsyth 
794*37da2899SCharles.Forsyth     if ( !face->sbit_strikes                        ||
795*37da2899SCharles.Forsyth          ( face->num_sbit_strikes <= strike_index ) )
796*37da2899SCharles.Forsyth       goto Fail;
797*37da2899SCharles.Forsyth 
798*37da2899SCharles.Forsyth     strike = &face->sbit_strikes[strike_index];
799*37da2899SCharles.Forsyth 
800*37da2899SCharles.Forsyth     error = find_sbit_range( glyph_index, strike,
801*37da2899SCharles.Forsyth                              arange, aglyph_offset );
802*37da2899SCharles.Forsyth     if ( error )
803*37da2899SCharles.Forsyth       goto Fail;
804*37da2899SCharles.Forsyth 
805*37da2899SCharles.Forsyth     *astrike = strike;
806*37da2899SCharles.Forsyth 
807*37da2899SCharles.Forsyth     return SFNT_Err_Ok;
808*37da2899SCharles.Forsyth 
809*37da2899SCharles.Forsyth   Fail:
810*37da2899SCharles.Forsyth     /* no embedded bitmap for this glyph in face */
811*37da2899SCharles.Forsyth     *arange        = 0;
812*37da2899SCharles.Forsyth     *astrike       = 0;
813*37da2899SCharles.Forsyth     *aglyph_offset = 0;
814*37da2899SCharles.Forsyth 
815*37da2899SCharles.Forsyth     return SFNT_Err_Invalid_Argument;
816*37da2899SCharles.Forsyth   }
817*37da2899SCharles.Forsyth 
818*37da2899SCharles.Forsyth 
819*37da2899SCharles.Forsyth   /*************************************************************************/
820*37da2899SCharles.Forsyth   /*                                                                       */
821*37da2899SCharles.Forsyth   /* <Function>                                                            */
822*37da2899SCharles.Forsyth   /*    load_sbit_metrics                                                  */
823*37da2899SCharles.Forsyth   /*                                                                       */
824*37da2899SCharles.Forsyth   /* <Description>                                                         */
825*37da2899SCharles.Forsyth   /*    Gets the big metrics for a given SBit.                             */
826*37da2899SCharles.Forsyth   /*                                                                       */
827*37da2899SCharles.Forsyth   /* <Input>                                                               */
828*37da2899SCharles.Forsyth   /*    stream      :: The input stream.                                   */
829*37da2899SCharles.Forsyth   /*                                                                       */
830*37da2899SCharles.Forsyth   /*    range       :: The SBit range containing the glyph.                */
831*37da2899SCharles.Forsyth   /*                                                                       */
832*37da2899SCharles.Forsyth   /* <Output>                                                              */
833*37da2899SCharles.Forsyth   /*    big_metrics :: A big SBit metrics structure for the glyph.         */
834*37da2899SCharles.Forsyth   /*                                                                       */
835*37da2899SCharles.Forsyth   /* <Return>                                                              */
836*37da2899SCharles.Forsyth   /*    FreeType error code.  0 means success.                             */
837*37da2899SCharles.Forsyth   /*                                                                       */
838*37da2899SCharles.Forsyth   /* <Note>                                                                */
839*37da2899SCharles.Forsyth   /*    The stream cursor must be positioned at the glyph's offset within  */
840*37da2899SCharles.Forsyth   /*    the `EBDT' table before the call.                                  */
841*37da2899SCharles.Forsyth   /*                                                                       */
842*37da2899SCharles.Forsyth   /*    If the image format uses variable metrics, the stream cursor is    */
843*37da2899SCharles.Forsyth   /*    positioned just after the metrics header in the `EBDT' table on    */
844*37da2899SCharles.Forsyth   /*    function exit.                                                     */
845*37da2899SCharles.Forsyth   /*                                                                       */
846*37da2899SCharles.Forsyth   static FT_Error
load_sbit_metrics(FT_Stream stream,TT_SBit_Range range,TT_SBit_Metrics metrics)847*37da2899SCharles.Forsyth   load_sbit_metrics( FT_Stream        stream,
848*37da2899SCharles.Forsyth                      TT_SBit_Range    range,
849*37da2899SCharles.Forsyth                      TT_SBit_Metrics  metrics )
850*37da2899SCharles.Forsyth   {
851*37da2899SCharles.Forsyth     FT_Error  error = SFNT_Err_Ok;
852*37da2899SCharles.Forsyth 
853*37da2899SCharles.Forsyth 
854*37da2899SCharles.Forsyth     switch ( range->image_format )
855*37da2899SCharles.Forsyth     {
856*37da2899SCharles.Forsyth     case 1:
857*37da2899SCharles.Forsyth     case 2:
858*37da2899SCharles.Forsyth     case 8:
859*37da2899SCharles.Forsyth       /* variable small metrics */
860*37da2899SCharles.Forsyth       {
861*37da2899SCharles.Forsyth         TT_SBit_SmallMetricsRec  smetrics;
862*37da2899SCharles.Forsyth 
863*37da2899SCharles.Forsyth         const FT_Frame_Field  sbit_small_metrics_fields[] =
864*37da2899SCharles.Forsyth         {
865*37da2899SCharles.Forsyth #undef  FT_STRUCTURE
866*37da2899SCharles.Forsyth #define FT_STRUCTURE  TT_SBit_SmallMetricsRec
867*37da2899SCharles.Forsyth 
868*37da2899SCharles.Forsyth           FT_FRAME_START( 5 ),
869*37da2899SCharles.Forsyth             FT_FRAME_BYTE( height ),
870*37da2899SCharles.Forsyth             FT_FRAME_BYTE( width ),
871*37da2899SCharles.Forsyth             FT_FRAME_CHAR( bearingX ),
872*37da2899SCharles.Forsyth             FT_FRAME_CHAR( bearingY ),
873*37da2899SCharles.Forsyth             FT_FRAME_BYTE( advance ),
874*37da2899SCharles.Forsyth           FT_FRAME_END
875*37da2899SCharles.Forsyth         };
876*37da2899SCharles.Forsyth 
877*37da2899SCharles.Forsyth 
878*37da2899SCharles.Forsyth         /* read small metrics */
879*37da2899SCharles.Forsyth         if ( FT_STREAM_READ_FIELDS( sbit_small_metrics_fields, &smetrics ) )
880*37da2899SCharles.Forsyth           goto Exit;
881*37da2899SCharles.Forsyth 
882*37da2899SCharles.Forsyth         /* convert it to a big metrics */
883*37da2899SCharles.Forsyth         metrics->height       = smetrics.height;
884*37da2899SCharles.Forsyth         metrics->width        = smetrics.width;
885*37da2899SCharles.Forsyth         metrics->horiBearingX = smetrics.bearingX;
886*37da2899SCharles.Forsyth         metrics->horiBearingY = smetrics.bearingY;
887*37da2899SCharles.Forsyth         metrics->horiAdvance  = smetrics.advance;
888*37da2899SCharles.Forsyth 
889*37da2899SCharles.Forsyth         /* these metrics are made up at a higher level when */
890*37da2899SCharles.Forsyth         /* needed.                                          */
891*37da2899SCharles.Forsyth         metrics->vertBearingX = 0;
892*37da2899SCharles.Forsyth         metrics->vertBearingY = 0;
893*37da2899SCharles.Forsyth         metrics->vertAdvance  = 0;
894*37da2899SCharles.Forsyth       }
895*37da2899SCharles.Forsyth       break;
896*37da2899SCharles.Forsyth 
897*37da2899SCharles.Forsyth     case 6:
898*37da2899SCharles.Forsyth     case 7:
899*37da2899SCharles.Forsyth     case 9:
900*37da2899SCharles.Forsyth       /* variable big metrics */
901*37da2899SCharles.Forsyth       if ( FT_STREAM_READ_FIELDS( sbit_metrics_fields, metrics ) )
902*37da2899SCharles.Forsyth         goto Exit;
903*37da2899SCharles.Forsyth       break;
904*37da2899SCharles.Forsyth 
905*37da2899SCharles.Forsyth     case 5:
906*37da2899SCharles.Forsyth     default:  /* constant metrics */
907*37da2899SCharles.Forsyth       if ( range->index_format == 2 || range->index_format == 5 )
908*37da2899SCharles.Forsyth         *metrics = range->metrics;
909*37da2899SCharles.Forsyth       else
910*37da2899SCharles.Forsyth         return SFNT_Err_Invalid_File_Format;
911*37da2899SCharles.Forsyth    }
912*37da2899SCharles.Forsyth 
913*37da2899SCharles.Forsyth   Exit:
914*37da2899SCharles.Forsyth     return error;
915*37da2899SCharles.Forsyth   }
916*37da2899SCharles.Forsyth 
917*37da2899SCharles.Forsyth 
918*37da2899SCharles.Forsyth   /*************************************************************************/
919*37da2899SCharles.Forsyth   /*                                                                       */
920*37da2899SCharles.Forsyth   /* <Function>                                                            */
921*37da2899SCharles.Forsyth   /*    crop_bitmap                                                        */
922*37da2899SCharles.Forsyth   /*                                                                       */
923*37da2899SCharles.Forsyth   /* <Description>                                                         */
924*37da2899SCharles.Forsyth   /*    Crops a bitmap to its tightest bounding box, and adjusts its       */
925*37da2899SCharles.Forsyth   /*    metrics.                                                           */
926*37da2899SCharles.Forsyth   /*                                                                       */
927*37da2899SCharles.Forsyth   /* <InOut>                                                               */
928*37da2899SCharles.Forsyth   /*    map     :: The bitmap.                                             */
929*37da2899SCharles.Forsyth   /*                                                                       */
930*37da2899SCharles.Forsyth   /*    metrics :: The corresponding metrics structure.                    */
931*37da2899SCharles.Forsyth   /*                                                                       */
932*37da2899SCharles.Forsyth   static void
crop_bitmap(FT_Bitmap * map,TT_SBit_Metrics metrics)933*37da2899SCharles.Forsyth   crop_bitmap( FT_Bitmap*       map,
934*37da2899SCharles.Forsyth                TT_SBit_Metrics  metrics )
935*37da2899SCharles.Forsyth   {
936*37da2899SCharles.Forsyth     /***********************************************************************/
937*37da2899SCharles.Forsyth     /*                                                                     */
938*37da2899SCharles.Forsyth     /* In this situation, some bounding boxes of embedded bitmaps are too  */
939*37da2899SCharles.Forsyth     /* large.  We need to crop it to a reasonable size.                    */
940*37da2899SCharles.Forsyth     /*                                                                     */
941*37da2899SCharles.Forsyth     /*      ---------                                                      */
942*37da2899SCharles.Forsyth     /*      |       |                -----                                 */
943*37da2899SCharles.Forsyth     /*      |  ***  |                |***|                                 */
944*37da2899SCharles.Forsyth     /*      |   *   |                | * |                                 */
945*37da2899SCharles.Forsyth     /*      |   *   |    ------>     | * |                                 */
946*37da2899SCharles.Forsyth     /*      |   *   |                | * |                                 */
947*37da2899SCharles.Forsyth     /*      |   *   |                | * |                                 */
948*37da2899SCharles.Forsyth     /*      |  ***  |                |***|                                 */
949*37da2899SCharles.Forsyth     /*      ---------                -----                                 */
950*37da2899SCharles.Forsyth     /*                                                                     */
951*37da2899SCharles.Forsyth     /***********************************************************************/
952*37da2899SCharles.Forsyth 
953*37da2899SCharles.Forsyth     FT_Int    rows, count;
954*37da2899SCharles.Forsyth     FT_Long   line_len;
955*37da2899SCharles.Forsyth     FT_Byte*  line;
956*37da2899SCharles.Forsyth 
957*37da2899SCharles.Forsyth 
958*37da2899SCharles.Forsyth     /***********************************************************************/
959*37da2899SCharles.Forsyth     /*                                                                     */
960*37da2899SCharles.Forsyth     /* first of all, check the top-most lines of the bitmap, and remove    */
961*37da2899SCharles.Forsyth     /* them if they're empty.                                              */
962*37da2899SCharles.Forsyth     /*                                                                     */
963*37da2899SCharles.Forsyth     {
964*37da2899SCharles.Forsyth       line     = (FT_Byte*)map->buffer;
965*37da2899SCharles.Forsyth       rows     = map->rows;
966*37da2899SCharles.Forsyth       line_len = map->pitch;
967*37da2899SCharles.Forsyth 
968*37da2899SCharles.Forsyth 
969*37da2899SCharles.Forsyth       for ( count = 0; count < rows; count++ )
970*37da2899SCharles.Forsyth       {
971*37da2899SCharles.Forsyth         FT_Byte*  cur   = line;
972*37da2899SCharles.Forsyth         FT_Byte*  limit = line + line_len;
973*37da2899SCharles.Forsyth 
974*37da2899SCharles.Forsyth 
975*37da2899SCharles.Forsyth         for ( ; cur < limit; cur++ )
976*37da2899SCharles.Forsyth           if ( cur[0] )
977*37da2899SCharles.Forsyth             goto Found_Top;
978*37da2899SCharles.Forsyth 
979*37da2899SCharles.Forsyth         /* the current line was empty - skip to next one */
980*37da2899SCharles.Forsyth         line  = limit;
981*37da2899SCharles.Forsyth       }
982*37da2899SCharles.Forsyth 
983*37da2899SCharles.Forsyth     Found_Top:
984*37da2899SCharles.Forsyth       /* check that we have at least one filled line */
985*37da2899SCharles.Forsyth       if ( count >= rows )
986*37da2899SCharles.Forsyth         goto Empty_Bitmap;
987*37da2899SCharles.Forsyth 
988*37da2899SCharles.Forsyth       /* now, crop the empty upper lines */
989*37da2899SCharles.Forsyth       if ( count > 0 )
990*37da2899SCharles.Forsyth       {
991*37da2899SCharles.Forsyth         line = (FT_Byte*)map->buffer;
992*37da2899SCharles.Forsyth 
993*37da2899SCharles.Forsyth         FT_MEM_MOVE( line, line + count * line_len,
994*37da2899SCharles.Forsyth                      ( rows - count ) * line_len );
995*37da2899SCharles.Forsyth 
996*37da2899SCharles.Forsyth         metrics->height       = (FT_Byte)( metrics->height - count );
997*37da2899SCharles.Forsyth         metrics->horiBearingY = (FT_Char)( metrics->horiBearingY - count );
998*37da2899SCharles.Forsyth         metrics->vertBearingY = (FT_Char)( metrics->vertBearingY - count );
999*37da2899SCharles.Forsyth 
1000*37da2899SCharles.Forsyth         map->rows -= count;
1001*37da2899SCharles.Forsyth         rows      -= count;
1002*37da2899SCharles.Forsyth       }
1003*37da2899SCharles.Forsyth     }
1004*37da2899SCharles.Forsyth 
1005*37da2899SCharles.Forsyth     /***********************************************************************/
1006*37da2899SCharles.Forsyth     /*                                                                     */
1007*37da2899SCharles.Forsyth     /* second, crop the lower lines                                        */
1008*37da2899SCharles.Forsyth     /*                                                                     */
1009*37da2899SCharles.Forsyth     {
1010*37da2899SCharles.Forsyth       line = (FT_Byte*)map->buffer + ( rows - 1 ) * line_len;
1011*37da2899SCharles.Forsyth 
1012*37da2899SCharles.Forsyth       for ( count = 0; count < rows; count++ )
1013*37da2899SCharles.Forsyth       {
1014*37da2899SCharles.Forsyth         FT_Byte*  cur   = line;
1015*37da2899SCharles.Forsyth         FT_Byte*  limit = line + line_len;
1016*37da2899SCharles.Forsyth 
1017*37da2899SCharles.Forsyth 
1018*37da2899SCharles.Forsyth         for ( ; cur < limit; cur++ )
1019*37da2899SCharles.Forsyth           if ( cur[0] )
1020*37da2899SCharles.Forsyth             goto Found_Bottom;
1021*37da2899SCharles.Forsyth 
1022*37da2899SCharles.Forsyth         /* the current line was empty - skip to previous one */
1023*37da2899SCharles.Forsyth         line -= line_len;
1024*37da2899SCharles.Forsyth       }
1025*37da2899SCharles.Forsyth 
1026*37da2899SCharles.Forsyth     Found_Bottom:
1027*37da2899SCharles.Forsyth       if ( count > 0 )
1028*37da2899SCharles.Forsyth       {
1029*37da2899SCharles.Forsyth         metrics->height  = (FT_Byte)( metrics->height - count );
1030*37da2899SCharles.Forsyth         rows            -= count;
1031*37da2899SCharles.Forsyth         map->rows       -= count;
1032*37da2899SCharles.Forsyth       }
1033*37da2899SCharles.Forsyth     }
1034*37da2899SCharles.Forsyth 
1035*37da2899SCharles.Forsyth     /***********************************************************************/
1036*37da2899SCharles.Forsyth     /*                                                                     */
1037*37da2899SCharles.Forsyth     /* third, get rid of the space on the left side of the glyph           */
1038*37da2899SCharles.Forsyth     /*                                                                     */
1039*37da2899SCharles.Forsyth     do
1040*37da2899SCharles.Forsyth     {
1041*37da2899SCharles.Forsyth       FT_Byte*  limit;
1042*37da2899SCharles.Forsyth 
1043*37da2899SCharles.Forsyth 
1044*37da2899SCharles.Forsyth       line  = (FT_Byte*)map->buffer;
1045*37da2899SCharles.Forsyth       limit = line + rows * line_len;
1046*37da2899SCharles.Forsyth 
1047*37da2899SCharles.Forsyth       for ( ; line < limit; line += line_len )
1048*37da2899SCharles.Forsyth         if ( line[0] & 0x80 )
1049*37da2899SCharles.Forsyth           goto Found_Left;
1050*37da2899SCharles.Forsyth 
1051*37da2899SCharles.Forsyth       /* shift the whole glyph one pixel to the left */
1052*37da2899SCharles.Forsyth       line  = (FT_Byte*)map->buffer;
1053*37da2899SCharles.Forsyth       limit = line + rows * line_len;
1054*37da2899SCharles.Forsyth 
1055*37da2899SCharles.Forsyth       for ( ; line < limit; line += line_len )
1056*37da2899SCharles.Forsyth       {
1057*37da2899SCharles.Forsyth         FT_Int    n, width = map->width;
1058*37da2899SCharles.Forsyth         FT_Byte   old;
1059*37da2899SCharles.Forsyth         FT_Byte*  cur = line;
1060*37da2899SCharles.Forsyth 
1061*37da2899SCharles.Forsyth 
1062*37da2899SCharles.Forsyth         old = (FT_Byte)(cur[0] << 1);
1063*37da2899SCharles.Forsyth         for ( n = 8; n < width; n += 8 )
1064*37da2899SCharles.Forsyth         {
1065*37da2899SCharles.Forsyth           FT_Byte  val;
1066*37da2899SCharles.Forsyth 
1067*37da2899SCharles.Forsyth 
1068*37da2899SCharles.Forsyth           val    = cur[1];
1069*37da2899SCharles.Forsyth           cur[0] = (FT_Byte)( old | ( val >> 7 ) );
1070*37da2899SCharles.Forsyth           old    = (FT_Byte)( val << 1 );
1071*37da2899SCharles.Forsyth           cur++;
1072*37da2899SCharles.Forsyth         }
1073*37da2899SCharles.Forsyth         cur[0] = old;
1074*37da2899SCharles.Forsyth       }
1075*37da2899SCharles.Forsyth 
1076*37da2899SCharles.Forsyth       map->width--;
1077*37da2899SCharles.Forsyth       metrics->horiBearingX++;
1078*37da2899SCharles.Forsyth       metrics->vertBearingX++;
1079*37da2899SCharles.Forsyth       metrics->width--;
1080*37da2899SCharles.Forsyth 
1081*37da2899SCharles.Forsyth     } while ( map->width > 0 );
1082*37da2899SCharles.Forsyth 
1083*37da2899SCharles.Forsyth   Found_Left:
1084*37da2899SCharles.Forsyth 
1085*37da2899SCharles.Forsyth     /***********************************************************************/
1086*37da2899SCharles.Forsyth     /*                                                                     */
1087*37da2899SCharles.Forsyth     /* finally, crop the bitmap width to get rid of the space on the right */
1088*37da2899SCharles.Forsyth     /* side of the glyph.                                                  */
1089*37da2899SCharles.Forsyth     /*                                                                     */
1090*37da2899SCharles.Forsyth     do
1091*37da2899SCharles.Forsyth     {
1092*37da2899SCharles.Forsyth       FT_Int    right = map->width - 1;
1093*37da2899SCharles.Forsyth       FT_Byte*  limit;
1094*37da2899SCharles.Forsyth       FT_Byte   mask;
1095*37da2899SCharles.Forsyth 
1096*37da2899SCharles.Forsyth 
1097*37da2899SCharles.Forsyth       line  = (FT_Byte*)map->buffer + ( right >> 3 );
1098*37da2899SCharles.Forsyth       limit = line + rows * line_len;
1099*37da2899SCharles.Forsyth       mask  = (FT_Byte)( 0x80 >> ( right & 7 ) );
1100*37da2899SCharles.Forsyth 
1101*37da2899SCharles.Forsyth       for ( ; line < limit; line += line_len )
1102*37da2899SCharles.Forsyth         if ( line[0] & mask )
1103*37da2899SCharles.Forsyth           goto Found_Right;
1104*37da2899SCharles.Forsyth 
1105*37da2899SCharles.Forsyth       /* crop the whole glyph to the right */
1106*37da2899SCharles.Forsyth       map->width--;
1107*37da2899SCharles.Forsyth       metrics->width--;
1108*37da2899SCharles.Forsyth 
1109*37da2899SCharles.Forsyth     } while ( map->width > 0 );
1110*37da2899SCharles.Forsyth 
1111*37da2899SCharles.Forsyth   Found_Right:
1112*37da2899SCharles.Forsyth     /* all right, the bitmap was cropped */
1113*37da2899SCharles.Forsyth     return;
1114*37da2899SCharles.Forsyth 
1115*37da2899SCharles.Forsyth   Empty_Bitmap:
1116*37da2899SCharles.Forsyth     map->width      = 0;
1117*37da2899SCharles.Forsyth     map->rows       = 0;
1118*37da2899SCharles.Forsyth     map->pitch      = 0;
1119*37da2899SCharles.Forsyth     map->pixel_mode = FT_PIXEL_MODE_MONO;
1120*37da2899SCharles.Forsyth   }
1121*37da2899SCharles.Forsyth 
1122*37da2899SCharles.Forsyth 
1123*37da2899SCharles.Forsyth   static FT_Error
Load_SBit_Single(FT_Bitmap * map,FT_Int x_offset,FT_Int y_offset,FT_Int pix_bits,FT_UShort image_format,TT_SBit_Metrics metrics,FT_Stream stream)1124*37da2899SCharles.Forsyth   Load_SBit_Single( FT_Bitmap*       map,
1125*37da2899SCharles.Forsyth                     FT_Int           x_offset,
1126*37da2899SCharles.Forsyth                     FT_Int           y_offset,
1127*37da2899SCharles.Forsyth                     FT_Int           pix_bits,
1128*37da2899SCharles.Forsyth                     FT_UShort        image_format,
1129*37da2899SCharles.Forsyth                     TT_SBit_Metrics  metrics,
1130*37da2899SCharles.Forsyth                     FT_Stream        stream )
1131*37da2899SCharles.Forsyth   {
1132*37da2899SCharles.Forsyth     FT_Error  error;
1133*37da2899SCharles.Forsyth 
1134*37da2899SCharles.Forsyth 
1135*37da2899SCharles.Forsyth     /* check that the source bitmap fits into the target pixmap */
1136*37da2899SCharles.Forsyth     if ( x_offset < 0 || x_offset + metrics->width  > map->width ||
1137*37da2899SCharles.Forsyth          y_offset < 0 || y_offset + metrics->height > map->rows  )
1138*37da2899SCharles.Forsyth     {
1139*37da2899SCharles.Forsyth       error = SFNT_Err_Invalid_Argument;
1140*37da2899SCharles.Forsyth 
1141*37da2899SCharles.Forsyth       goto Exit;
1142*37da2899SCharles.Forsyth     }
1143*37da2899SCharles.Forsyth 
1144*37da2899SCharles.Forsyth     {
1145*37da2899SCharles.Forsyth       FT_Int   glyph_width  = metrics->width;
1146*37da2899SCharles.Forsyth       FT_Int   glyph_height = metrics->height;
1147*37da2899SCharles.Forsyth       FT_Int   glyph_size;
1148*37da2899SCharles.Forsyth       FT_Int   line_bits    = pix_bits * glyph_width;
1149*37da2899SCharles.Forsyth       FT_Bool  pad_bytes    = 0;
1150*37da2899SCharles.Forsyth 
1151*37da2899SCharles.Forsyth 
1152*37da2899SCharles.Forsyth       /* compute size of glyph image */
1153*37da2899SCharles.Forsyth       switch ( image_format )
1154*37da2899SCharles.Forsyth       {
1155*37da2899SCharles.Forsyth       case 1:  /* byte-padded formats */
1156*37da2899SCharles.Forsyth       case 6:
1157*37da2899SCharles.Forsyth         {
1158*37da2899SCharles.Forsyth           FT_Int  line_length;
1159*37da2899SCharles.Forsyth 
1160*37da2899SCharles.Forsyth 
1161*37da2899SCharles.Forsyth           switch ( pix_bits )
1162*37da2899SCharles.Forsyth           {
1163*37da2899SCharles.Forsyth           case 1:
1164*37da2899SCharles.Forsyth             line_length = ( glyph_width + 7 ) >> 3;
1165*37da2899SCharles.Forsyth             break;
1166*37da2899SCharles.Forsyth           case 2:
1167*37da2899SCharles.Forsyth             line_length = ( glyph_width + 3 ) >> 2;
1168*37da2899SCharles.Forsyth             break;
1169*37da2899SCharles.Forsyth           case 4:
1170*37da2899SCharles.Forsyth             line_length = ( glyph_width + 1 ) >> 1;
1171*37da2899SCharles.Forsyth             break;
1172*37da2899SCharles.Forsyth           default:
1173*37da2899SCharles.Forsyth             line_length =   glyph_width;
1174*37da2899SCharles.Forsyth           }
1175*37da2899SCharles.Forsyth 
1176*37da2899SCharles.Forsyth           glyph_size = glyph_height * line_length;
1177*37da2899SCharles.Forsyth           pad_bytes  = 1;
1178*37da2899SCharles.Forsyth         }
1179*37da2899SCharles.Forsyth         break;
1180*37da2899SCharles.Forsyth 
1181*37da2899SCharles.Forsyth       case 2:
1182*37da2899SCharles.Forsyth       case 5:
1183*37da2899SCharles.Forsyth       case 7:
1184*37da2899SCharles.Forsyth         line_bits  =   glyph_width  * pix_bits;
1185*37da2899SCharles.Forsyth         glyph_size = ( glyph_height * line_bits + 7 ) >> 3;
1186*37da2899SCharles.Forsyth         break;
1187*37da2899SCharles.Forsyth 
1188*37da2899SCharles.Forsyth       default:  /* invalid format */
1189*37da2899SCharles.Forsyth         return SFNT_Err_Invalid_File_Format;
1190*37da2899SCharles.Forsyth       }
1191*37da2899SCharles.Forsyth 
1192*37da2899SCharles.Forsyth       /* Now read data and draw glyph into target pixmap       */
1193*37da2899SCharles.Forsyth       if ( FT_FRAME_ENTER( glyph_size ) )
1194*37da2899SCharles.Forsyth         goto Exit;
1195*37da2899SCharles.Forsyth 
1196*37da2899SCharles.Forsyth       /* don't forget to multiply `x_offset' by `map->pix_bits' as */
1197*37da2899SCharles.Forsyth       /* the sbit blitter doesn't make a difference between pixmap */
1198*37da2899SCharles.Forsyth       /* depths.                                                   */
1199*37da2899SCharles.Forsyth       blit_sbit( map, (FT_Byte*)stream->cursor, line_bits, pad_bytes,
1200*37da2899SCharles.Forsyth                  x_offset * pix_bits, y_offset );
1201*37da2899SCharles.Forsyth 
1202*37da2899SCharles.Forsyth       FT_FRAME_EXIT();
1203*37da2899SCharles.Forsyth     }
1204*37da2899SCharles.Forsyth 
1205*37da2899SCharles.Forsyth   Exit:
1206*37da2899SCharles.Forsyth     return error;
1207*37da2899SCharles.Forsyth   }
1208*37da2899SCharles.Forsyth 
1209*37da2899SCharles.Forsyth 
1210*37da2899SCharles.Forsyth   static FT_Error
Load_SBit_Image(TT_SBit_Strike strike,TT_SBit_Range range,FT_ULong ebdt_pos,FT_ULong glyph_offset,FT_Bitmap * map,FT_Int x_offset,FT_Int y_offset,FT_Stream stream,TT_SBit_Metrics metrics)1211*37da2899SCharles.Forsyth   Load_SBit_Image( TT_SBit_Strike   strike,
1212*37da2899SCharles.Forsyth                    TT_SBit_Range    range,
1213*37da2899SCharles.Forsyth                    FT_ULong         ebdt_pos,
1214*37da2899SCharles.Forsyth                    FT_ULong         glyph_offset,
1215*37da2899SCharles.Forsyth                    FT_Bitmap*       map,
1216*37da2899SCharles.Forsyth                    FT_Int           x_offset,
1217*37da2899SCharles.Forsyth                    FT_Int           y_offset,
1218*37da2899SCharles.Forsyth                    FT_Stream        stream,
1219*37da2899SCharles.Forsyth                    TT_SBit_Metrics  metrics )
1220*37da2899SCharles.Forsyth   {
1221*37da2899SCharles.Forsyth     FT_Memory  memory = stream->memory;
1222*37da2899SCharles.Forsyth     FT_Error   error;
1223*37da2899SCharles.Forsyth 
1224*37da2899SCharles.Forsyth 
1225*37da2899SCharles.Forsyth     /* place stream at beginning of glyph data and read metrics */
1226*37da2899SCharles.Forsyth     if ( FT_STREAM_SEEK( ebdt_pos + glyph_offset ) )
1227*37da2899SCharles.Forsyth       goto Exit;
1228*37da2899SCharles.Forsyth 
1229*37da2899SCharles.Forsyth     error = load_sbit_metrics( stream, range, metrics );
1230*37da2899SCharles.Forsyth     if ( error )
1231*37da2899SCharles.Forsyth       goto Exit;
1232*37da2899SCharles.Forsyth 
1233*37da2899SCharles.Forsyth     /* this function is recursive.  At the top-level call, the */
1234*37da2899SCharles.Forsyth     /* field map.buffer is NULL.  We thus begin by finding the */
1235*37da2899SCharles.Forsyth     /* dimensions of the higher-level glyph to allocate the    */
1236*37da2899SCharles.Forsyth     /* final pixmap buffer                                     */
1237*37da2899SCharles.Forsyth     if ( map->buffer == 0 )
1238*37da2899SCharles.Forsyth     {
1239*37da2899SCharles.Forsyth       FT_Long  size;
1240*37da2899SCharles.Forsyth 
1241*37da2899SCharles.Forsyth 
1242*37da2899SCharles.Forsyth       map->width = metrics->width;
1243*37da2899SCharles.Forsyth       map->rows  = metrics->height;
1244*37da2899SCharles.Forsyth 
1245*37da2899SCharles.Forsyth       switch ( strike->bit_depth )
1246*37da2899SCharles.Forsyth       {
1247*37da2899SCharles.Forsyth       case 1:
1248*37da2899SCharles.Forsyth         map->pixel_mode = FT_PIXEL_MODE_MONO;
1249*37da2899SCharles.Forsyth         map->pitch      = ( map->width + 7 ) >> 3;
1250*37da2899SCharles.Forsyth         break;
1251*37da2899SCharles.Forsyth 
1252*37da2899SCharles.Forsyth       case 2:
1253*37da2899SCharles.Forsyth         map->pixel_mode = FT_PIXEL_MODE_GRAY2;
1254*37da2899SCharles.Forsyth         map->pitch      = ( map->width + 3 ) >> 2;
1255*37da2899SCharles.Forsyth         break;
1256*37da2899SCharles.Forsyth 
1257*37da2899SCharles.Forsyth       case 4:
1258*37da2899SCharles.Forsyth         map->pixel_mode = FT_PIXEL_MODE_GRAY4;
1259*37da2899SCharles.Forsyth         map->pitch      = ( map->width + 1 ) >> 1;
1260*37da2899SCharles.Forsyth         break;
1261*37da2899SCharles.Forsyth 
1262*37da2899SCharles.Forsyth       case 8:
1263*37da2899SCharles.Forsyth         map->pixel_mode = FT_PIXEL_MODE_GRAY;
1264*37da2899SCharles.Forsyth         map->pitch      = map->width;
1265*37da2899SCharles.Forsyth         break;
1266*37da2899SCharles.Forsyth 
1267*37da2899SCharles.Forsyth       default:
1268*37da2899SCharles.Forsyth         return SFNT_Err_Invalid_File_Format;
1269*37da2899SCharles.Forsyth       }
1270*37da2899SCharles.Forsyth 
1271*37da2899SCharles.Forsyth       size = map->rows * map->pitch;
1272*37da2899SCharles.Forsyth 
1273*37da2899SCharles.Forsyth       /* check that there is no empty image */
1274*37da2899SCharles.Forsyth       if ( size == 0 )
1275*37da2899SCharles.Forsyth         goto Exit;     /* exit successfully! */
1276*37da2899SCharles.Forsyth 
1277*37da2899SCharles.Forsyth       if ( FT_ALLOC( map->buffer, size ) )
1278*37da2899SCharles.Forsyth         goto Exit;
1279*37da2899SCharles.Forsyth     }
1280*37da2899SCharles.Forsyth 
1281*37da2899SCharles.Forsyth     switch ( range->image_format )
1282*37da2899SCharles.Forsyth     {
1283*37da2899SCharles.Forsyth     case 1:  /* single sbit image - load it */
1284*37da2899SCharles.Forsyth     case 2:
1285*37da2899SCharles.Forsyth     case 5:
1286*37da2899SCharles.Forsyth     case 6:
1287*37da2899SCharles.Forsyth     case 7:
1288*37da2899SCharles.Forsyth       return Load_SBit_Single( map, x_offset, y_offset, strike->bit_depth,
1289*37da2899SCharles.Forsyth                                range->image_format, metrics, stream );
1290*37da2899SCharles.Forsyth 
1291*37da2899SCharles.Forsyth     case 8:  /* compound format */
1292*37da2899SCharles.Forsyth       FT_Stream_Skip( stream, 1L );
1293*37da2899SCharles.Forsyth       /* fallthrough */
1294*37da2899SCharles.Forsyth 
1295*37da2899SCharles.Forsyth     case 9:
1296*37da2899SCharles.Forsyth       break;
1297*37da2899SCharles.Forsyth 
1298*37da2899SCharles.Forsyth     default: /* invalid image format */
1299*37da2899SCharles.Forsyth       return SFNT_Err_Invalid_File_Format;
1300*37da2899SCharles.Forsyth     }
1301*37da2899SCharles.Forsyth 
1302*37da2899SCharles.Forsyth     /* All right, we have a compound format.  First of all, read */
1303*37da2899SCharles.Forsyth     /* the array of elements.                                    */
1304*37da2899SCharles.Forsyth     {
1305*37da2899SCharles.Forsyth       TT_SBit_Component  components;
1306*37da2899SCharles.Forsyth       TT_SBit_Component  comp;
1307*37da2899SCharles.Forsyth       FT_UShort          num_components, count;
1308*37da2899SCharles.Forsyth 
1309*37da2899SCharles.Forsyth 
1310*37da2899SCharles.Forsyth       if ( FT_READ_USHORT( num_components )           ||
1311*37da2899SCharles.Forsyth            FT_NEW_ARRAY( components, num_components ) )
1312*37da2899SCharles.Forsyth         goto Exit;
1313*37da2899SCharles.Forsyth 
1314*37da2899SCharles.Forsyth       count = num_components;
1315*37da2899SCharles.Forsyth 
1316*37da2899SCharles.Forsyth       if ( FT_FRAME_ENTER( 4L * num_components ) )
1317*37da2899SCharles.Forsyth         goto Fail_Memory;
1318*37da2899SCharles.Forsyth 
1319*37da2899SCharles.Forsyth       for ( comp = components; count > 0; count--, comp++ )
1320*37da2899SCharles.Forsyth       {
1321*37da2899SCharles.Forsyth         comp->glyph_code = FT_GET_USHORT();
1322*37da2899SCharles.Forsyth         comp->x_offset   = FT_GET_CHAR();
1323*37da2899SCharles.Forsyth         comp->y_offset   = FT_GET_CHAR();
1324*37da2899SCharles.Forsyth       }
1325*37da2899SCharles.Forsyth 
1326*37da2899SCharles.Forsyth       FT_FRAME_EXIT();
1327*37da2899SCharles.Forsyth 
1328*37da2899SCharles.Forsyth       /* Now recursively load each element glyph */
1329*37da2899SCharles.Forsyth       count = num_components;
1330*37da2899SCharles.Forsyth       comp  = components;
1331*37da2899SCharles.Forsyth       for ( ; count > 0; count--, comp++ )
1332*37da2899SCharles.Forsyth       {
1333*37da2899SCharles.Forsyth         TT_SBit_Range       elem_range;
1334*37da2899SCharles.Forsyth         TT_SBit_MetricsRec  elem_metrics;
1335*37da2899SCharles.Forsyth         FT_ULong            elem_offset;
1336*37da2899SCharles.Forsyth 
1337*37da2899SCharles.Forsyth 
1338*37da2899SCharles.Forsyth         /* find the range for this element */
1339*37da2899SCharles.Forsyth         error = find_sbit_range( comp->glyph_code,
1340*37da2899SCharles.Forsyth                                  strike,
1341*37da2899SCharles.Forsyth                                  &elem_range,
1342*37da2899SCharles.Forsyth                                  &elem_offset );
1343*37da2899SCharles.Forsyth         if ( error )
1344*37da2899SCharles.Forsyth           goto Fail_Memory;
1345*37da2899SCharles.Forsyth 
1346*37da2899SCharles.Forsyth         /* now load the element, recursively */
1347*37da2899SCharles.Forsyth         error = Load_SBit_Image( strike,
1348*37da2899SCharles.Forsyth                                  elem_range,
1349*37da2899SCharles.Forsyth                                  ebdt_pos,
1350*37da2899SCharles.Forsyth                                  elem_offset,
1351*37da2899SCharles.Forsyth                                  map,
1352*37da2899SCharles.Forsyth                                  x_offset + comp->x_offset,
1353*37da2899SCharles.Forsyth                                  y_offset + comp->y_offset,
1354*37da2899SCharles.Forsyth                                  stream,
1355*37da2899SCharles.Forsyth                                  &elem_metrics );
1356*37da2899SCharles.Forsyth         if ( error )
1357*37da2899SCharles.Forsyth           goto Fail_Memory;
1358*37da2899SCharles.Forsyth       }
1359*37da2899SCharles.Forsyth 
1360*37da2899SCharles.Forsyth     Fail_Memory:
1361*37da2899SCharles.Forsyth       FT_FREE( components );
1362*37da2899SCharles.Forsyth     }
1363*37da2899SCharles.Forsyth 
1364*37da2899SCharles.Forsyth   Exit:
1365*37da2899SCharles.Forsyth     return error;
1366*37da2899SCharles.Forsyth   }
1367*37da2899SCharles.Forsyth 
1368*37da2899SCharles.Forsyth 
1369*37da2899SCharles.Forsyth   /*************************************************************************/
1370*37da2899SCharles.Forsyth   /*                                                                       */
1371*37da2899SCharles.Forsyth   /* <Function>                                                            */
1372*37da2899SCharles.Forsyth   /*    tt_face_load_sbit_image                                            */
1373*37da2899SCharles.Forsyth   /*                                                                       */
1374*37da2899SCharles.Forsyth   /* <Description>                                                         */
1375*37da2899SCharles.Forsyth   /*    Loads a given glyph sbit image from the font resource.  This also  */
1376*37da2899SCharles.Forsyth   /*    returns its metrics.                                               */
1377*37da2899SCharles.Forsyth   /*                                                                       */
1378*37da2899SCharles.Forsyth   /* <Input>                                                               */
1379*37da2899SCharles.Forsyth   /*    face         :: The target face object.                            */
1380*37da2899SCharles.Forsyth   /*                                                                       */
1381*37da2899SCharles.Forsyth   /*    strike_index :: The current strike index.                          */
1382*37da2899SCharles.Forsyth   /*                                                                       */
1383*37da2899SCharles.Forsyth   /*    glyph_index  :: The current glyph index.                           */
1384*37da2899SCharles.Forsyth   /*                                                                       */
1385*37da2899SCharles.Forsyth   /*    load_flags   :: The glyph load flags (the code checks for the flag */
1386*37da2899SCharles.Forsyth   /*                    FT_LOAD_CROP_BITMAP).                              */
1387*37da2899SCharles.Forsyth   /*                                                                       */
1388*37da2899SCharles.Forsyth   /*    stream       :: The input stream.                                  */
1389*37da2899SCharles.Forsyth   /*                                                                       */
1390*37da2899SCharles.Forsyth   /* <Output>                                                              */
1391*37da2899SCharles.Forsyth   /*    map          :: The target pixmap.                                 */
1392*37da2899SCharles.Forsyth   /*                                                                       */
1393*37da2899SCharles.Forsyth   /*    metrics      :: A big sbit metrics structure for the glyph image.  */
1394*37da2899SCharles.Forsyth   /*                                                                       */
1395*37da2899SCharles.Forsyth   /* <Return>                                                              */
1396*37da2899SCharles.Forsyth   /*    FreeType error code.  0 means success.  Returns an error if no     */
1397*37da2899SCharles.Forsyth   /*    glyph sbit exists for the index.                                   */
1398*37da2899SCharles.Forsyth   /*                                                                       */
1399*37da2899SCharles.Forsyth   /*  <Note>                                                               */
1400*37da2899SCharles.Forsyth   /*    The `map.buffer' field is always freed before the glyph is loaded. */
1401*37da2899SCharles.Forsyth   /*                                                                       */
1402*37da2899SCharles.Forsyth   FT_LOCAL_DEF( FT_Error )
tt_face_load_sbit_image(TT_Face face,FT_ULong strike_index,FT_UInt glyph_index,FT_UInt load_flags,FT_Stream stream,FT_Bitmap * map,TT_SBit_MetricsRec * metrics)1403*37da2899SCharles.Forsyth   tt_face_load_sbit_image( TT_Face              face,
1404*37da2899SCharles.Forsyth                            FT_ULong             strike_index,
1405*37da2899SCharles.Forsyth                            FT_UInt              glyph_index,
1406*37da2899SCharles.Forsyth                            FT_UInt              load_flags,
1407*37da2899SCharles.Forsyth                            FT_Stream            stream,
1408*37da2899SCharles.Forsyth                            FT_Bitmap           *map,
1409*37da2899SCharles.Forsyth                            TT_SBit_MetricsRec  *metrics )
1410*37da2899SCharles.Forsyth   {
1411*37da2899SCharles.Forsyth     FT_Error        error;
1412*37da2899SCharles.Forsyth     FT_Memory       memory = stream->memory;
1413*37da2899SCharles.Forsyth     FT_ULong        ebdt_pos, glyph_offset;
1414*37da2899SCharles.Forsyth 
1415*37da2899SCharles.Forsyth     TT_SBit_Strike  strike;
1416*37da2899SCharles.Forsyth     TT_SBit_Range   range;
1417*37da2899SCharles.Forsyth 
1418*37da2899SCharles.Forsyth 
1419*37da2899SCharles.Forsyth     /* Check whether there is a glyph sbit for the current index */
1420*37da2899SCharles.Forsyth     error = find_sbit_image( face, glyph_index, strike_index,
1421*37da2899SCharles.Forsyth                              &range, &strike, &glyph_offset );
1422*37da2899SCharles.Forsyth     if ( error )
1423*37da2899SCharles.Forsyth       goto Exit;
1424*37da2899SCharles.Forsyth 
1425*37da2899SCharles.Forsyth     /* now, find the location of the `EBDT' table in */
1426*37da2899SCharles.Forsyth     /* the font file                                 */
1427*37da2899SCharles.Forsyth     error = face->goto_table( face, TTAG_EBDT, stream, 0 );
1428*37da2899SCharles.Forsyth     if ( error )
1429*37da2899SCharles.Forsyth       error = face->goto_table( face, TTAG_bdat, stream, 0 );
1430*37da2899SCharles.Forsyth     if (error)
1431*37da2899SCharles.Forsyth       goto Exit;
1432*37da2899SCharles.Forsyth 
1433*37da2899SCharles.Forsyth     ebdt_pos = FT_STREAM_POS();
1434*37da2899SCharles.Forsyth 
1435*37da2899SCharles.Forsyth     /* clear the bitmap & load the bitmap */
1436*37da2899SCharles.Forsyth     if ( face->root.glyph->flags & FT_GLYPH_OWN_BITMAP )
1437*37da2899SCharles.Forsyth       FT_FREE( map->buffer );
1438*37da2899SCharles.Forsyth 
1439*37da2899SCharles.Forsyth     map->rows = map->pitch = map->width = 0;
1440*37da2899SCharles.Forsyth 
1441*37da2899SCharles.Forsyth     error = Load_SBit_Image( strike, range, ebdt_pos, glyph_offset,
1442*37da2899SCharles.Forsyth                              map, 0, 0, stream, metrics );
1443*37da2899SCharles.Forsyth     if ( error )
1444*37da2899SCharles.Forsyth       goto Exit;
1445*37da2899SCharles.Forsyth 
1446*37da2899SCharles.Forsyth     /* the glyph slot owns this bitmap buffer */
1447*37da2899SCharles.Forsyth     face->root.glyph->flags |= FT_GLYPH_OWN_BITMAP;
1448*37da2899SCharles.Forsyth 
1449*37da2899SCharles.Forsyth     /* setup vertical metrics if needed */
1450*37da2899SCharles.Forsyth     if ( strike->flags & 1 )
1451*37da2899SCharles.Forsyth     {
1452*37da2899SCharles.Forsyth       /* in case of a horizontal strike only */
1453*37da2899SCharles.Forsyth       FT_Int  advance;
1454*37da2899SCharles.Forsyth 
1455*37da2899SCharles.Forsyth 
1456*37da2899SCharles.Forsyth       advance = strike->hori.ascender - strike->hori.descender;
1457*37da2899SCharles.Forsyth 
1458*37da2899SCharles.Forsyth       /* some heuristic values */
1459*37da2899SCharles.Forsyth 
1460*37da2899SCharles.Forsyth       metrics->vertBearingX = (FT_Char)(-metrics->width / 2 );
1461*37da2899SCharles.Forsyth       metrics->vertBearingY = (FT_Char)( advance / 10 );
1462*37da2899SCharles.Forsyth       metrics->vertAdvance  = (FT_Char)( advance * 12 / 10 );
1463*37da2899SCharles.Forsyth     }
1464*37da2899SCharles.Forsyth 
1465*37da2899SCharles.Forsyth     /* Crop the bitmap now, unless specified otherwise */
1466*37da2899SCharles.Forsyth     if ( load_flags & FT_LOAD_CROP_BITMAP )
1467*37da2899SCharles.Forsyth       crop_bitmap( map, metrics );
1468*37da2899SCharles.Forsyth 
1469*37da2899SCharles.Forsyth   Exit:
1470*37da2899SCharles.Forsyth     return error;
1471*37da2899SCharles.Forsyth   }
1472*37da2899SCharles.Forsyth 
1473*37da2899SCharles.Forsyth 
1474*37da2899SCharles.Forsyth /* END */
1475