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