| File: | jdk/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh |
| Warning: | line 510, column 12 Potential leak of memory pointed to by 'p' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 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): Garret Rieger, Rod Sheeter, Behdad Esfahbod | ||||
| 25 | */ | ||||
| 26 | |||||
| 27 | #include "hb.hh" | ||||
| 28 | #include "hb-open-type.hh" | ||||
| 29 | |||||
| 30 | #include "hb-subset.hh" | ||||
| 31 | |||||
| 32 | #include "hb-open-file.hh" | ||||
| 33 | #include "hb-ot-cmap-table.hh" | ||||
| 34 | #include "hb-ot-glyf-table.hh" | ||||
| 35 | #include "hb-ot-hdmx-table.hh" | ||||
| 36 | #include "hb-ot-head-table.hh" | ||||
| 37 | #include "hb-ot-hhea-table.hh" | ||||
| 38 | #include "hb-ot-hmtx-table.hh" | ||||
| 39 | #include "hb-ot-maxp-table.hh" | ||||
| 40 | #include "hb-ot-color-sbix-table.hh" | ||||
| 41 | #include "hb-ot-color-colr-table.hh" | ||||
| 42 | #include "hb-ot-os2-table.hh" | ||||
| 43 | #include "hb-ot-post-table.hh" | ||||
| 44 | #include "hb-ot-cff1-table.hh" | ||||
| 45 | #include "hb-ot-cff2-table.hh" | ||||
| 46 | #include "hb-ot-vorg-table.hh" | ||||
| 47 | #include "hb-ot-name-table.hh" | ||||
| 48 | #include "hb-ot-color-cbdt-table.hh" | ||||
| 49 | #include "hb-ot-layout-gsub-table.hh" | ||||
| 50 | #include "hb-ot-layout-gpos-table.hh" | ||||
| 51 | #include "hb-ot-var-gvar-table.hh" | ||||
| 52 | #include "hb-ot-var-hvar-table.hh" | ||||
| 53 | |||||
| 54 | |||||
| 55 | static unsigned | ||||
| 56 | _plan_estimate_subset_table_size (hb_subset_plan_t *plan, unsigned table_len) | ||||
| 57 | { | ||||
| 58 | unsigned src_glyphs = plan->source->get_num_glyphs (); | ||||
| 59 | unsigned dst_glyphs = plan->glyphset ()->get_population (); | ||||
| 60 | |||||
| 61 | if (unlikely (!src_glyphs)(__builtin_expect (!!(!src_glyphs), 0))) | ||||
| 62 | return 512 + table_len; | ||||
| 63 | |||||
| 64 | return 512 + (unsigned) (table_len * sqrt ((double) dst_glyphs / src_glyphs)); | ||||
| 65 | } | ||||
| 66 | |||||
| 67 | template<typename TableType> | ||||
| 68 | static bool | ||||
| 69 | _subset (hb_subset_plan_t *plan) | ||||
| 70 | { | ||||
| 71 | bool result = false; | ||||
| 72 | hb_blob_t *source_blob = hb_sanitize_context_t ().reference_table<TableType> (plan->source); | ||||
| 73 | const TableType *table = source_blob->as<TableType> (); | ||||
| 74 | |||||
| 75 | hb_tag_t tag = TableType::tableTag; | ||||
| 76 | if (source_blob->data) | ||||
| |||||
| 77 | { | ||||
| 78 | hb_vector_t<char> buf; | ||||
| 79 | /* TODO Not all tables are glyph-related. 'name' table size for example should not be | ||||
| 80 | * affected by number of glyphs. Accommodate that. */ | ||||
| 81 | unsigned buf_size = _plan_estimate_subset_table_size (plan, source_blob->length); | ||||
| 82 | DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG (tag), buf_size)_hb_debug_msg<(0 +0)> ("SUBSET", (nullptr), nullptr, false , 0, 0, "OT::%c%c%c%c initial estimated table size: %u bytes." , (uint8_t)(((tag)>>24)&0xFF), (uint8_t)(((tag)>> 16)&0xFF), (uint8_t)(((tag)>>8)&0xFF), (uint8_t )((tag)&0xFF), buf_size); | ||||
| 83 | if (unlikely (!buf.alloc (buf_size))(__builtin_expect (!!(!buf.alloc (buf_size)), 0))) | ||||
| 84 | { | ||||
| 85 | DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to allocate %u bytes.", HB_UNTAG (tag), buf_size)_hb_debug_msg<(0 +0)> ("SUBSET", (nullptr), nullptr, false , 0, 0, "OT::%c%c%c%c failed to allocate %u bytes.", (uint8_t )(((tag)>>24)&0xFF), (uint8_t)(((tag)>>16)& 0xFF), (uint8_t)(((tag)>>8)&0xFF), (uint8_t)((tag)& 0xFF), buf_size); | ||||
| 86 | hb_blob_destroy (source_blob); | ||||
| 87 | return false; | ||||
| 88 | } | ||||
| 89 | retry: | ||||
| 90 | hb_serialize_context_t serializer ((void *) buf, buf_size); | ||||
| 91 | serializer.start_serialize<TableType> (); | ||||
| 92 | hb_subset_context_t c (source_blob, plan, &serializer, tag); | ||||
| 93 | bool needed = table->subset (&c); | ||||
| 94 | if (serializer.ran_out_of_room) | ||||
| 95 | { | ||||
| 96 | buf_size += (buf_size >> 1) + 32; | ||||
| 97 | DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.", HB_UNTAG (tag), buf_size)_hb_debug_msg<(0 +0)> ("SUBSET", (nullptr), nullptr, false , 0, 0, "OT::%c%c%c%c ran out of room; reallocating to %u bytes." , (uint8_t)(((tag)>>24)&0xFF), (uint8_t)(((tag)>> 16)&0xFF), (uint8_t)(((tag)>>8)&0xFF), (uint8_t )((tag)&0xFF), buf_size); | ||||
| 98 | if (unlikely (!buf.alloc (buf_size))(__builtin_expect (!!(!buf.alloc (buf_size)), 0))) | ||||
| 99 | { | ||||
| 100 | DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to reallocate %u bytes.", HB_UNTAG (tag), buf_size)_hb_debug_msg<(0 +0)> ("SUBSET", (nullptr), nullptr, false , 0, 0, "OT::%c%c%c%c failed to reallocate %u bytes.", (uint8_t )(((tag)>>24)&0xFF), (uint8_t)(((tag)>>16)& 0xFF), (uint8_t)(((tag)>>8)&0xFF), (uint8_t)((tag)& 0xFF), buf_size); | ||||
| 101 | hb_blob_destroy (source_blob); | ||||
| 102 | return false; | ||||
| 103 | } | ||||
| 104 | goto retry; | ||||
| 105 | } | ||||
| 106 | serializer.end_serialize (); | ||||
| 107 | |||||
| 108 | result = !serializer.in_error (); | ||||
| 109 | |||||
| 110 | if (result
| ||||
| 111 | { | ||||
| 112 | if (needed
| ||||
| 113 | { | ||||
| 114 | hb_blob_t *dest_blob = serializer.copy_blob (); | ||||
| 115 | DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c final subset table size: %u bytes.", HB_UNTAG (tag), dest_blob->length)_hb_debug_msg<(0 +0)> ("SUBSET", (nullptr), nullptr, false , 0, 0, "OT::%c%c%c%c final subset table size: %u bytes.", (uint8_t )(((tag)>>24)&0xFF), (uint8_t)(((tag)>>16)& 0xFF), (uint8_t)(((tag)>>8)&0xFF), (uint8_t)((tag)& 0xFF), dest_blob->length); | ||||
| 116 | result = c.plan->add_table (tag, dest_blob); | ||||
| 117 | hb_blob_destroy (dest_blob); | ||||
| 118 | } | ||||
| 119 | else | ||||
| 120 | { | ||||
| 121 | DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset table subsetted to empty.", HB_UNTAG (tag))_hb_debug_msg<(0 +0)> ("SUBSET", (nullptr), nullptr, false , 0, 0, "OT::%c%c%c%c::subset table subsetted to empty.", (uint8_t )(((tag)>>24)&0xFF), (uint8_t)(((tag)>>16)& 0xFF), (uint8_t)(((tag)>>8)&0xFF), (uint8_t)((tag)& 0xFF)); | ||||
| 122 | } | ||||
| 123 | } | ||||
| 124 | } | ||||
| 125 | else | ||||
| 126 | DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag))_hb_debug_msg<(0 +0)> ("SUBSET", (nullptr), nullptr, false , 0, 0, "OT::%c%c%c%c::subset sanitize failed on source table." , (uint8_t)(((tag)>>24)&0xFF), (uint8_t)(((tag)>> 16)&0xFF), (uint8_t)(((tag)>>8)&0xFF), (uint8_t )((tag)&0xFF)); | ||||
| 127 | |||||
| 128 | hb_blob_destroy (source_blob); | ||||
| 129 | DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset %s", HB_UNTAG (tag), result ? "success" : "FAILED!")_hb_debug_msg<(0 +0)> ("SUBSET", (nullptr), nullptr, false , 0, 0, "OT::%c%c%c%c::subset %s", (uint8_t)(((tag)>>24 )&0xFF), (uint8_t)(((tag)>>16)&0xFF), (uint8_t) (((tag)>>8)&0xFF), (uint8_t)((tag)&0xFF), result ? "success" : "FAILED!"); | ||||
| 130 | return result; | ||||
| 131 | } | ||||
| 132 | |||||
| 133 | static bool | ||||
| 134 | _is_table_present (hb_face_t *source, hb_tag_t tag) | ||||
| 135 | { | ||||
| 136 | hb_tag_t table_tags[32]; | ||||
| 137 | unsigned offset = 0, num_tables = ARRAY_LENGTH (table_tags); | ||||
| 138 | while ((hb_face_get_table_tags (source, offset, &num_tables, table_tags), num_tables)) | ||||
| 139 | { | ||||
| 140 | for (unsigned i = 0; i < num_tables; ++i) | ||||
| 141 | if (table_tags[i] == tag) | ||||
| 142 | return true; | ||||
| 143 | offset += num_tables; | ||||
| 144 | } | ||||
| 145 | return false; | ||||
| 146 | } | ||||
| 147 | |||||
| 148 | static bool | ||||
| 149 | _should_drop_table (hb_subset_plan_t *plan, hb_tag_t tag) | ||||
| 150 | { | ||||
| 151 | if (plan->drop_tables->has (tag)) | ||||
| 152 | return true; | ||||
| 153 | |||||
| 154 | switch (tag) | ||||
| 155 | { | ||||
| 156 | case HB_TAG ('c','v','a','r')((hb_tag_t)((((uint32_t)('c')&0xFF)<<24)|(((uint32_t )('v')&0xFF)<<16)|(((uint32_t)('a')&0xFF)<< 8)|((uint32_t)('r')&0xFF))): /* hint table, fallthrough */ | ||||
| 157 | case HB_TAG ('c','v','t',' ')((hb_tag_t)((((uint32_t)('c')&0xFF)<<24)|(((uint32_t )('v')&0xFF)<<16)|(((uint32_t)('t')&0xFF)<< 8)|((uint32_t)(' ')&0xFF))): /* hint table, fallthrough */ | ||||
| 158 | case HB_TAG ('f','p','g','m')((hb_tag_t)((((uint32_t)('f')&0xFF)<<24)|(((uint32_t )('p')&0xFF)<<16)|(((uint32_t)('g')&0xFF)<< 8)|((uint32_t)('m')&0xFF))): /* hint table, fallthrough */ | ||||
| 159 | case HB_TAG ('p','r','e','p')((hb_tag_t)((((uint32_t)('p')&0xFF)<<24)|(((uint32_t )('r')&0xFF)<<16)|(((uint32_t)('e')&0xFF)<< 8)|((uint32_t)('p')&0xFF))): /* hint table, fallthrough */ | ||||
| 160 | case HB_TAG ('h','d','m','x')((hb_tag_t)((((uint32_t)('h')&0xFF)<<24)|(((uint32_t )('d')&0xFF)<<16)|(((uint32_t)('m')&0xFF)<< 8)|((uint32_t)('x')&0xFF))): /* hint table, fallthrough */ | ||||
| 161 | case HB_TAG ('V','D','M','X')((hb_tag_t)((((uint32_t)('V')&0xFF)<<24)|(((uint32_t )('D')&0xFF)<<16)|(((uint32_t)('M')&0xFF)<< 8)|((uint32_t)('X')&0xFF))): /* hint table, fallthrough */ | ||||
| 162 | return plan->drop_hints; | ||||
| 163 | |||||
| 164 | #ifdef HB_NO_SUBSET_LAYOUT | ||||
| 165 | // Drop Layout Tables if requested. | ||||
| 166 | case HB_OT_TAG_GDEF((hb_tag_t)((((uint32_t)('G')&0xFF)<<24)|(((uint32_t )('D')&0xFF)<<16)|(((uint32_t)('E')&0xFF)<< 8)|((uint32_t)('F')&0xFF))): | ||||
| 167 | case HB_OT_TAG_GPOS((hb_tag_t)((((uint32_t)('G')&0xFF)<<24)|(((uint32_t )('P')&0xFF)<<16)|(((uint32_t)('O')&0xFF)<< 8)|((uint32_t)('S')&0xFF))): | ||||
| 168 | case HB_OT_TAG_GSUB((hb_tag_t)((((uint32_t)('G')&0xFF)<<24)|(((uint32_t )('S')&0xFF)<<16)|(((uint32_t)('U')&0xFF)<< 8)|((uint32_t)('B')&0xFF))): | ||||
| 169 | case HB_TAG ('m','o','r','x')((hb_tag_t)((((uint32_t)('m')&0xFF)<<24)|(((uint32_t )('o')&0xFF)<<16)|(((uint32_t)('r')&0xFF)<< 8)|((uint32_t)('x')&0xFF))): | ||||
| 170 | case HB_TAG ('m','o','r','t')((hb_tag_t)((((uint32_t)('m')&0xFF)<<24)|(((uint32_t )('o')&0xFF)<<16)|(((uint32_t)('r')&0xFF)<< 8)|((uint32_t)('t')&0xFF))): | ||||
| 171 | case HB_TAG ('k','e','r','x')((hb_tag_t)((((uint32_t)('k')&0xFF)<<24)|(((uint32_t )('e')&0xFF)<<16)|(((uint32_t)('r')&0xFF)<< 8)|((uint32_t)('x')&0xFF))): | ||||
| 172 | case HB_TAG ('k','e','r','n')((hb_tag_t)((((uint32_t)('k')&0xFF)<<24)|(((uint32_t )('e')&0xFF)<<16)|(((uint32_t)('r')&0xFF)<< 8)|((uint32_t)('n')&0xFF))): | ||||
| 173 | return true; | ||||
| 174 | #endif | ||||
| 175 | |||||
| 176 | default: | ||||
| 177 | return false; | ||||
| 178 | } | ||||
| 179 | } | ||||
| 180 | |||||
| 181 | static bool | ||||
| 182 | _subset_table (hb_subset_plan_t *plan, hb_tag_t tag) | ||||
| 183 | { | ||||
| 184 | DEBUG_MSG (SUBSET, nullptr, "subset %c%c%c%c", HB_UNTAG (tag))_hb_debug_msg<(0 +0)> ("SUBSET", (nullptr), nullptr, false , 0, 0, "subset %c%c%c%c", (uint8_t)(((tag)>>24)&0xFF ), (uint8_t)(((tag)>>16)&0xFF), (uint8_t)(((tag)>> 8)&0xFF), (uint8_t)((tag)&0xFF)); | ||||
| 185 | switch (tag) | ||||
| 186 | { | ||||
| 187 | case HB_OT_TAG_glyf((hb_tag_t)((((uint32_t)('g')&0xFF)<<24)|(((uint32_t )('l')&0xFF)<<16)|(((uint32_t)('y')&0xFF)<< 8)|((uint32_t)('f')&0xFF))): return _subset<const OT::glyf> (plan); | ||||
| 188 | case HB_OT_TAG_hdmx((hb_tag_t)((((uint32_t)('h')&0xFF)<<24)|(((uint32_t )('d')&0xFF)<<16)|(((uint32_t)('m')&0xFF)<< 8)|((uint32_t)('x')&0xFF))): return _subset<const OT::hdmx> (plan); | ||||
| 189 | case HB_OT_TAG_name((hb_tag_t)((((uint32_t)('n')&0xFF)<<24)|(((uint32_t )('a')&0xFF)<<16)|(((uint32_t)('m')&0xFF)<< 8)|((uint32_t)('e')&0xFF))): return _subset<const OT::name> (plan); | ||||
| 190 | case HB_OT_TAG_head((hb_tag_t)((((uint32_t)('h')&0xFF)<<24)|(((uint32_t )('e')&0xFF)<<16)|(((uint32_t)('a')&0xFF)<< 8)|((uint32_t)('d')&0xFF))): | ||||
| 191 | if (_is_table_present (plan->source, HB_OT_TAG_glyf((hb_tag_t)((((uint32_t)('g')&0xFF)<<24)|(((uint32_t )('l')&0xFF)<<16)|(((uint32_t)('y')&0xFF)<< 8)|((uint32_t)('f')&0xFF)))) && !_should_drop_table (plan, HB_OT_TAG_glyf((hb_tag_t)((((uint32_t)('g')&0xFF)<<24)|(((uint32_t )('l')&0xFF)<<16)|(((uint32_t)('y')&0xFF)<< 8)|((uint32_t)('f')&0xFF))))) | ||||
| 192 | return true; /* skip head, handled by glyf */ | ||||
| 193 | return _subset<const OT::head> (plan); | ||||
| 194 | case HB_OT_TAG_hhea((hb_tag_t)((((uint32_t)('h')&0xFF)<<24)|(((uint32_t )('h')&0xFF)<<16)|(((uint32_t)('e')&0xFF)<< 8)|((uint32_t)('a')&0xFF))): return true; /* skip hhea, handled by hmtx */ | ||||
| 195 | case HB_OT_TAG_hmtx((hb_tag_t)((((uint32_t)('h')&0xFF)<<24)|(((uint32_t )('m')&0xFF)<<16)|(((uint32_t)('t')&0xFF)<< 8)|((uint32_t)('x')&0xFF))): return _subset<const OT::hmtx> (plan); | ||||
| 196 | case HB_OT_TAG_vhea((hb_tag_t)((((uint32_t)('v')&0xFF)<<24)|(((uint32_t )('h')&0xFF)<<16)|(((uint32_t)('e')&0xFF)<< 8)|((uint32_t)('a')&0xFF))): return true; /* skip vhea, handled by vmtx */ | ||||
| 197 | case HB_OT_TAG_vmtx((hb_tag_t)((((uint32_t)('v')&0xFF)<<24)|(((uint32_t )('m')&0xFF)<<16)|(((uint32_t)('t')&0xFF)<< 8)|((uint32_t)('x')&0xFF))): return _subset<const OT::vmtx> (plan); | ||||
| 198 | case HB_OT_TAG_maxp((hb_tag_t)((((uint32_t)('m')&0xFF)<<24)|(((uint32_t )('a')&0xFF)<<16)|(((uint32_t)('x')&0xFF)<< 8)|((uint32_t)('p')&0xFF))): return _subset<const OT::maxp> (plan); | ||||
| 199 | case HB_OT_TAG_sbix((hb_tag_t)((((uint32_t)('s')&0xFF)<<24)|(((uint32_t )('b')&0xFF)<<16)|(((uint32_t)('i')&0xFF)<< 8)|((uint32_t)('x')&0xFF))): return _subset<const OT::sbix> (plan); | ||||
| 200 | case HB_OT_TAG_loca((hb_tag_t)((((uint32_t)('l')&0xFF)<<24)|(((uint32_t )('o')&0xFF)<<16)|(((uint32_t)('c')&0xFF)<< 8)|((uint32_t)('a')&0xFF))): return true; /* skip loca, handled by glyf */ | ||||
| 201 | case HB_OT_TAG_cmap((hb_tag_t)((((uint32_t)('c')&0xFF)<<24)|(((uint32_t )('m')&0xFF)<<16)|(((uint32_t)('a')&0xFF)<< 8)|((uint32_t)('p')&0xFF))): return _subset<const OT::cmap> (plan); | ||||
| 202 | case HB_OT_TAG_OS2((hb_tag_t)((((uint32_t)('O')&0xFF)<<24)|(((uint32_t )('S')&0xFF)<<16)|(((uint32_t)('/')&0xFF)<< 8)|((uint32_t)('2')&0xFF))) : return _subset<const OT::OS2 > (plan); | ||||
| 203 | case HB_OT_TAG_post((hb_tag_t)((((uint32_t)('p')&0xFF)<<24)|(((uint32_t )('o')&0xFF)<<16)|(((uint32_t)('s')&0xFF)<< 8)|((uint32_t)('t')&0xFF))): return _subset<const OT::post> (plan); | ||||
| 204 | case HB_OT_TAG_COLR((hb_tag_t)((((uint32_t)('C')&0xFF)<<24)|(((uint32_t )('O')&0xFF)<<16)|(((uint32_t)('L')&0xFF)<< 8)|((uint32_t)('R')&0xFF))): return _subset<const OT::COLR> (plan); | ||||
| 205 | case HB_OT_TAG_CBLC((hb_tag_t)((((uint32_t)('C')&0xFF)<<24)|(((uint32_t )('B')&0xFF)<<16)|(((uint32_t)('L')&0xFF)<< 8)|((uint32_t)('C')&0xFF))): return _subset<const OT::CBLC> (plan); | ||||
| 206 | case HB_OT_TAG_CBDT((hb_tag_t)((((uint32_t)('C')&0xFF)<<24)|(((uint32_t )('B')&0xFF)<<16)|(((uint32_t)('D')&0xFF)<< 8)|((uint32_t)('T')&0xFF))): return true; /* skip CBDT, handled by CBLC */ | ||||
| 207 | |||||
| 208 | #ifndef HB_NO_SUBSET_CFF | ||||
| 209 | case HB_OT_TAG_cff1((hb_tag_t)((((uint32_t)('C')&0xFF)<<24)|(((uint32_t )('F')&0xFF)<<16)|(((uint32_t)('F')&0xFF)<< 8)|((uint32_t)(' ')&0xFF))): return _subset<const OT::cff1> (plan); | ||||
| 210 | case HB_OT_TAG_cff2((hb_tag_t)((((uint32_t)('C')&0xFF)<<24)|(((uint32_t )('F')&0xFF)<<16)|(((uint32_t)('F')&0xFF)<< 8)|((uint32_t)('2')&0xFF))): return _subset<const OT::cff2> (plan); | ||||
| 211 | case HB_OT_TAG_VORG((hb_tag_t)((((uint32_t)('V')&0xFF)<<24)|(((uint32_t )('O')&0xFF)<<16)|(((uint32_t)('R')&0xFF)<< 8)|((uint32_t)('G')&0xFF))): return _subset<const OT::VORG> (plan); | ||||
| 212 | #endif | ||||
| 213 | |||||
| 214 | #ifndef HB_NO_SUBSET_LAYOUT | ||||
| 215 | case HB_OT_TAG_GDEF((hb_tag_t)((((uint32_t)('G')&0xFF)<<24)|(((uint32_t )('D')&0xFF)<<16)|(((uint32_t)('E')&0xFF)<< 8)|((uint32_t)('F')&0xFF))): return _subset<const OT::GDEF> (plan); | ||||
| 216 | case HB_OT_TAG_GSUB((hb_tag_t)((((uint32_t)('G')&0xFF)<<24)|(((uint32_t )('S')&0xFF)<<16)|(((uint32_t)('U')&0xFF)<< 8)|((uint32_t)('B')&0xFF))): return _subset<const OT::GSUB> (plan); | ||||
| 217 | case HB_OT_TAG_GPOS((hb_tag_t)((((uint32_t)('G')&0xFF)<<24)|(((uint32_t )('P')&0xFF)<<16)|(((uint32_t)('O')&0xFF)<< 8)|((uint32_t)('S')&0xFF))): return _subset<const OT::GPOS> (plan); | ||||
| 218 | case HB_OT_TAG_gvar((hb_tag_t)((((uint32_t)('g')&0xFF)<<24)|(((uint32_t )('v')&0xFF)<<16)|(((uint32_t)('a')&0xFF)<< 8)|((uint32_t)('r')&0xFF))): return _subset<const OT::gvar> (plan); | ||||
| 219 | case HB_OT_TAG_HVAR((hb_tag_t)((((uint32_t)('H')&0xFF)<<24)|(((uint32_t )('V')&0xFF)<<16)|(((uint32_t)('A')&0xFF)<< 8)|((uint32_t)('R')&0xFF))): return _subset<const OT::HVAR> (plan); | ||||
| 220 | case HB_OT_TAG_VVAR((hb_tag_t)((((uint32_t)('V')&0xFF)<<24)|(((uint32_t )('V')&0xFF)<<16)|(((uint32_t)('A')&0xFF)<< 8)|((uint32_t)('R')&0xFF))): return _subset<const OT::VVAR> (plan); | ||||
| 221 | #endif | ||||
| 222 | |||||
| 223 | default: | ||||
| 224 | hb_blob_t *source_table = hb_face_reference_table (plan->source, tag); | ||||
| 225 | bool result = plan->add_table (tag, source_table); | ||||
| 226 | hb_blob_destroy (source_table); | ||||
| 227 | return result; | ||||
| 228 | } | ||||
| 229 | } | ||||
| 230 | |||||
| 231 | /** | ||||
| 232 | * hb_subset: | ||||
| 233 | * @source: font face data to be subset. | ||||
| 234 | * @input: input to use for the subsetting. | ||||
| 235 | * | ||||
| 236 | * Subsets a font according to provided input. | ||||
| 237 | **/ | ||||
| 238 | hb_face_t * | ||||
| 239 | hb_subset (hb_face_t *source, hb_subset_input_t *input) | ||||
| 240 | { | ||||
| 241 | if (unlikely (!input || !source)(__builtin_expect (!!(!input || !source), 0))) return hb_face_get_empty (); | ||||
| 242 | |||||
| 243 | hb_subset_plan_t *plan = hb_subset_plan_create (source, input); | ||||
| 244 | if (unlikely (plan->in_error ())(__builtin_expect (!!(plan->in_error ()), 0))) | ||||
| 245 | return hb_face_get_empty (); | ||||
| 246 | |||||
| 247 | hb_set_t tags_set; | ||||
| 248 | bool success = true; | ||||
| 249 | hb_tag_t table_tags[32]; | ||||
| 250 | unsigned offset = 0, num_tables = ARRAY_LENGTH (table_tags); | ||||
| 251 | while ((hb_face_get_table_tags (source, offset, &num_tables, table_tags), num_tables)) | ||||
| 252 | { | ||||
| 253 | for (unsigned i = 0; i < num_tables; ++i) | ||||
| 254 | { | ||||
| 255 | hb_tag_t tag = table_tags[i]; | ||||
| 256 | if (_should_drop_table (plan, tag) && !tags_set.has (tag)) continue; | ||||
| 257 | tags_set.add (tag); | ||||
| 258 | success = _subset_table (plan, tag); | ||||
| 259 | if (unlikely (!success)(__builtin_expect (!!(!success), 0))) goto end; | ||||
| 260 | } | ||||
| 261 | offset += num_tables; | ||||
| 262 | } | ||||
| 263 | end: | ||||
| 264 | |||||
| 265 | hb_face_t *result = success ? hb_face_reference (plan->dest) : hb_face_get_empty (); | ||||
| 266 | |||||
| 267 | hb_subset_plan_destroy (plan); | ||||
| 268 | return result; | ||||
| 269 | } |
| 1 | /* | |||
| 2 | * Copyright © 2007,2008,2009,2010 Red Hat, Inc. | |||
| 3 | * Copyright © 2012,2018 Google, Inc. | |||
| 4 | * Copyright © 2019 Facebook, Inc. | |||
| 5 | * | |||
| 6 | * This is part of HarfBuzz, a text shaping library. | |||
| 7 | * | |||
| 8 | * Permission is hereby granted, without written agreement and without | |||
| 9 | * license or royalty fees, to use, copy, modify, and distribute this | |||
| 10 | * software and its documentation for any purpose, provided that the | |||
| 11 | * above copyright notice and the following two paragraphs appear in | |||
| 12 | * all copies of this software. | |||
| 13 | * | |||
| 14 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR | |||
| 15 | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES | |||
| 16 | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN | |||
| 17 | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH | |||
| 18 | * DAMAGE. | |||
| 19 | * | |||
| 20 | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, | |||
| 21 | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | |||
| 22 | * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS | |||
| 23 | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO | |||
| 24 | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | |||
| 25 | * | |||
| 26 | * Red Hat Author(s): Behdad Esfahbod | |||
| 27 | * Google Author(s): Behdad Esfahbod | |||
| 28 | * Facebook Author(s): Behdad Esfahbod | |||
| 29 | */ | |||
| 30 | ||||
| 31 | #ifndef HB_SERIALIZE_HH | |||
| 32 | #define HB_SERIALIZE_HH | |||
| 33 | ||||
| 34 | #include "hb.hh" | |||
| 35 | #include "hb-blob.hh" | |||
| 36 | #include "hb-map.hh" | |||
| 37 | #include "hb-pool.hh" | |||
| 38 | ||||
| 39 | ||||
| 40 | /* | |||
| 41 | * Serialize | |||
| 42 | */ | |||
| 43 | ||||
| 44 | struct hb_serialize_context_t | |||
| 45 | { | |||
| 46 | typedef unsigned objidx_t; | |||
| 47 | ||||
| 48 | enum whence_t { | |||
| 49 | Head, /* Relative to the current object head (default). */ | |||
| 50 | Tail, /* Relative to the current object tail after packed. */ | |||
| 51 | Absolute /* Absolute: from the start of the serialize buffer. */ | |||
| 52 | }; | |||
| 53 | ||||
| 54 | struct object_t | |||
| 55 | { | |||
| 56 | void fini () { links.fini (); } | |||
| 57 | ||||
| 58 | bool operator == (const object_t &o) const | |||
| 59 | { | |||
| 60 | return (tail - head == o.tail - o.head) | |||
| 61 | && (links.length == o.links.length) | |||
| 62 | && 0 == hb_memcmp (head, o.head, tail - head) | |||
| 63 | && links.as_bytes () == o.links.as_bytes (); | |||
| 64 | } | |||
| 65 | uint32_t hash () const | |||
| 66 | { | |||
| 67 | return hb_bytes_t (head, tail - head).hash () ^ | |||
| 68 | links.as_bytes ().hash (); | |||
| 69 | } | |||
| 70 | ||||
| 71 | struct link_t | |||
| 72 | { | |||
| 73 | bool is_wide: 1; | |||
| 74 | bool is_signed: 1; | |||
| 75 | unsigned whence: 2; | |||
| 76 | unsigned position: 28; | |||
| 77 | unsigned bias; | |||
| 78 | objidx_t objidx; | |||
| 79 | }; | |||
| 80 | ||||
| 81 | char *head; | |||
| 82 | char *tail; | |||
| 83 | hb_vector_t<link_t> links; | |||
| 84 | object_t *next; | |||
| 85 | }; | |||
| 86 | ||||
| 87 | struct snapshot_t | |||
| 88 | { | |||
| 89 | char *head; | |||
| 90 | char *tail; | |||
| 91 | object_t *current; // Just for sanity check | |||
| 92 | unsigned num_links; | |||
| 93 | }; | |||
| 94 | ||||
| 95 | snapshot_t snapshot () | |||
| 96 | { return snapshot_t { head, tail, current, current->links.length }; } | |||
| 97 | ||||
| 98 | hb_serialize_context_t (void *start_, unsigned int size) : | |||
| 99 | start ((char *) start_), | |||
| 100 | end (start + size), | |||
| 101 | current (nullptr) | |||
| 102 | { reset (); } | |||
| 103 | ~hb_serialize_context_t () { fini (); } | |||
| 104 | ||||
| 105 | void fini () | |||
| 106 | { | |||
| 107 | for (object_t *_ : ++hb_iter (packed)) _->fini (); | |||
| 108 | packed.fini (); | |||
| 109 | this->packed_map.fini (); | |||
| 110 | ||||
| 111 | while (current) | |||
| 112 | { | |||
| 113 | auto *_ = current; | |||
| 114 | current = current->next; | |||
| 115 | _->fini (); | |||
| 116 | } | |||
| 117 | object_pool.fini (); | |||
| 118 | } | |||
| 119 | ||||
| 120 | bool in_error () const { return !this->successful; } | |||
| 121 | ||||
| 122 | void reset () | |||
| 123 | { | |||
| 124 | this->successful = true; | |||
| 125 | this->ran_out_of_room = false; | |||
| 126 | this->head = this->start; | |||
| 127 | this->tail = this->end; | |||
| 128 | this->debug_depth = 0; | |||
| 129 | ||||
| 130 | fini (); | |||
| 131 | this->packed.push (nullptr); | |||
| 132 | } | |||
| 133 | ||||
| 134 | bool check_success (bool success) | |||
| 135 | { return this->successful && (success || (err_other_error (), false)); } | |||
| 136 | ||||
| 137 | template <typename T1, typename T2> | |||
| 138 | bool check_equal (T1 &&v1, T2 &&v2) | |||
| 139 | { return check_success ((long long) v1 == (long long) v2); } | |||
| 140 | ||||
| 141 | template <typename T1, typename T2> | |||
| 142 | bool check_assign (T1 &v1, T2 &&v2) | |||
| 143 | { return check_equal (v1 = v2, v2); } | |||
| 144 | ||||
| 145 | template <typename T> bool propagate_error (T &&obj) | |||
| 146 | { return check_success (!hb_deref (obj).in_error ()); } | |||
| 147 | ||||
| 148 | template <typename T1, typename... Ts> bool propagate_error (T1 &&o1, Ts&&... os) | |||
| 149 | { return propagate_error (hb_forward<T1> (o1)) && | |||
| 150 | propagate_error (hb_forward<Ts> (os)...); } | |||
| 151 | ||||
| 152 | /* To be called around main operation. */ | |||
| 153 | template <typename Type> | |||
| 154 | Type *start_serialize () | |||
| 155 | { | |||
| 156 | DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, +1,_hb_debug_msg<(0 +0)> ("SERIALIZE", (this->start), nullptr , true, (0), (+1), "start [%p..%p] (%lu bytes)", this->start , this->end, (unsigned long) (this->end - this->start )) | |||
| 157 | "start [%p..%p] (%lu bytes)",_hb_debug_msg<(0 +0)> ("SERIALIZE", (this->start), nullptr , true, (0), (+1), "start [%p..%p] (%lu bytes)", this->start , this->end, (unsigned long) (this->end - this->start )) | |||
| 158 | this->start, this->end,_hb_debug_msg<(0 +0)> ("SERIALIZE", (this->start), nullptr , true, (0), (+1), "start [%p..%p] (%lu bytes)", this->start , this->end, (unsigned long) (this->end - this->start )) | |||
| 159 | (unsigned long) (this->end - this->start))_hb_debug_msg<(0 +0)> ("SERIALIZE", (this->start), nullptr , true, (0), (+1), "start [%p..%p] (%lu bytes)", this->start , this->end, (unsigned long) (this->end - this->start )); | |||
| 160 | ||||
| 161 | assert (!current)(static_cast <bool> (!current) ? void (0) : __assert_fail ("!current", "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh" , 161, __extension__ __PRETTY_FUNCTION__)); | |||
| 162 | return push<Type> (); | |||
| 163 | } | |||
| 164 | void end_serialize () | |||
| 165 | { | |||
| 166 | DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1,_hb_debug_msg<(0 +0)> ("SERIALIZE", (this->start), nullptr , true, (0), (-1), "end [%p..%p] serialized %u bytes; %s", this ->start, this->end, (unsigned) (this->head - this-> start), this->successful ? "successful" : "UNSUCCESSFUL") | |||
| 167 | "end [%p..%p] serialized %u bytes; %s",_hb_debug_msg<(0 +0)> ("SERIALIZE", (this->start), nullptr , true, (0), (-1), "end [%p..%p] serialized %u bytes; %s", this ->start, this->end, (unsigned) (this->head - this-> start), this->successful ? "successful" : "UNSUCCESSFUL") | |||
| 168 | this->start, this->end,_hb_debug_msg<(0 +0)> ("SERIALIZE", (this->start), nullptr , true, (0), (-1), "end [%p..%p] serialized %u bytes; %s", this ->start, this->end, (unsigned) (this->head - this-> start), this->successful ? "successful" : "UNSUCCESSFUL") | |||
| 169 | (unsigned) (this->head - this->start),_hb_debug_msg<(0 +0)> ("SERIALIZE", (this->start), nullptr , true, (0), (-1), "end [%p..%p] serialized %u bytes; %s", this ->start, this->end, (unsigned) (this->head - this-> start), this->successful ? "successful" : "UNSUCCESSFUL") | |||
| 170 | this->successful ? "successful" : "UNSUCCESSFUL")_hb_debug_msg<(0 +0)> ("SERIALIZE", (this->start), nullptr , true, (0), (-1), "end [%p..%p] serialized %u bytes; %s", this ->start, this->end, (unsigned) (this->head - this-> start), this->successful ? "successful" : "UNSUCCESSFUL"); | |||
| 171 | ||||
| 172 | propagate_error (packed, packed_map); | |||
| 173 | ||||
| 174 | if (unlikely (!current)(__builtin_expect (!!(!current), 0))) return; | |||
| 175 | if (unlikely (in_error())(__builtin_expect (!!(in_error()), 0))) return; | |||
| 176 | ||||
| 177 | assert (!current->next)(static_cast <bool> (!current->next) ? void (0) : __assert_fail ("!current->next", "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh" , 177, __extension__ __PRETTY_FUNCTION__)); | |||
| 178 | ||||
| 179 | /* Only "pack" if there exist other objects... Otherwise, don't bother. | |||
| 180 | * Saves a move. */ | |||
| 181 | if (packed.length <= 1) | |||
| 182 | return; | |||
| 183 | ||||
| 184 | pop_pack (false); | |||
| 185 | ||||
| 186 | resolve_links (); | |||
| 187 | } | |||
| 188 | ||||
| 189 | template <typename Type = void> | |||
| 190 | Type *push () | |||
| 191 | { | |||
| 192 | if (unlikely (in_error ())(__builtin_expect (!!(in_error ()), 0))) return start_embed<Type> (); | |||
| 193 | ||||
| 194 | object_t *obj = object_pool.alloc (); | |||
| 195 | if (unlikely (!obj)(__builtin_expect (!!(!obj), 0))) | |||
| 196 | check_success (false); | |||
| 197 | else | |||
| 198 | { | |||
| 199 | obj->head = head; | |||
| 200 | obj->tail = tail; | |||
| 201 | obj->next = current; | |||
| 202 | current = obj; | |||
| 203 | } | |||
| 204 | return start_embed<Type> (); | |||
| 205 | } | |||
| 206 | void pop_discard () | |||
| 207 | { | |||
| 208 | object_t *obj = current; | |||
| 209 | if (unlikely (!obj)(__builtin_expect (!!(!obj), 0))) return; | |||
| 210 | if (unlikely (in_error())(__builtin_expect (!!(in_error()), 0))) return; | |||
| 211 | ||||
| 212 | current = current->next; | |||
| 213 | revert (obj->head, obj->tail); | |||
| 214 | obj->fini (); | |||
| 215 | object_pool.free (obj); | |||
| 216 | } | |||
| 217 | ||||
| 218 | /* Set share to false when an object is unlikely sharable with others | |||
| 219 | * so not worth an attempt, or a contiguous table is serialized as | |||
| 220 | * multiple consecutive objects in the reverse order so can't be shared. | |||
| 221 | */ | |||
| 222 | objidx_t pop_pack (bool share=true) | |||
| 223 | { | |||
| 224 | object_t *obj = current; | |||
| 225 | if (unlikely (!obj)(__builtin_expect (!!(!obj), 0))) return 0; | |||
| 226 | if (unlikely (in_error())(__builtin_expect (!!(in_error()), 0))) return 0; | |||
| 227 | ||||
| 228 | current = current->next; | |||
| 229 | obj->tail = head; | |||
| 230 | obj->next = nullptr; | |||
| 231 | unsigned len = obj->tail - obj->head; | |||
| 232 | head = obj->head; /* Rewind head. */ | |||
| 233 | ||||
| 234 | if (!len) | |||
| 235 | { | |||
| 236 | assert (!obj->links.length)(static_cast <bool> (!obj->links.length) ? void (0) : __assert_fail ("!obj->links.length", "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh" , 236, __extension__ __PRETTY_FUNCTION__)); | |||
| 237 | return 0; | |||
| 238 | } | |||
| 239 | ||||
| 240 | objidx_t objidx; | |||
| 241 | if (share) | |||
| 242 | { | |||
| 243 | objidx = packed_map.get (obj); | |||
| 244 | if (objidx) | |||
| 245 | { | |||
| 246 | obj->fini (); | |||
| 247 | return objidx; | |||
| 248 | } | |||
| 249 | } | |||
| 250 | ||||
| 251 | tail -= len; | |||
| 252 | memmove (tail, obj->head, len); | |||
| 253 | ||||
| 254 | obj->head = tail; | |||
| 255 | obj->tail = tail + len; | |||
| 256 | ||||
| 257 | packed.push (obj); | |||
| 258 | ||||
| 259 | if (unlikely (!propagate_error (packed))(__builtin_expect (!!(!propagate_error (packed)), 0))) | |||
| 260 | { | |||
| 261 | /* Obj wasn't successfully added to packed, so clean it up otherwise its | |||
| 262 | * links will be leaked. When we use constructor/destructors properly, we | |||
| 263 | * can remove these. */ | |||
| 264 | obj->fini (); | |||
| 265 | return 0; | |||
| 266 | } | |||
| 267 | ||||
| 268 | objidx = packed.length - 1; | |||
| 269 | ||||
| 270 | if (share) packed_map.set (obj, objidx); | |||
| 271 | propagate_error (packed_map); | |||
| 272 | ||||
| 273 | return objidx; | |||
| 274 | } | |||
| 275 | ||||
| 276 | void revert (snapshot_t snap) | |||
| 277 | { | |||
| 278 | if (unlikely (in_error ())(__builtin_expect (!!(in_error ()), 0))) return; | |||
| 279 | assert (snap.current == current)(static_cast <bool> (snap.current == current) ? void (0 ) : __assert_fail ("snap.current == current", "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh" , 279, __extension__ __PRETTY_FUNCTION__)); | |||
| 280 | current->links.shrink (snap.num_links); | |||
| 281 | revert (snap.head, snap.tail); | |||
| 282 | } | |||
| 283 | ||||
| 284 | void revert (char *snap_head, | |||
| 285 | char *snap_tail) | |||
| 286 | { | |||
| 287 | if (unlikely (in_error ())(__builtin_expect (!!(in_error ()), 0))) return; | |||
| 288 | assert (snap_head <= head)(static_cast <bool> (snap_head <= head) ? void (0) : __assert_fail ("snap_head <= head", "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh" , 288, __extension__ __PRETTY_FUNCTION__)); | |||
| 289 | assert (tail <= snap_tail)(static_cast <bool> (tail <= snap_tail) ? void (0) : __assert_fail ("tail <= snap_tail", "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh" , 289, __extension__ __PRETTY_FUNCTION__)); | |||
| 290 | head = snap_head; | |||
| 291 | tail = snap_tail; | |||
| 292 | discard_stale_objects (); | |||
| 293 | } | |||
| 294 | ||||
| 295 | void discard_stale_objects () | |||
| 296 | { | |||
| 297 | if (unlikely (in_error ())(__builtin_expect (!!(in_error ()), 0))) return; | |||
| 298 | while (packed.length > 1 && | |||
| 299 | packed.tail ()->head < tail) | |||
| 300 | { | |||
| 301 | packed_map.del (packed.tail ()); | |||
| 302 | assert (!packed.tail ()->next)(static_cast <bool> (!packed.tail ()->next) ? void ( 0) : __assert_fail ("!packed.tail ()->next", "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh" , 302, __extension__ __PRETTY_FUNCTION__)); | |||
| 303 | packed.tail ()->fini (); | |||
| 304 | packed.pop (); | |||
| 305 | } | |||
| 306 | if (packed.length > 1) | |||
| 307 | assert (packed.tail ()->head == tail)(static_cast <bool> (packed.tail ()->head == tail) ? void (0) : __assert_fail ("packed.tail ()->head == tail", "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh" , 307, __extension__ __PRETTY_FUNCTION__)); | |||
| 308 | } | |||
| 309 | ||||
| 310 | template <typename T> | |||
| 311 | void add_link (T &ofs, objidx_t objidx, | |||
| 312 | whence_t whence = Head, | |||
| 313 | unsigned bias = 0) | |||
| 314 | { | |||
| 315 | static_assert (sizeof (T) == 2 || sizeof (T) == 4, ""); | |||
| 316 | if (unlikely (in_error ())(__builtin_expect (!!(in_error ()), 0))) return; | |||
| 317 | ||||
| 318 | if (!objidx) | |||
| 319 | return; | |||
| 320 | ||||
| 321 | assert (current)(static_cast <bool> (current) ? void (0) : __assert_fail ("current", "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh" , 321, __extension__ __PRETTY_FUNCTION__)); | |||
| 322 | assert (current->head <= (const char *) &ofs)(static_cast <bool> (current->head <= (const char *) &ofs) ? void (0) : __assert_fail ("current->head <= (const char *) &ofs" , "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh" , 322, __extension__ __PRETTY_FUNCTION__)); | |||
| 323 | ||||
| 324 | auto& link = *current->links.push (); | |||
| 325 | ||||
| 326 | link.is_wide = sizeof (T) == 4; | |||
| 327 | link.is_signed = hb_is_signed (hb_unwrap_type (T))hb_is_signed<typename hb_unwrap_type<T>::type>::value; | |||
| 328 | link.whence = (unsigned) whence; | |||
| 329 | link.position = (const char *) &ofs - current->head; | |||
| 330 | link.bias = bias; | |||
| 331 | link.objidx = objidx; | |||
| 332 | } | |||
| 333 | ||||
| 334 | unsigned to_bias (const void *base) const | |||
| 335 | { | |||
| 336 | if (unlikely (in_error ())(__builtin_expect (!!(in_error ()), 0))) return 0; | |||
| 337 | if (!base) return 0; | |||
| 338 | assert (current)(static_cast <bool> (current) ? void (0) : __assert_fail ("current", "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh" , 338, __extension__ __PRETTY_FUNCTION__)); | |||
| 339 | assert (current->head <= (const char *) base)(static_cast <bool> (current->head <= (const char *) base) ? void (0) : __assert_fail ("current->head <= (const char *) base" , "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh" , 339, __extension__ __PRETTY_FUNCTION__)); | |||
| 340 | return (const char *) base - current->head; | |||
| 341 | } | |||
| 342 | ||||
| 343 | void resolve_links () | |||
| 344 | { | |||
| 345 | if (unlikely (in_error ())(__builtin_expect (!!(in_error ()), 0))) return; | |||
| 346 | ||||
| 347 | assert (!current)(static_cast <bool> (!current) ? void (0) : __assert_fail ("!current", "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh" , 347, __extension__ __PRETTY_FUNCTION__)); | |||
| 348 | assert (packed.length > 1)(static_cast <bool> (packed.length > 1) ? void (0) : __assert_fail ("packed.length > 1", "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh" , 348, __extension__ __PRETTY_FUNCTION__)); | |||
| 349 | ||||
| 350 | for (const object_t* parent : ++hb_iter (packed)) | |||
| 351 | for (const object_t::link_t &link : parent->links) | |||
| 352 | { | |||
| 353 | const object_t* child = packed[link.objidx]; | |||
| 354 | if (unlikely (!child)(__builtin_expect (!!(!child), 0))) { err_other_error(); return; } | |||
| 355 | unsigned offset = 0; | |||
| 356 | switch ((whence_t) link.whence) { | |||
| 357 | case Head: offset = child->head - parent->head; break; | |||
| 358 | case Tail: offset = child->head - parent->tail; break; | |||
| 359 | case Absolute: offset = (head - start) + (child->head - tail); break; | |||
| 360 | } | |||
| 361 | ||||
| 362 | assert (offset >= link.bias)(static_cast <bool> (offset >= link.bias) ? void (0) : __assert_fail ("offset >= link.bias", "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh" , 362, __extension__ __PRETTY_FUNCTION__)); | |||
| 363 | offset -= link.bias; | |||
| 364 | if (link.is_signed) | |||
| 365 | { | |||
| 366 | if (link.is_wide) | |||
| 367 | assign_offset<int32_t> (parent, link, offset); | |||
| 368 | else | |||
| 369 | assign_offset<int16_t> (parent, link, offset); | |||
| 370 | } | |||
| 371 | else | |||
| 372 | { | |||
| 373 | if (link.is_wide) | |||
| 374 | assign_offset<uint32_t> (parent, link, offset); | |||
| 375 | else | |||
| 376 | assign_offset<uint16_t> (parent, link, offset); | |||
| 377 | } | |||
| 378 | } | |||
| 379 | } | |||
| 380 | ||||
| 381 | unsigned int length () const | |||
| 382 | { | |||
| 383 | if (unlikely (!current)(__builtin_expect (!!(!current), 0))) return 0; | |||
| 384 | return this->head - current->head; | |||
| 385 | } | |||
| 386 | ||||
| 387 | void align (unsigned int alignment) | |||
| 388 | { | |||
| 389 | unsigned int l = length () % alignment; | |||
| 390 | if (l) | |||
| 391 | allocate_size<void> (alignment - l); | |||
| 392 | } | |||
| 393 | ||||
| 394 | template <typename Type = void> | |||
| 395 | Type *start_embed (const Type *obj HB_UNUSED__attribute__((unused)) = nullptr) const | |||
| 396 | { return reinterpret_cast<Type *> (this->head); } | |||
| 397 | template <typename Type> | |||
| 398 | Type *start_embed (const Type &obj) const | |||
| 399 | { return start_embed (hb_addressof (obj)); } | |||
| 400 | ||||
| 401 | /* Following two functions exist to allow setting breakpoint on. */ | |||
| 402 | void err_ran_out_of_room () { this->ran_out_of_room = true; } | |||
| 403 | void err_other_error () { this->successful = false; } | |||
| 404 | ||||
| 405 | template <typename Type> | |||
| 406 | Type *allocate_size (unsigned int size) | |||
| 407 | { | |||
| 408 | if (unlikely (!this->successful)(__builtin_expect (!!(!this->successful), 0))) return nullptr; | |||
| 409 | ||||
| 410 | if (this->tail - this->head < ptrdiff_t (size)) | |||
| 411 | { | |||
| 412 | err_ran_out_of_room (); | |||
| 413 | this->successful = false; | |||
| 414 | return nullptr; | |||
| 415 | } | |||
| 416 | memset (this->head, 0, size); | |||
| 417 | char *ret = this->head; | |||
| 418 | this->head += size; | |||
| 419 | return reinterpret_cast<Type *> (ret); | |||
| 420 | } | |||
| 421 | ||||
| 422 | template <typename Type> | |||
| 423 | Type *allocate_min () | |||
| 424 | { return this->allocate_size<Type> (Type::min_size); } | |||
| 425 | ||||
| 426 | template <typename Type> | |||
| 427 | Type *embed (const Type *obj) | |||
| 428 | { | |||
| 429 | unsigned int size = obj->get_size (); | |||
| 430 | Type *ret = this->allocate_size<Type> (size); | |||
| 431 | if (unlikely (!ret)(__builtin_expect (!!(!ret), 0))) return nullptr; | |||
| 432 | memcpy (ret, obj, size); | |||
| 433 | return ret; | |||
| 434 | } | |||
| 435 | template <typename Type> | |||
| 436 | Type *embed (const Type &obj) | |||
| 437 | { return embed (hb_addressof (obj)); } | |||
| 438 | ||||
| 439 | template <typename Type, typename ...Ts> auto | |||
| 440 | _copy (const Type &src, hb_priority<1>, Ts&&... ds) HB_RETURN-> hb_head_t<Type *, decltype ((src.copy (this, hb_forward <Ts> (ds)...)))> { return (src.copy (this, hb_forward <Ts> (ds)...)); } | |||
| 441 | (Type *, src.copy (this, hb_forward<Ts> (ds)...))-> hb_head_t<Type *, decltype ((src.copy (this, hb_forward <Ts> (ds)...)))> { return (src.copy (this, hb_forward <Ts> (ds)...)); } | |||
| 442 | ||||
| 443 | template <typename Type> auto | |||
| 444 | _copy (const Type &src, hb_priority<0>) -> decltype (&(hb_declval<Type> () = src)) | |||
| 445 | { | |||
| 446 | Type *ret = this->allocate_size<Type> (sizeof (Type)); | |||
| 447 | if (unlikely (!ret)(__builtin_expect (!!(!ret), 0))) return nullptr; | |||
| 448 | *ret = src; | |||
| 449 | return ret; | |||
| 450 | } | |||
| 451 | ||||
| 452 | /* Like embed, but active: calls obj.operator=() or obj.copy() to transfer data | |||
| 453 | * instead of memcpy(). */ | |||
| 454 | template <typename Type, typename ...Ts> | |||
| 455 | Type *copy (const Type &src, Ts&&... ds) | |||
| 456 | { return _copy (src, hb_prioritizehb_priority<16> (), hb_forward<Ts> (ds)...); } | |||
| 457 | template <typename Type, typename ...Ts> | |||
| 458 | Type *copy (const Type *src, Ts&&... ds) | |||
| 459 | { return copy (*src, hb_forward<Ts> (ds)...); } | |||
| 460 | ||||
| 461 | template<typename Iterator, | |||
| 462 | hb_requires (hb_is_iterator (Iterator))typename hb_enable_if<((hb_is_iterator_of<Iterator, typename Iterator::item_t>::value))>::type* = nullptr, | |||
| 463 | typename ...Ts> | |||
| 464 | void copy_all (Iterator it, Ts&&... ds) | |||
| 465 | { for (decltype (*it) _ : it) copy (_, hb_forward<Ts> (ds)...); } | |||
| 466 | ||||
| 467 | template <typename Type> | |||
| 468 | hb_serialize_context_t& operator << (const Type &obj) & { embed (obj); return *this; } | |||
| 469 | ||||
| 470 | template <typename Type> | |||
| 471 | Type *extend_size (Type *obj, unsigned int size) | |||
| 472 | { | |||
| 473 | if (unlikely (in_error ())(__builtin_expect (!!(in_error ()), 0))) return nullptr; | |||
| 474 | ||||
| 475 | assert (this->start <= (char *) obj)(static_cast <bool> (this->start <= (char *) obj) ? void (0) : __assert_fail ("this->start <= (char *) obj" , "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh" , 475, __extension__ __PRETTY_FUNCTION__)); | |||
| 476 | assert ((char *) obj <= this->head)(static_cast <bool> ((char *) obj <= this->head) ? void (0) : __assert_fail ("(char *) obj <= this->head" , "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh" , 476, __extension__ __PRETTY_FUNCTION__)); | |||
| 477 | assert ((char *) obj + size >= this->head)(static_cast <bool> ((char *) obj + size >= this-> head) ? void (0) : __assert_fail ("(char *) obj + size >= this->head" , "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh" , 477, __extension__ __PRETTY_FUNCTION__)); | |||
| 478 | if (unlikely (!this->allocate_size<Type> (((char *) obj) + size - this->head))(__builtin_expect (!!(!this->allocate_size<Type> ((( char *) obj) + size - this->head)), 0))) return nullptr; | |||
| 479 | return reinterpret_cast<Type *> (obj); | |||
| 480 | } | |||
| 481 | template <typename Type> | |||
| 482 | Type *extend_size (Type &obj, unsigned int size) | |||
| 483 | { return extend_size (hb_addressof (obj), size); } | |||
| 484 | ||||
| 485 | template <typename Type> | |||
| 486 | Type *extend_min (Type *obj) { return extend_size (obj, obj->min_size); } | |||
| 487 | template <typename Type> | |||
| 488 | Type *extend_min (Type &obj) { return extend_min (hb_addressof (obj)); } | |||
| 489 | ||||
| 490 | template <typename Type, typename ...Ts> | |||
| 491 | Type *extend (Type *obj, Ts&&... ds) | |||
| 492 | { return extend_size (obj, obj->get_size (hb_forward<Ts> (ds)...)); } | |||
| 493 | template <typename Type, typename ...Ts> | |||
| 494 | Type *extend (Type &obj, Ts&&... ds) | |||
| 495 | { return extend (hb_addressof (obj), hb_forward<Ts> (ds)...); } | |||
| 496 | ||||
| 497 | /* Output routines. */ | |||
| 498 | hb_bytes_t copy_bytes () const | |||
| 499 | { | |||
| 500 | assert (this->successful)(static_cast <bool> (this->successful) ? void (0) : __assert_fail ("this->successful", "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh" , 500, __extension__ __PRETTY_FUNCTION__)); | |||
| 501 | /* Copy both items from head side and tail side... */ | |||
| 502 | unsigned int len = (this->head - this->start) | |||
| 503 | + (this->end - this->tail); | |||
| 504 | ||||
| 505 | char *p = (char *) malloc (len); | |||
| 506 | if (unlikely (!p)(__builtin_expect (!!(!p), 0))) return hb_bytes_t (); | |||
| 507 | ||||
| 508 | memcpy (p, this->start, this->head - this->start); | |||
| 509 | memcpy (p + (this->head - this->start), this->tail, this->end - this->tail); | |||
| 510 | return hb_bytes_t (p, len); | |||
| ||||
| 511 | } | |||
| 512 | template <typename Type> | |||
| 513 | Type *copy () const | |||
| 514 | { return reinterpret_cast<Type *> ((char *) copy_bytes ().arrayZ); } | |||
| 515 | hb_blob_t *copy_blob () const | |||
| 516 | { | |||
| 517 | hb_bytes_t b = copy_bytes (); | |||
| 518 | return hb_blob_create (b.arrayZ, b.length, | |||
| 519 | HB_MEMORY_MODE_WRITABLE, | |||
| 520 | (char *) b.arrayZ, free); | |||
| 521 | } | |||
| 522 | ||||
| 523 | private: | |||
| 524 | template <typename T> | |||
| 525 | void assign_offset (const object_t* parent, const object_t::link_t &link, unsigned offset) | |||
| 526 | { | |||
| 527 | auto &off = * ((BEInt<T> *) (parent->head + link.position)); | |||
| 528 | assert (0 == off)(static_cast <bool> (0 == off) ? void (0) : __assert_fail ("0 == off", "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh" , 528, __extension__ __PRETTY_FUNCTION__)); | |||
| 529 | check_assign (off, offset); | |||
| 530 | } | |||
| 531 | ||||
| 532 | public: /* TODO Make private. */ | |||
| 533 | char *start, *head, *tail, *end; | |||
| 534 | unsigned int debug_depth; | |||
| 535 | bool successful; | |||
| 536 | bool ran_out_of_room; | |||
| 537 | ||||
| 538 | private: | |||
| 539 | ||||
| 540 | /* Object memory pool. */ | |||
| 541 | hb_pool_t<object_t> object_pool; | |||
| 542 | ||||
| 543 | /* Stack of currently under construction objects. */ | |||
| 544 | object_t *current; | |||
| 545 | ||||
| 546 | /* Stack of packed objects. Object 0 is always nil object. */ | |||
| 547 | hb_vector_t<object_t *> packed; | |||
| 548 | ||||
| 549 | /* Map view of packed objects. */ | |||
| 550 | hb_hashmap_t<const object_t *, objidx_t, nullptr, 0> packed_map; | |||
| 551 | }; | |||
| 552 | ||||
| 553 | ||||
| 554 | #endif /* HB_SERIALIZE_HH */ |