serialize.hh (8361B)
1 /* 2 * Copyright © 2022 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 25 */ 26 27 #ifndef GRAPH_SERIALIZE_HH 28 #define GRAPH_SERIALIZE_HH 29 30 namespace graph { 31 32 struct overflow_record_t 33 { 34 unsigned parent; 35 unsigned child; 36 37 bool operator != (const overflow_record_t o) const 38 { return !(*this == o); } 39 40 inline bool operator == (const overflow_record_t& o) const 41 { 42 return parent == o.parent && 43 child == o.child; 44 } 45 46 inline uint32_t hash () const 47 { 48 uint32_t current = 0; 49 current = current * 31 + hb_hash (parent); 50 current = current * 31 + hb_hash (child); 51 return current; 52 } 53 }; 54 55 inline 56 int64_t compute_offset ( 57 const graph_t& graph, 58 unsigned parent_idx, 59 const hb_serialize_context_t::object_t::link_t& link) 60 { 61 const auto& parent = graph.vertices_[parent_idx]; 62 const auto& child = graph.vertices_[link.objidx]; 63 int64_t offset = 0; 64 switch ((hb_serialize_context_t::whence_t) link.whence) { 65 case hb_serialize_context_t::whence_t::Head: 66 offset = child.start - parent.start; break; 67 case hb_serialize_context_t::whence_t::Tail: 68 offset = child.start - parent.end; break; 69 case hb_serialize_context_t::whence_t::Absolute: 70 offset = child.start; break; 71 } 72 73 assert (offset >= link.bias); 74 offset -= link.bias; 75 return offset; 76 } 77 78 inline 79 bool is_valid_offset (int64_t offset, 80 const hb_serialize_context_t::object_t::link_t& link) 81 { 82 if (unlikely (!link.width)) 83 // Virtual links can't overflow. 84 return link.is_signed || offset >= 0; 85 86 if (link.is_signed) 87 { 88 if (link.width == 4) 89 return offset >= -((int64_t) 1 << 31) && offset < ((int64_t) 1 << 31); 90 else 91 return offset >= -(1 << 15) && offset < (1 << 15); 92 } 93 else 94 { 95 if (link.width == 4) 96 return offset >= 0 && offset < ((int64_t) 1 << 32); 97 else if (link.width == 3) 98 return offset >= 0 && offset < ((int32_t) 1 << 24); 99 else 100 return offset >= 0 && offset < (1 << 16); 101 } 102 } 103 104 /* 105 * Will any offsets overflow on graph when it's serialized? 106 */ 107 inline bool 108 will_overflow (graph_t& graph, 109 hb_vector_t<overflow_record_t>* overflows = nullptr) 110 { 111 if (overflows) overflows->resize (0); 112 graph.update_positions (); 113 114 hb_hashmap_t<overflow_record_t*, bool> record_set; 115 const auto& vertices = graph.vertices_; 116 for (unsigned parent_idx : graph.ordering_) 117 { 118 // Don't need to check virtual links for overflow 119 for (const auto& link : vertices.arrayZ[parent_idx].obj.real_links) 120 { 121 int64_t offset = compute_offset (graph, parent_idx, link); 122 if (likely (is_valid_offset (offset, link))) 123 continue; 124 125 if (!overflows) return true; 126 127 overflow_record_t r; 128 r.parent = parent_idx; 129 r.child = link.objidx; 130 if (record_set.has(&r)) continue; // don't keep duplicate overflows. 131 132 overflows->push (r); 133 record_set.set(&r, true); 134 } 135 } 136 137 if (!overflows) return false; 138 return overflows->length; 139 } 140 141 inline 142 void print_overflows (graph_t& graph, 143 const hb_vector_t<overflow_record_t>& overflows) 144 { 145 if (!DEBUG_ENABLED(SUBSET_REPACK)) return; 146 147 graph.update_parents (); 148 int limit = 10; 149 for (const auto& o : overflows) 150 { 151 if (!limit--) break; 152 const auto& parent = graph.vertices_[o.parent]; 153 const auto& child = graph.vertices_[o.child]; 154 DEBUG_MSG (SUBSET_REPACK, nullptr, 155 " overflow from " 156 "%4u (%4u in, %4u out, space %2u) => " 157 "%4u (%4u in, %4u out, space %2u)", 158 o.parent, 159 parent.incoming_edges (), 160 parent.obj.real_links.length + parent.obj.virtual_links.length, 161 graph.space_for (o.parent), 162 o.child, 163 child.incoming_edges (), 164 child.obj.real_links.length + child.obj.virtual_links.length, 165 graph.space_for (o.child)); 166 } 167 if (overflows.length > 10) { 168 DEBUG_MSG (SUBSET_REPACK, nullptr, " ... plus %u more overflows.", overflows.length - 10); 169 } 170 } 171 172 template <typename O> inline void 173 serialize_link_of_type (const hb_serialize_context_t::object_t::link_t& link, 174 char* head, 175 unsigned size, 176 const hb_vector_t<unsigned>& id_map, 177 hb_serialize_context_t* c) 178 { 179 assert(link.position + link.width <= size); 180 181 OT::Offset<O>* offset = reinterpret_cast<OT::Offset<O>*> (head + link.position); 182 *offset = 0; 183 c->add_link (*offset, 184 id_map[link.objidx], 185 (hb_serialize_context_t::whence_t) link.whence, 186 link.bias); 187 } 188 189 inline 190 void serialize_link (const hb_serialize_context_t::object_t::link_t& link, 191 char* head, 192 unsigned size, 193 const hb_vector_t<unsigned>& id_map, 194 hb_serialize_context_t* c) 195 { 196 switch (link.width) 197 { 198 case 0: 199 // Virtual links aren't serialized. 200 return; 201 case 4: 202 if (link.is_signed) 203 { 204 serialize_link_of_type<OT::HBINT32> (link, head, size, id_map, c); 205 } else { 206 serialize_link_of_type<OT::HBUINT32> (link, head, size, id_map, c); 207 } 208 return; 209 case 2: 210 if (link.is_signed) 211 { 212 serialize_link_of_type<OT::HBINT16> (link, head, size, id_map, c); 213 } else { 214 serialize_link_of_type<OT::HBUINT16> (link, head, size, id_map, c); 215 } 216 return; 217 case 3: 218 serialize_link_of_type<OT::HBUINT24> (link, head, size, id_map, c); 219 return; 220 default: 221 // Unexpected link width. 222 assert (0); 223 } 224 } 225 226 /* 227 * serialize graph into the provided serialization buffer. 228 */ 229 inline hb_blob_t* serialize (const graph_t& graph) 230 { 231 hb_vector_t<char> buffer; 232 size_t size = graph.total_size_in_bytes (); 233 234 if (!size) return hb_blob_get_empty (); 235 236 if (!buffer.alloc (size)) { 237 DEBUG_MSG (SUBSET_REPACK, nullptr, "Unable to allocate output buffer."); 238 return nullptr; 239 } 240 hb_serialize_context_t c((void *) buffer, size); 241 242 c.start_serialize<void> (); 243 const auto& vertices = graph.vertices_; 244 245 // Objects are placed in the serializer in reverse order since children need 246 // to be inserted before their parents. 247 248 // Maps from our obj id's to the id's used during this serialization. 249 hb_vector_t<unsigned> id_map; 250 id_map.resize(graph.ordering_.length); 251 for (int pos = graph.ordering_.length - 1; pos >= 0; pos--) { 252 unsigned i = graph.ordering_[pos]; 253 c.push (); 254 255 auto& v = vertices[i]; 256 257 size_t size = v.obj.tail - v.obj.head; 258 259 char* start = c.allocate_size <char> (size); 260 if (!start) { 261 DEBUG_MSG (SUBSET_REPACK, nullptr, "Buffer out of space."); 262 return nullptr; 263 } 264 265 hb_memcpy (start, v.obj.head, size); 266 267 // Only real links needs to be serialized. 268 for (const auto& link : v.obj.real_links) 269 serialize_link (link, start, size, id_map, &c); 270 271 // All duplications are already encoded in the graph, so don't 272 // enable sharing during packing. 273 id_map[i] = c.pop_pack (false); 274 } 275 c.end_serialize (); 276 277 if (c.in_error ()) { 278 DEBUG_MSG (SUBSET_REPACK, nullptr, "Error during serialization. Err flag: %d", 279 c.errors); 280 return nullptr; 281 } 282 283 return c.copy_blob (); 284 } 285 286 } // namespace graph 287 288 #endif // GRAPH_SERIALIZE_HH