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 */ |