(root)/
freetype-2.13.2/
src/
sfnt/
ttcpal.c
       1  /****************************************************************************
       2   *
       3   * ttcpal.c
       4   *
       5   *   TrueType and OpenType color palette support (body).
       6   *
       7   * Copyright (C) 2018-2023 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     * `CPAL' table specification:
      24     *
      25     *   https://www.microsoft.com/typography/otspec/cpal.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 "ttcpal.h"
      39  
      40  
      41    /* NOTE: These are the table sizes calculated through the specs. */
      42  #define CPAL_V0_HEADER_BASE_SIZE  12U
      43  #define COLOR_SIZE                 4U
      44  
      45  
      46    /* all data from `CPAL' not covered in FT_Palette_Data */
      47    typedef struct Cpal_
      48    {
      49      FT_UShort  version;        /* Table version number (0 or 1 supported). */
      50      FT_UShort  num_colors;               /* Total number of color records, */
      51                                           /* combined for all palettes.     */
      52      FT_Byte*  colors;                              /* RGBA array of colors */
      53      FT_Byte*  color_indices; /* Index of each palette's first color record */
      54                               /* in the combined color record array.        */
      55  
      56      /* The memory which backs up the `CPAL' table. */
      57      void*     table;
      58      FT_ULong  table_size;
      59  
      60    } Cpal;
      61  
      62  
      63    /**************************************************************************
      64     *
      65     * The macro FT_COMPONENT is used in trace mode.  It is an implicit
      66     * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
      67     * messages during execution.
      68     */
      69  #undef  FT_COMPONENT
      70  #define FT_COMPONENT  ttcpal
      71  
      72  
      73    FT_LOCAL_DEF( FT_Error )
      74    tt_face_load_cpal( TT_Face    face,
      75                       FT_Stream  stream )
      76    {
      77      FT_Error   error;
      78      FT_Memory  memory = face->root.memory;
      79  
      80      FT_Byte*  table = NULL;
      81      FT_Byte*  p     = NULL;
      82  
      83      Cpal*  cpal = NULL;
      84  
      85      FT_ULong  colors_offset;
      86      FT_ULong  table_size;
      87  
      88  
      89      error = face->goto_table( face, TTAG_CPAL, stream, &table_size );
      90      if ( error )
      91        goto NoCpal;
      92  
      93      if ( table_size < CPAL_V0_HEADER_BASE_SIZE )
      94        goto InvalidTable;
      95  
      96      if ( FT_FRAME_EXTRACT( table_size, table ) )
      97        goto NoCpal;
      98  
      99      p = table;
     100  
     101      if ( FT_NEW( cpal ) )
     102        goto NoCpal;
     103  
     104      cpal->version = FT_NEXT_USHORT( p );
     105      if ( cpal->version > 1 )
     106        goto InvalidTable;
     107  
     108      face->palette_data.num_palette_entries = FT_NEXT_USHORT( p );
     109      face->palette_data.num_palettes        = FT_NEXT_USHORT( p );
     110  
     111      cpal->num_colors = FT_NEXT_USHORT( p );
     112      colors_offset    = FT_NEXT_ULONG( p );
     113  
     114      if ( CPAL_V0_HEADER_BASE_SIZE             +
     115           face->palette_data.num_palettes * 2U > table_size )
     116        goto InvalidTable;
     117  
     118      if ( colors_offset >= table_size )
     119        goto InvalidTable;
     120      if ( cpal->num_colors * COLOR_SIZE > table_size - colors_offset )
     121        goto InvalidTable;
     122  
     123      if ( face->palette_data.num_palette_entries > cpal->num_colors )
     124        goto InvalidTable;
     125  
     126      cpal->color_indices = p;
     127      cpal->colors        = (FT_Byte*)( table + colors_offset );
     128  
     129      if ( cpal->version == 1 )
     130      {
     131        FT_ULong    type_offset, label_offset, entry_label_offset;
     132        FT_UShort*  array = NULL;
     133        FT_UShort*  limit;
     134        FT_UShort*  q;
     135  
     136  
     137        if ( CPAL_V0_HEADER_BASE_SIZE             +
     138             face->palette_data.num_palettes * 2U +
     139             3U * 4                               > table_size )
     140          goto InvalidTable;
     141  
     142        p += face->palette_data.num_palettes * 2U;
     143  
     144        type_offset        = FT_NEXT_ULONG( p );
     145        label_offset       = FT_NEXT_ULONG( p );
     146        entry_label_offset = FT_NEXT_ULONG( p );
     147  
     148        if ( type_offset )
     149        {
     150          if ( type_offset >= table_size )
     151            goto InvalidTable;
     152          if ( face->palette_data.num_palettes * 2U >
     153                 table_size - type_offset )
     154            goto InvalidTable;
     155  
     156          if ( FT_QNEW_ARRAY( array, face->palette_data.num_palettes ) )
     157            goto NoCpal;
     158  
     159          p     = table + type_offset;
     160          q     = array;
     161          limit = q + face->palette_data.num_palettes;
     162  
     163          while ( q < limit )
     164            *q++ = FT_NEXT_USHORT( p );
     165  
     166          face->palette_data.palette_flags = array;
     167        }
     168  
     169        if ( label_offset )
     170        {
     171          if ( label_offset >= table_size )
     172            goto InvalidTable;
     173          if ( face->palette_data.num_palettes * 2U >
     174                 table_size - label_offset )
     175            goto InvalidTable;
     176  
     177          if ( FT_QNEW_ARRAY( array, face->palette_data.num_palettes ) )
     178            goto NoCpal;
     179  
     180          p     = table + label_offset;
     181          q     = array;
     182          limit = q + face->palette_data.num_palettes;
     183  
     184          while ( q < limit )
     185            *q++ = FT_NEXT_USHORT( p );
     186  
     187          face->palette_data.palette_name_ids = array;
     188        }
     189  
     190        if ( entry_label_offset )
     191        {
     192          if ( entry_label_offset >= table_size )
     193            goto InvalidTable;
     194          if ( face->palette_data.num_palette_entries * 2U >
     195                 table_size - entry_label_offset )
     196            goto InvalidTable;
     197  
     198          if ( FT_QNEW_ARRAY( array, face->palette_data.num_palette_entries ) )
     199            goto NoCpal;
     200  
     201          p     = table + entry_label_offset;
     202          q     = array;
     203          limit = q + face->palette_data.num_palette_entries;
     204  
     205          while ( q < limit )
     206            *q++ = FT_NEXT_USHORT( p );
     207  
     208          face->palette_data.palette_entry_name_ids = array;
     209        }
     210      }
     211  
     212      cpal->table      = table;
     213      cpal->table_size = table_size;
     214  
     215      face->cpal = cpal;
     216  
     217      /* set up default palette */
     218      if ( FT_NEW_ARRAY( face->palette,
     219                         face->palette_data.num_palette_entries ) )
     220        goto NoCpal;
     221  
     222      if ( tt_face_palette_set( face, 0 ) )
     223        goto InvalidTable;
     224  
     225      return FT_Err_Ok;
     226  
     227    InvalidTable:
     228      error = FT_THROW( Invalid_Table );
     229  
     230    NoCpal:
     231      FT_FRAME_RELEASE( table );
     232      FT_FREE( cpal );
     233  
     234      face->cpal = NULL;
     235  
     236      /* arrays in `face->palette_data' and `face->palette' */
     237      /* are freed in `sfnt_done_face'                      */
     238  
     239      return error;
     240    }
     241  
     242  
     243    FT_LOCAL_DEF( void )
     244    tt_face_free_cpal( TT_Face  face )
     245    {
     246      FT_Stream  stream = face->root.stream;
     247      FT_Memory  memory = face->root.memory;
     248  
     249      Cpal*  cpal = (Cpal*)face->cpal;
     250  
     251  
     252      if ( cpal )
     253      {
     254        FT_FRAME_RELEASE( cpal->table );
     255        FT_FREE( cpal );
     256      }
     257    }
     258  
     259  
     260    FT_LOCAL_DEF( FT_Error )
     261    tt_face_palette_set( TT_Face  face,
     262                         FT_UInt  palette_index )
     263    {
     264      Cpal*  cpal = (Cpal*)face->cpal;
     265  
     266      FT_Byte*   offset;
     267      FT_Byte*   p;
     268  
     269      FT_Color*  q;
     270      FT_Color*  limit;
     271  
     272      FT_UShort  color_index;
     273  
     274  
     275      if ( !cpal || palette_index >= face->palette_data.num_palettes )
     276        return FT_THROW( Invalid_Argument );
     277  
     278      offset      = cpal->color_indices + 2 * palette_index;
     279      color_index = FT_PEEK_USHORT( offset );
     280  
     281      if ( color_index + face->palette_data.num_palette_entries >
     282             cpal->num_colors )
     283        return FT_THROW( Invalid_Table );
     284  
     285      p     = cpal->colors + COLOR_SIZE * color_index;
     286      q     = face->palette;
     287      limit = q + face->palette_data.num_palette_entries;
     288  
     289      while ( q < limit )
     290      {
     291        q->blue  = FT_NEXT_BYTE( p );
     292        q->green = FT_NEXT_BYTE( p );
     293        q->red   = FT_NEXT_BYTE( p );
     294        q->alpha = FT_NEXT_BYTE( p );
     295  
     296        q++;
     297      }
     298  
     299      return FT_Err_Ok;
     300    }
     301  
     302  
     303  #else /* !TT_CONFIG_OPTION_COLOR_LAYERS */
     304  
     305    /* ANSI C doesn't like empty source files */
     306    typedef int  tt_cpal_dummy_;
     307  
     308  #endif /* !TT_CONFIG_OPTION_COLOR_LAYERS */
     309  
     310  /* EOF */