• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  *
3  * ttcolr.c
4  *
5  *   TrueType and OpenType colored glyph layer support (body).
6  *
7  * Copyright (C) 2018-2020 by
8  * David Turner, Robert Wilhelm, and Werner Lemberg.
9  *
10  * Originally written by Shao Yu Zhang <shaozhang@fb.com>.
11  *
12  * This file is part of the FreeType project, and may only be used,
13  * modified, and distributed under the terms of the FreeType project
14  * license, LICENSE.TXT.  By continuing to use, modify, or distribute
15  * this file you indicate that you have read the license and
16  * understand and accept it fully.
17  *
18  */
19 
20 
21   /**************************************************************************
22    *
23    * `COLR' table specification:
24    *
25    *   https://www.microsoft.com/typography/otspec/colr.htm
26    *
27    */
28 
29 
30 #include <freetype/internal/ftdebug.h>
31 #include <freetype/internal/ftstream.h>
32 #include <freetype/tttags.h>
33 #include <freetype/ftcolor.h>
34 
35 
36 #ifdef TT_CONFIG_OPTION_COLOR_LAYERS
37 
38 #include "ttcolr.h"
39 
40 
41   /* NOTE: These are the table sizes calculated through the specs. */
42 #define BASE_GLYPH_SIZE            6U
43 #define LAYER_SIZE                 4U
44 #define COLR_HEADER_SIZE          14U
45 
46 
47   typedef struct BaseGlyphRecord_
48   {
49     FT_UShort  gid;
50     FT_UShort  first_layer_index;
51     FT_UShort  num_layers;
52 
53   } BaseGlyphRecord;
54 
55 
56   typedef struct Colr_
57   {
58     FT_UShort  version;
59     FT_UShort  num_base_glyphs;
60     FT_UShort  num_layers;
61 
62     FT_Byte*  base_glyphs;
63     FT_Byte*  layers;
64 
65     /* The memory which backs up the `COLR' table. */
66     void*     table;
67     FT_ULong  table_size;
68 
69   } Colr;
70 
71 
72   /**************************************************************************
73    *
74    * The macro FT_COMPONENT is used in trace mode.  It is an implicit
75    * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
76    * messages during execution.
77    */
78 #undef  FT_COMPONENT
79 #define FT_COMPONENT  ttcolr
80 
81 
82   FT_LOCAL_DEF( FT_Error )
tt_face_load_colr(TT_Face face,FT_Stream stream)83   tt_face_load_colr( TT_Face    face,
84                      FT_Stream  stream )
85   {
86     FT_Error   error;
87     FT_Memory  memory = face->root.memory;
88 
89     FT_Byte*  table = NULL;
90     FT_Byte*  p     = NULL;
91 
92     Colr*  colr = NULL;
93 
94     FT_ULong  base_glyph_offset, layer_offset;
95     FT_ULong  table_size;
96 
97 
98     /* `COLR' always needs `CPAL' */
99     if ( !face->cpal )
100       return FT_THROW( Invalid_File_Format );
101 
102     error = face->goto_table( face, TTAG_COLR, stream, &table_size );
103     if ( error )
104       goto NoColr;
105 
106     if ( table_size < COLR_HEADER_SIZE )
107       goto InvalidTable;
108 
109     if ( FT_FRAME_EXTRACT( table_size, table ) )
110       goto NoColr;
111 
112     p = table;
113 
114     if ( FT_NEW( colr ) )
115       goto NoColr;
116 
117     colr->version = FT_NEXT_USHORT( p );
118     if ( colr->version != 0 )
119       goto InvalidTable;
120 
121     colr->num_base_glyphs = FT_NEXT_USHORT( p );
122     base_glyph_offset     = FT_NEXT_ULONG( p );
123 
124     if ( base_glyph_offset >= table_size )
125       goto InvalidTable;
126     if ( colr->num_base_glyphs * BASE_GLYPH_SIZE >
127            table_size - base_glyph_offset )
128       goto InvalidTable;
129 
130     layer_offset     = FT_NEXT_ULONG( p );
131     colr->num_layers = FT_NEXT_USHORT( p );
132 
133     if ( layer_offset >= table_size )
134       goto InvalidTable;
135     if ( colr->num_layers * LAYER_SIZE > table_size - layer_offset )
136       goto InvalidTable;
137 
138     colr->base_glyphs = (FT_Byte*)( table + base_glyph_offset );
139     colr->layers      = (FT_Byte*)( table + layer_offset      );
140     colr->table       = table;
141     colr->table_size  = table_size;
142 
143     face->colr = colr;
144 
145     return FT_Err_Ok;
146 
147   InvalidTable:
148     error = FT_THROW( Invalid_Table );
149 
150   NoColr:
151     FT_FRAME_RELEASE( table );
152     FT_FREE( colr );
153 
154     return error;
155   }
156 
157 
158   FT_LOCAL_DEF( void )
tt_face_free_colr(TT_Face face)159   tt_face_free_colr( TT_Face  face )
160   {
161     FT_Stream  stream = face->root.stream;
162     FT_Memory  memory = face->root.memory;
163 
164     Colr*  colr = (Colr*)face->colr;
165 
166 
167     if ( colr )
168     {
169       FT_FRAME_RELEASE( colr->table );
170       FT_FREE( colr );
171     }
172   }
173 
174 
175   static FT_Bool
find_base_glyph_record(FT_Byte * base_glyph_begin,FT_Int num_base_glyph,FT_UInt glyph_id,BaseGlyphRecord * record)176   find_base_glyph_record( FT_Byte*          base_glyph_begin,
177                           FT_Int            num_base_glyph,
178                           FT_UInt           glyph_id,
179                           BaseGlyphRecord*  record )
180   {
181     FT_Int  min = 0;
182     FT_Int  max = num_base_glyph - 1;
183 
184 
185     while ( min <= max )
186     {
187       FT_Int    mid = min + ( max - min ) / 2;
188       FT_Byte*  p   = base_glyph_begin + mid * BASE_GLYPH_SIZE;
189 
190       FT_UShort  gid = FT_NEXT_USHORT( p );
191 
192 
193       if ( gid < glyph_id )
194         min = mid + 1;
195       else if (gid > glyph_id )
196         max = mid - 1;
197       else
198       {
199         record->gid               = gid;
200         record->first_layer_index = FT_NEXT_USHORT( p );
201         record->num_layers        = FT_NEXT_USHORT( p );
202 
203         return 1;
204       }
205     }
206 
207     return 0;
208   }
209 
210 
211   FT_LOCAL_DEF( FT_Bool )
tt_face_get_colr_layer(TT_Face face,FT_UInt base_glyph,FT_UInt * aglyph_index,FT_UInt * acolor_index,FT_LayerIterator * iterator)212   tt_face_get_colr_layer( TT_Face            face,
213                           FT_UInt            base_glyph,
214                           FT_UInt           *aglyph_index,
215                           FT_UInt           *acolor_index,
216                           FT_LayerIterator*  iterator )
217   {
218     Colr*            colr = (Colr*)face->colr;
219     BaseGlyphRecord  glyph_record;
220 
221 
222     if ( !colr )
223       return 0;
224 
225     if ( !iterator->p )
226     {
227       FT_ULong  offset;
228 
229 
230       /* first call to function */
231       iterator->layer = 0;
232 
233       if ( !find_base_glyph_record( colr->base_glyphs,
234                                     colr->num_base_glyphs,
235                                     base_glyph,
236                                     &glyph_record ) )
237         return 0;
238 
239       if ( glyph_record.num_layers )
240         iterator->num_layers = glyph_record.num_layers;
241       else
242         return 0;
243 
244       offset = LAYER_SIZE * glyph_record.first_layer_index;
245       if ( offset + LAYER_SIZE * glyph_record.num_layers > colr->table_size )
246         return 0;
247 
248       iterator->p = colr->layers + offset;
249     }
250 
251     if ( iterator->layer >= iterator->num_layers )
252       return 0;
253 
254     *aglyph_index = FT_NEXT_USHORT( iterator->p );
255     *acolor_index = FT_NEXT_USHORT( iterator->p );
256 
257     if ( *aglyph_index >= (FT_UInt)( FT_FACE( face )->num_glyphs )   ||
258          ( *acolor_index != 0xFFFF                                 &&
259            *acolor_index >= face->palette_data.num_palette_entries ) )
260       return 0;
261 
262     iterator->layer++;
263 
264     return 1;
265   }
266 
267 
268   FT_LOCAL_DEF( FT_Error )
tt_face_colr_blend_layer(TT_Face face,FT_UInt color_index,FT_GlyphSlot dstSlot,FT_GlyphSlot srcSlot)269   tt_face_colr_blend_layer( TT_Face       face,
270                             FT_UInt       color_index,
271                             FT_GlyphSlot  dstSlot,
272                             FT_GlyphSlot  srcSlot )
273   {
274     FT_Error  error;
275 
276     FT_UInt  x, y;
277     FT_Byte  b, g, r, alpha;
278 
279     FT_ULong  size;
280     FT_Byte*  src;
281     FT_Byte*  dst;
282 
283 
284     if ( !dstSlot->bitmap.buffer )
285     {
286       /* Initialize destination of color bitmap */
287       /* with the size of first component.      */
288       dstSlot->bitmap_left = srcSlot->bitmap_left;
289       dstSlot->bitmap_top  = srcSlot->bitmap_top;
290 
291       dstSlot->bitmap.width      = srcSlot->bitmap.width;
292       dstSlot->bitmap.rows       = srcSlot->bitmap.rows;
293       dstSlot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA;
294       dstSlot->bitmap.pitch      = (int)dstSlot->bitmap.width * 4;
295       dstSlot->bitmap.num_grays  = 256;
296 
297       size = dstSlot->bitmap.rows * (unsigned int)dstSlot->bitmap.pitch;
298 
299       error = ft_glyphslot_alloc_bitmap( dstSlot, size );
300       if ( error )
301         return error;
302 
303       FT_MEM_ZERO( dstSlot->bitmap.buffer, size );
304     }
305     else
306     {
307       /* Resize destination if needed such that new component fits. */
308       FT_Int  x_min, x_max, y_min, y_max;
309 
310 
311       x_min = FT_MIN( dstSlot->bitmap_left, srcSlot->bitmap_left );
312       x_max = FT_MAX( dstSlot->bitmap_left + (FT_Int)dstSlot->bitmap.width,
313                       srcSlot->bitmap_left + (FT_Int)srcSlot->bitmap.width );
314 
315       y_min = FT_MIN( dstSlot->bitmap_top - (FT_Int)dstSlot->bitmap.rows,
316                       srcSlot->bitmap_top - (FT_Int)srcSlot->bitmap.rows );
317       y_max = FT_MAX( dstSlot->bitmap_top, srcSlot->bitmap_top );
318 
319       if ( x_min != dstSlot->bitmap_left                                 ||
320            x_max != dstSlot->bitmap_left + (FT_Int)dstSlot->bitmap.width ||
321            y_min != dstSlot->bitmap_top - (FT_Int)dstSlot->bitmap.rows   ||
322            y_max != dstSlot->bitmap_top                                  )
323       {
324         FT_Memory  memory = face->root.memory;
325 
326         FT_UInt  width = (FT_UInt)( x_max - x_min );
327         FT_UInt  rows  = (FT_UInt)( y_max - y_min );
328         FT_UInt  pitch = width * 4;
329 
330         FT_Byte*  buf = NULL;
331         FT_Byte*  p;
332         FT_Byte*  q;
333 
334 
335         size  = rows * pitch;
336         if ( FT_ALLOC( buf, size ) )
337           return error;
338 
339         p = dstSlot->bitmap.buffer;
340         q = buf +
341             (int)pitch * ( y_max - dstSlot->bitmap_top ) +
342             4 * ( dstSlot->bitmap_left - x_min );
343 
344         for ( y = 0; y < dstSlot->bitmap.rows; y++ )
345         {
346           FT_MEM_COPY( q, p, dstSlot->bitmap.width * 4 );
347 
348           p += dstSlot->bitmap.pitch;
349           q += pitch;
350         }
351 
352         ft_glyphslot_set_bitmap( dstSlot, buf );
353 
354         dstSlot->bitmap_top  = y_max;
355         dstSlot->bitmap_left = x_min;
356 
357         dstSlot->bitmap.width = width;
358         dstSlot->bitmap.rows  = rows;
359         dstSlot->bitmap.pitch = (int)pitch;
360 
361         dstSlot->internal->flags |= FT_GLYPH_OWN_BITMAP;
362         dstSlot->format           = FT_GLYPH_FORMAT_BITMAP;
363       }
364     }
365 
366     if ( color_index == 0xFFFF )
367     {
368       if ( face->have_foreground_color )
369       {
370         b     = face->foreground_color.blue;
371         g     = face->foreground_color.green;
372         r     = face->foreground_color.red;
373         alpha = face->foreground_color.alpha;
374       }
375       else
376       {
377         if ( face->palette_data.palette_flags                          &&
378              ( face->palette_data.palette_flags[face->palette_index] &
379                  FT_PALETTE_FOR_DARK_BACKGROUND                      ) )
380         {
381           /* white opaque */
382           b     = 0xFF;
383           g     = 0xFF;
384           r     = 0xFF;
385           alpha = 0xFF;
386         }
387         else
388         {
389           /* black opaque */
390           b     = 0x00;
391           g     = 0x00;
392           r     = 0x00;
393           alpha = 0xFF;
394         }
395       }
396     }
397     else
398     {
399       b     = face->palette[color_index].blue;
400       g     = face->palette[color_index].green;
401       r     = face->palette[color_index].red;
402       alpha = face->palette[color_index].alpha;
403     }
404 
405     /* XXX Convert if srcSlot.bitmap is not grey? */
406     src = srcSlot->bitmap.buffer;
407     dst = dstSlot->bitmap.buffer +
408           dstSlot->bitmap.pitch * ( dstSlot->bitmap_top - srcSlot->bitmap_top ) +
409           4 * ( srcSlot->bitmap_left - dstSlot->bitmap_left );
410 
411     for ( y = 0; y < srcSlot->bitmap.rows; y++ )
412     {
413       for ( x = 0; x < srcSlot->bitmap.width; x++ )
414       {
415         int  aa = src[x];
416         int  fa = alpha * aa / 255;
417 
418         int  fb = b * fa / 255;
419         int  fg = g * fa / 255;
420         int  fr = r * fa / 255;
421 
422         int  ba2 = 255 - fa;
423 
424         int  bb = dst[4 * x + 0];
425         int  bg = dst[4 * x + 1];
426         int  br = dst[4 * x + 2];
427         int  ba = dst[4 * x + 3];
428 
429 
430         dst[4 * x + 0] = (FT_Byte)( bb * ba2 / 255 + fb );
431         dst[4 * x + 1] = (FT_Byte)( bg * ba2 / 255 + fg );
432         dst[4 * x + 2] = (FT_Byte)( br * ba2 / 255 + fr );
433         dst[4 * x + 3] = (FT_Byte)( ba * ba2 / 255 + fa );
434       }
435 
436       src += srcSlot->bitmap.pitch;
437       dst += dstSlot->bitmap.pitch;
438     }
439 
440     return FT_Err_Ok;
441   }
442 
443 #else /* !TT_CONFIG_OPTION_COLOR_LAYERS */
444 
445   /* ANSI C doesn't like empty source files */
446   typedef int  _tt_colr_dummy;
447 
448 #endif /* !TT_CONFIG_OPTION_COLOR_LAYERS */
449 
450 /* EOF */
451