1 /*
   2  * Copyright © 2018  Google, Inc.
   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  * Google Author(s): Behdad Esfahbod
  25  */
  26 
  27 #include "hb.hh"
  28 
  29 #include "hb-ot-name-table.hh"
  30 
  31 #include "hb-ot-face.hh"
  32 #include "hb-utf.hh"
  33 
  34 
  35 /**
  36  * SECTION:hb-ot-name
  37  * @title: hb-ot-name
  38  * @short_description: OpenType font name information
  39  * @include: hb-ot.h
  40  *
  41  * Functions for fetching name strings from OpenType fonts.
  42  **/
  43 
  44 
  45 /**
  46  * hb_ot_name_list_names:
  47  * @face: font face.
  48  * @num_entries: (out) (allow-none): number of returned entries.
  49  *
  50  * Enumerates all available name IDs and language combinations. Returned
  51  * array is owned by the @face and should not be modified.  It can be
  52  * used as long as @face is alive.
  53  *
  54  * Returns: (out) (transfer none) (array length=num_entries): Array of available name entries.
  55  * Since: 2.1.0
  56  **/
  57 const hb_ot_name_entry_t *
  58 hb_ot_name_list_names (hb_face_t    *face,
  59                        unsigned int *num_entries /* OUT */)
  60 {
  61   const OT::name_accelerator_t &name = *face->table.name;
  62   if (num_entries) *num_entries = name.names.length;
  63   return (const hb_ot_name_entry_t *) name.names;
  64 }
  65 
  66 
  67 template <typename in_utf_t, typename out_utf_t>
  68 static inline unsigned int
  69 hb_ot_name_convert_utf (hb_bytes_t                       bytes,
  70                         unsigned int                    *text_size /* IN/OUT */,
  71                         typename out_utf_t::codepoint_t *text /* OUT */)
  72 {
  73   unsigned int src_len = bytes.length / sizeof (typename in_utf_t::codepoint_t);
  74   const typename in_utf_t::codepoint_t *src = (const typename in_utf_t::codepoint_t *) bytes.arrayZ;
  75   const typename in_utf_t::codepoint_t *src_end = src + src_len;
  76 
  77   typename out_utf_t::codepoint_t *dst = text;
  78 
  79   hb_codepoint_t unicode;
  80   const hb_codepoint_t replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
  81 
  82   if (text_size && *text_size)
  83   {
  84     (*text_size)--; /* Same room for NUL-termination. */
  85     const typename out_utf_t::codepoint_t *dst_end = text + *text_size;
  86 
  87     while (src < src_end && dst < dst_end)
  88     {
  89       const typename in_utf_t::codepoint_t *src_next = in_utf_t::next (src, src_end, &unicode, replacement);
  90       typename out_utf_t::codepoint_t *dst_next = out_utf_t::encode (dst, dst_end, unicode);
  91       if (dst_next == dst)
  92         break; /* Out-of-room. */
  93 
  94       dst = dst_next;
  95       src = src_next;
  96     };
  97 
  98     *text_size = dst - text;
  99     *dst = 0; /* NUL-terminate. */
 100   }
 101 
 102   /* Accumulate length of rest. */
 103   unsigned int dst_len = dst - text;
 104   while (src < src_end)
 105   {
 106     src = in_utf_t::next (src, src_end, &unicode, replacement);
 107     dst_len += out_utf_t::encode_len (unicode);
 108   };
 109   return dst_len;
 110 }
 111 
 112 template <typename utf_t>
 113 static inline unsigned int
 114 hb_ot_name_get_utf (hb_face_t       *face,
 115                     hb_ot_name_id_t  name_id,
 116                     hb_language_t    language,
 117                     unsigned int    *text_size /* IN/OUT */,
 118                     typename utf_t::codepoint_t *text /* OUT */)
 119 {
 120   const OT::name_accelerator_t &name = *face->table.name;
 121 
 122   if (!language)
 123     language = hb_language_from_string ("en", 2);
 124 
 125   unsigned int width;
 126   int idx = name.get_index (name_id, language, &width);
 127   if (idx != -1)
 128   {
 129     hb_bytes_t bytes = name.get_name (idx);
 130 
 131     if (width == 2) /* UTF16-BE */
 132       return hb_ot_name_convert_utf<hb_utf16_be_t, utf_t> (bytes, text_size, text);
 133 
 134     if (width == 1) /* ASCII */
 135       return hb_ot_name_convert_utf<hb_ascii_t, utf_t> (bytes, text_size, text);
 136   }
 137 
 138   if (text_size)
 139   {
 140     if (*text_size)
 141       *text = 0;
 142     *text_size = 0;
 143   }
 144   return 0;
 145 }
 146 
 147 /**
 148  * hb_ot_name_get_utf8:
 149  * @face: font face.
 150  * @name_id: OpenType name identifier to fetch.
 151  * @language: language to fetch the name for.
 152  * @text_size: (inout) (allow-none): input size of @text buffer, and output size of
 153  *                                   text written to buffer.
 154  * @text: (out caller-allocates) (array length=text_size): buffer to write fetched name into.
 155  *
 156  * Fetches a font name from the OpenType 'name' table.
 157  * If @language is #HB_LANGUAGE_INVALID, English ("en") is assumed.
 158  * Returns string in UTF-8 encoding.
 159  *
 160  * Returns: full length of the requested string, or 0 if not found.
 161  * Since: 2.1.0
 162  **/
 163 unsigned int
 164 hb_ot_name_get_utf8 (hb_face_t       *face,
 165                      hb_ot_name_id_t  name_id,
 166                      hb_language_t    language,
 167                      unsigned int    *text_size /* IN/OUT */,
 168                      char            *text      /* OUT */)
 169 {
 170   return hb_ot_name_get_utf<hb_utf8_t> (face, name_id, language, text_size,
 171                                         (hb_utf8_t::codepoint_t *) text);
 172 }
 173 
 174 /**
 175  * hb_ot_name_get_utf16:
 176  * @face: font face.
 177  * @name_id: OpenType name identifier to fetch.
 178  * @language: language to fetch the name for.
 179  * @text_size: (inout) (allow-none): input size of @text buffer, and output size of
 180  *                                   text written to buffer.
 181  * @text: (out caller-allocates) (array length=text_size): buffer to write fetched name into.
 182  *
 183  * Fetches a font name from the OpenType 'name' table.
 184  * If @language is #HB_LANGUAGE_INVALID, English ("en") is assumed.
 185  * Returns string in UTF-16 encoding.
 186  *
 187  * Returns: full length of the requested string, or 0 if not found.
 188  * Since: 2.1.0
 189  **/
 190 unsigned int
 191 hb_ot_name_get_utf16 (hb_face_t       *face,
 192                       hb_ot_name_id_t  name_id,
 193                       hb_language_t    language,
 194                       unsigned int    *text_size /* IN/OUT */,
 195                       uint16_t        *text      /* OUT */)
 196 {
 197   return hb_ot_name_get_utf<hb_utf16_t> (face, name_id, language, text_size, text);
 198 }
 199 
 200 /**
 201  * hb_ot_name_get_utf32:
 202  * @face: font face.
 203  * @name_id: OpenType name identifier to fetch.
 204  * @language: language to fetch the name for.
 205  * @text_size: (inout) (allow-none): input size of @text buffer, and output size of
 206  *                                   text written to buffer.
 207  * @text: (out caller-allocates) (array length=text_size): buffer to write fetched name into.
 208  *
 209  * Fetches a font name from the OpenType 'name' table.
 210  * If @language is #HB_LANGUAGE_INVALID, English ("en") is assumed.
 211  * Returns string in UTF-32 encoding.
 212  *
 213  * Returns: full length of the requested string, or 0 if not found.
 214  * Since: 2.1.0
 215  **/
 216 unsigned int
 217 hb_ot_name_get_utf32 (hb_face_t       *face,
 218                       hb_ot_name_id_t  name_id,
 219                       hb_language_t    language,
 220                       unsigned int    *text_size /* IN/OUT */,
 221                       uint32_t        *text      /* OUT */)
 222 {
 223   return hb_ot_name_get_utf<hb_utf32_t> (face, name_id, language, text_size, text);
 224 }