1 /*
   2  * Copyright © 2018  Ebrahim Byagowi
   3  *
   4  *  This is part of HarfBuzz, a text shaping library.
   5  *
   6  * Permission is hereby granted, without written agreement and without
   7  * license or royalty fees, to use, copy, modify, and distribute this
   8  * software and its documentation for any purpose, provided that the
   9  * above copyright notice and the following two paragraphs appear in
  10  * all copies of this software.
  11  *
  12  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
  13  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
  14  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
  15  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
  16  * DAMAGE.
  17  *
  18  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
  19  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  20  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  21  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  23  */
  24 
  25 #ifndef HB_OT_COLOR_COLR_TABLE_HH
  26 #define HB_OT_COLOR_COLR_TABLE_HH
  27 
  28 #include "hb-open-type.hh"
  29 
  30 /*
  31  * COLR -- Color
  32  * https://docs.microsoft.com/en-us/typography/opentype/spec/colr
  33  */
  34 #define HB_OT_TAG_COLR HB_TAG('C','O','L','R')
  35 
  36 
  37 namespace OT {
  38 
  39 
  40 struct LayerRecord
  41 {
  42   bool sanitize (hb_sanitize_context_t *c) const
  43   {
  44     TRACE_SANITIZE (this);
  45     return_trace (c->check_struct (this));
  46   }
  47 
  48   public:
  49   GlyphID       glyphId;        /* Glyph ID of layer glyph */
  50   Index         colorIdx;       /* Index value to use with a
  51                                  * selected color palette.
  52                                  * An index value of 0xFFFF
  53                                  * is a special case indicating
  54                                  * that the text foreground
  55                                  * color (defined by a
  56                                  * higher-level client) should
  57                                  * be used and shall not be
  58                                  * treated as actual index
  59                                  * into CPAL ColorRecord array. */
  60   public:
  61   DEFINE_SIZE_STATIC (4);
  62 };
  63 
  64 struct BaseGlyphRecord
  65 {
  66   int cmp (hb_codepoint_t g) const
  67   { return g < glyphId ? -1 : g > glyphId ? 1 : 0; }
  68 
  69   bool sanitize (hb_sanitize_context_t *c) const
  70   {
  71     TRACE_SANITIZE (this);
  72     return_trace (likely (c->check_struct (this)));
  73   }
  74 
  75   public:
  76   GlyphID       glyphId;        /* Glyph ID of reference glyph */
  77   HBUINT16      firstLayerIdx;  /* Index (from beginning of
  78                                  * the Layer Records) to the
  79                                  * layer record. There will be
  80                                  * numLayers consecutive entries
  81                                  * for this base glyph. */
  82   HBUINT16      numLayers;      /* Number of color layers
  83                                  * associated with this glyph */
  84   public:
  85   DEFINE_SIZE_STATIC (6);
  86 };
  87 
  88 struct COLR
  89 {
  90   static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR;
  91 
  92   bool has_data () const { return numBaseGlyphs; }
  93 
  94   unsigned int get_glyph_layers (hb_codepoint_t       glyph,
  95                                  unsigned int         start_offset,
  96                                  unsigned int        *count, /* IN/OUT.  May be NULL. */
  97                                  hb_ot_color_layer_t *layers /* OUT.     May be NULL. */) const
  98   {
  99     const BaseGlyphRecord &record = (this+baseGlyphsZ).bsearch (numBaseGlyphs, glyph);
 100 
 101     hb_array_t<const LayerRecord> all_layers ((this+layersZ).arrayZ, numLayers);
 102     hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx,
 103                                                                        record.numLayers);
 104     if (count)
 105     {
 106       hb_array_t<const LayerRecord> segment_layers = glyph_layers.sub_array (start_offset, *count);
 107       *count = segment_layers.length;
 108       for (unsigned int i = 0; i < segment_layers.length; i++)
 109       {
 110         layers[i].glyph = segment_layers.arrayZ[i].glyphId;
 111         layers[i].color_index = segment_layers.arrayZ[i].colorIdx;
 112       }
 113     }
 114     return glyph_layers.length;
 115   }
 116 
 117   bool sanitize (hb_sanitize_context_t *c) const
 118   {
 119     TRACE_SANITIZE (this);
 120     return_trace (likely (c->check_struct (this) &&
 121                           (this+baseGlyphsZ).sanitize (c, numBaseGlyphs) &&
 122                           (this+layersZ).sanitize (c, numLayers)));
 123   }
 124 
 125   protected:
 126   HBUINT16      version;        /* Table version number (starts at 0). */
 127   HBUINT16      numBaseGlyphs;  /* Number of Base Glyph Records. */
 128   LNNOffsetTo<SortedUnsizedArrayOf<BaseGlyphRecord> >
 129                 baseGlyphsZ;    /* Offset to Base Glyph records. */
 130   LNNOffsetTo<UnsizedArrayOf<LayerRecord> >
 131                 layersZ;        /* Offset to Layer Records. */
 132   HBUINT16      numLayers;      /* Number of Layer Records. */
 133   public:
 134   DEFINE_SIZE_STATIC (14);
 135 };
 136 
 137 } /* namespace OT */
 138 
 139 
 140 #endif /* HB_OT_COLOR_COLR_TABLE_HH */