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_SBIX_TABLE_HH 26 #define HB_OT_COLOR_SBIX_TABLE_HH 27 28 #include "hb-open-type-private.hh" 29 30 /* 31 * sbix -- Standard Bitmap Graphics 32 * https://docs.microsoft.com/en-us/typography/opentype/spec/sbix 33 * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6sbix.html 34 */ 35 #define HB_OT_TAG_sbix HB_TAG('s','b','i','x') 36 37 38 namespace OT { 39 40 41 struct SBIXGlyph 42 { 43 HBINT16 xOffset; /* The horizontal (x-axis) offset from the left 44 * edge of the graphic to the glyph’s origin. 45 * That is, the x-coordinate of the point on the 46 * baseline at the left edge of the glyph. */ 47 HBINT16 yOffset; /* The vertical (y-axis) offset from the bottom 48 * edge of the graphic to the glyph’s origin. 49 * That is, the y-coordinate of the point on the 50 * baseline at the left edge of the glyph. */ 51 Tag graphicType; /* Indicates the format of the embedded graphic 52 * data: one of 'jpg ', 'png ' or 'tiff', or the 53 * special format 'dupe'. */ 54 UnsizedArrayOf<HBUINT8> 55 data; /* The actual embedded graphic data. The total 56 * length is inferred from sequential entries in 57 * the glyphDataOffsets array and the fixed size 58 * (8 bytes) of the preceding fields. */ 59 public: 60 DEFINE_SIZE_ARRAY (8, data); 61 }; 62 63 struct SBIXStrike 64 { 65 friend struct sbix; 66 67 inline bool sanitize (hb_sanitize_context_t *c) const 68 { 69 TRACE_SANITIZE (this); 70 return_trace (c->check_struct (this) && 71 imageOffsetsZ.sanitize_shallow (c, c->num_glyphs + 1)); 72 } 73 74 protected: 75 HBUINT16 ppem; /* The PPEM size for which this strike was designed. */ 76 HBUINT16 resolution; /* The device pixel density (in PPI) for which this 77 * strike was designed. (E.g., 96 PPI, 192 PPI.) */ 78 UnsizedArrayOf<LOffsetTo<SBIXGlyph> > 79 imageOffsetsZ; /* Offset from the beginning of the strike data header 80 * to bitmap data for an individual glyph ID. */ 81 public: 82 DEFINE_SIZE_STATIC (8); 83 }; 84 85 struct sbix 86 { 87 static const hb_tag_t tableTag = HB_OT_TAG_sbix; 88 89 inline bool sanitize (hb_sanitize_context_t *c) const 90 { 91 TRACE_SANITIZE (this); 92 return_trace (likely (c->check_struct (this) && strikes.sanitize (c, this))); 93 } 94 95 struct accelerator_t 96 { 97 inline void init (hb_face_t *face) 98 { 99 num_glyphs = hb_face_get_glyph_count (face); 100 101 OT::Sanitizer<OT::sbix> sanitizer; 102 sanitizer.set_num_glyphs (num_glyphs); 103 sbix_blob = sanitizer.sanitize (face->reference_table (HB_OT_TAG_sbix)); 104 sbix_len = hb_blob_get_length (sbix_blob); 105 sbix_table = sbix_blob->as<OT::sbix> (); 106 107 } 108 109 inline void fini (void) 110 { 111 hb_blob_destroy (sbix_blob); 112 } 113 114 inline void dump (void (*callback) (const uint8_t* data, unsigned int length, 115 unsigned int group, unsigned int gid)) const 116 { 117 for (unsigned group = 0; group < sbix_table->strikes.len; ++group) 118 { 119 const SBIXStrike &strike = sbix_table->strikes[group](sbix_table); 120 for (unsigned int glyph = 0; glyph < num_glyphs; ++glyph) 121 if (strike.imageOffsetsZ[glyph + 1] - strike.imageOffsetsZ[glyph] > 0) 122 { 123 const SBIXGlyph &sbixGlyph = strike.imageOffsetsZ[glyph]((const void *) &strike); 124 callback ((const uint8_t*) &sbixGlyph.data, 125 strike.imageOffsetsZ[glyph + 1] - strike.imageOffsetsZ[glyph] - 8, 126 group, glyph); 127 } 128 } 129 } 130 131 private: 132 hb_blob_t *sbix_blob; 133 const sbix *sbix_table; 134 135 unsigned int sbix_len; 136 unsigned int num_glyphs; 137 138 }; 139 140 protected: 141 HBUINT16 version; /* Table version number — set to 1 */ 142 HBUINT16 flags; /* Bit 0: Set to 1. Bit 1: Draw outlines. 143 * Bits 2 to 15: reserved (set to 0). */ 144 LArrayOf<LOffsetTo<SBIXStrike> > 145 strikes; /* Offsets from the beginning of the 'sbix' 146 * table to data for each individual bitmap strike. */ 147 public: 148 DEFINE_SIZE_ARRAY (8, strikes); 149 }; 150 151 } /* namespace OT */ 152 153 #endif /* HB_OT_COLOR_SBIX_TABLE_HH */ | 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_SBIX_TABLE_HH 26 #define HB_OT_COLOR_SBIX_TABLE_HH 27 28 #include "hb-open-type.hh" 29 30 /* 31 * sbix -- Standard Bitmap Graphics 32 * https://docs.microsoft.com/en-us/typography/opentype/spec/sbix 33 * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6sbix.html 34 */ 35 #define HB_OT_TAG_sbix HB_TAG('s','b','i','x') 36 37 38 namespace OT { 39 40 41 struct SBIXGlyph 42 { 43 HBINT16 xOffset; /* The horizontal (x-axis) offset from the left 44 * edge of the graphic to the glyph’s origin. 45 * That is, the x-coordinate of the point on the 46 * baseline at the left edge of the glyph. */ 47 HBINT16 yOffset; /* The vertical (y-axis) offset from the bottom 48 * edge of the graphic to the glyph’s origin. 49 * That is, the y-coordinate of the point on the 50 * baseline at the left edge of the glyph. */ 51 Tag graphicType; /* Indicates the format of the embedded graphic 52 * data: one of 'jpg ', 'png ' or 'tiff', or the 53 * special format 'dupe'. */ 54 UnsizedArrayOf<HBUINT8> 55 data; /* The actual embedded graphic data. The total 56 * length is inferred from sequential entries in 57 * the glyphDataOffsets array and the fixed size 58 * (8 bytes) of the preceding fields. */ 59 public: 60 DEFINE_SIZE_ARRAY (8, data); 61 }; 62 63 struct SBIXStrike 64 { 65 bool sanitize (hb_sanitize_context_t *c) const 66 { 67 TRACE_SANITIZE (this); 68 return_trace (c->check_struct (this) && 69 imageOffsetsZ.sanitize_shallow (c, c->get_num_glyphs () + 1)); 70 } 71 72 hb_blob_t *get_glyph_blob (unsigned int glyph_id, 73 hb_blob_t *sbix_blob, 74 hb_tag_t file_type, 75 int *x_offset, 76 int *y_offset, 77 unsigned int num_glyphs, 78 unsigned int *strike_ppem) const 79 { 80 if (unlikely (!ppem)) return hb_blob_get_empty (); /* To get Null() object out of the way. */ 81 82 unsigned int retry_count = 8; 83 unsigned int sbix_len = sbix_blob->length; 84 unsigned int strike_offset = (const char *) this - (const char *) sbix_blob->data; 85 assert (strike_offset < sbix_len); 86 87 retry: 88 if (unlikely (glyph_id >= num_glyphs || 89 imageOffsetsZ[glyph_id + 1] <= imageOffsetsZ[glyph_id] || 90 imageOffsetsZ[glyph_id + 1] - imageOffsetsZ[glyph_id] <= SBIXGlyph::min_size || 91 (unsigned int) imageOffsetsZ[glyph_id + 1] > sbix_len - strike_offset)) 92 return hb_blob_get_empty (); 93 94 unsigned int glyph_offset = strike_offset + (unsigned int) imageOffsetsZ[glyph_id] + SBIXGlyph::min_size; 95 unsigned int glyph_length = imageOffsetsZ[glyph_id + 1] - imageOffsetsZ[glyph_id] - SBIXGlyph::min_size; 96 97 const SBIXGlyph *glyph = &(this+imageOffsetsZ[glyph_id]); 98 99 if (glyph->graphicType == HB_TAG ('d','u','p','e')) 100 { 101 if (glyph_length >= 2) 102 { 103 glyph_id = *((HBUINT16 *) &glyph->data); 104 if (retry_count--) 105 goto retry; 106 } 107 return hb_blob_get_empty (); 108 } 109 110 if (unlikely (file_type != glyph->graphicType)) 111 return hb_blob_get_empty (); 112 113 if (strike_ppem) *strike_ppem = ppem; 114 if (x_offset) *x_offset = glyph->xOffset; 115 if (y_offset) *y_offset = glyph->yOffset; 116 return hb_blob_create_sub_blob (sbix_blob, glyph_offset, glyph_length); 117 } 118 119 public: 120 HBUINT16 ppem; /* The PPEM size for which this strike was designed. */ 121 HBUINT16 resolution; /* The device pixel density (in PPI) for which this 122 * strike was designed. (E.g., 96 PPI, 192 PPI.) */ 123 protected: 124 UnsizedArrayOf<LOffsetTo<SBIXGlyph> > 125 imageOffsetsZ; /* Offset from the beginning of the strike data header 126 * to bitmap data for an individual glyph ID. */ 127 public: 128 DEFINE_SIZE_STATIC (8); 129 }; 130 131 struct sbix 132 { 133 static constexpr hb_tag_t tableTag = HB_OT_TAG_sbix; 134 135 bool has_data () const { return version; } 136 137 const SBIXStrike &get_strike (unsigned int i) const { return this+strikes[i]; } 138 139 struct accelerator_t 140 { 141 void init (hb_face_t *face) 142 { 143 table = hb_sanitize_context_t().reference_table<sbix> (face); 144 num_glyphs = face->get_num_glyphs (); 145 } 146 void fini () { table.destroy (); } 147 148 bool has_data () const { return table->has_data (); } 149 150 bool get_extents (hb_font_t *font, 151 hb_codepoint_t glyph, 152 hb_glyph_extents_t *extents) const 153 { 154 /* We only support PNG right now, and following function checks type. */ 155 return get_png_extents (font, glyph, extents); 156 } 157 158 hb_blob_t *reference_png (hb_font_t *font, 159 hb_codepoint_t glyph_id, 160 int *x_offset, 161 int *y_offset, 162 unsigned int *available_ppem) const 163 { 164 return choose_strike (font).get_glyph_blob (glyph_id, table.get_blob (), 165 HB_TAG ('p','n','g',' '), 166 x_offset, y_offset, 167 num_glyphs, available_ppem); 168 } 169 170 private: 171 172 const SBIXStrike &choose_strike (hb_font_t *font) const 173 { 174 unsigned count = table->strikes.len; 175 if (unlikely (!count)) 176 return Null(SBIXStrike); 177 178 unsigned int requested_ppem = MAX (font->x_ppem, font->y_ppem); 179 if (!requested_ppem) 180 requested_ppem = 1<<30; /* Choose largest strike. */ 181 /* TODO Add DPI sensitivity as well? */ 182 unsigned int best_i = 0; 183 unsigned int best_ppem = table->get_strike (0).ppem; 184 185 for (unsigned int i = 1; i < count; i++) 186 { 187 unsigned int ppem = (table->get_strike (i)).ppem; 188 if ((requested_ppem <= ppem && ppem < best_ppem) || 189 (requested_ppem > best_ppem && ppem > best_ppem)) 190 { 191 best_i = i; 192 best_ppem = ppem; 193 } 194 } 195 196 return table->get_strike (best_i); 197 } 198 199 struct PNGHeader 200 { 201 HBUINT8 signature[8]; 202 struct 203 { 204 struct 205 { 206 HBUINT32 length; 207 Tag type; 208 } header; 209 HBUINT32 width; 210 HBUINT32 height; 211 HBUINT8 bitDepth; 212 HBUINT8 colorType; 213 HBUINT8 compressionMethod; 214 HBUINT8 filterMethod; 215 HBUINT8 interlaceMethod; 216 } IHDR; 217 218 public: 219 DEFINE_SIZE_STATIC (29); 220 }; 221 222 bool get_png_extents (hb_font_t *font, 223 hb_codepoint_t glyph, 224 hb_glyph_extents_t *extents) const 225 { 226 /* Following code is safe to call even without data. 227 * But faster to short-circuit. */ 228 if (!has_data ()) 229 return false; 230 231 int x_offset = 0, y_offset = 0; 232 unsigned int strike_ppem = 0; 233 hb_blob_t *blob = reference_png (font, glyph, &x_offset, &y_offset, &strike_ppem); 234 235 const PNGHeader &png = *blob->as<PNGHeader>(); 236 237 extents->x_bearing = x_offset; 238 extents->y_bearing = y_offset; 239 extents->width = png.IHDR.width; 240 extents->height = png.IHDR.height; 241 242 /* Convert to font units. */ 243 if (strike_ppem) 244 { 245 double scale = font->face->get_upem () / (double) strike_ppem; 246 extents->x_bearing = round (extents->x_bearing * scale); 247 extents->y_bearing = round (extents->y_bearing * scale); 248 extents->width = round (extents->width * scale); 249 extents->height = round (extents->height * scale); 250 } 251 252 hb_blob_destroy (blob); 253 254 return strike_ppem; 255 } 256 257 private: 258 hb_blob_ptr_t<sbix> table; 259 260 unsigned int num_glyphs; 261 }; 262 263 bool sanitize (hb_sanitize_context_t *c) const 264 { 265 TRACE_SANITIZE (this); 266 return_trace (likely (c->check_struct (this) && 267 version >= 1 && 268 strikes.sanitize (c, this))); 269 } 270 271 protected: 272 HBUINT16 version; /* Table version number — set to 1 */ 273 HBUINT16 flags; /* Bit 0: Set to 1. Bit 1: Draw outlines. 274 * Bits 2 to 15: reserved (set to 0). */ 275 LOffsetLArrayOf<SBIXStrike> 276 strikes; /* Offsets from the beginning of the 'sbix' 277 * table to data for each individual bitmap strike. */ 278 public: 279 DEFINE_SIZE_ARRAY (8, strikes); 280 }; 281 282 struct sbix_accelerator_t : sbix::accelerator_t {}; 283 284 } /* namespace OT */ 285 286 #endif /* HB_OT_COLOR_SBIX_TABLE_HH */ |