tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ttcpal.c (7964B)


      1 /****************************************************************************
      2 *
      3 * ttcpal.c
      4 *
      5 *   TrueType and OpenType color palette support (body).
      6 *
      7 * Copyright (C) 2018-2025 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 */