jdk
671 строка · 20.1 Кб
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-subset.hh"28#include "hb-set.hh"29#include "hb-utf.hh"30
31
32hb_subset_input_t::hb_subset_input_t ()33{
34for (auto& set : sets_iter ())35set = hb::shared_ptr<hb_set_t> (hb_set_create ());36
37if (in_error ())38return;39
40flags = HB_SUBSET_FLAGS_DEFAULT;41
42hb_set_add_range (sets.name_ids, 0, 6);43hb_set_add (sets.name_languages, 0x0409);44
45hb_tag_t default_drop_tables[] = {46// Layout disabled by default47HB_TAG ('m', 'o', 'r', 'x'),48HB_TAG ('m', 'o', 'r', 't'),49HB_TAG ('k', 'e', 'r', 'x'),50HB_TAG ('k', 'e', 'r', 'n'),51
52// Copied from fontTools:53HB_TAG ('B', 'A', 'S', 'E'),54HB_TAG ('J', 'S', 'T', 'F'),55HB_TAG ('D', 'S', 'I', 'G'),56HB_TAG ('E', 'B', 'D', 'T'),57HB_TAG ('E', 'B', 'L', 'C'),58HB_TAG ('E', 'B', 'S', 'C'),59HB_TAG ('S', 'V', 'G', ' '),60HB_TAG ('P', 'C', 'L', 'T'),61HB_TAG ('L', 'T', 'S', 'H'),62// Graphite tables63HB_TAG ('F', 'e', 'a', 't'),64HB_TAG ('G', 'l', 'a', 't'),65HB_TAG ('G', 'l', 'o', 'c'),66HB_TAG ('S', 'i', 'l', 'f'),67HB_TAG ('S', 'i', 'l', 'l'),68};69sets.drop_tables->add_array (default_drop_tables, ARRAY_LENGTH (default_drop_tables));70
71hb_tag_t default_no_subset_tables[] = {72HB_TAG ('g', 'a', 's', 'p'),73HB_TAG ('f', 'p', 'g', 'm'),74HB_TAG ('p', 'r', 'e', 'p'),75HB_TAG ('V', 'D', 'M', 'X'),76HB_TAG ('D', 'S', 'I', 'G'),77};78sets.no_subset_tables->add_array (default_no_subset_tables,79ARRAY_LENGTH (default_no_subset_tables));80
81//copied from _layout_features_groups in fonttools82hb_tag_t default_layout_features[] = {83// default shaper84// common85HB_TAG ('r', 'v', 'r', 'n'),86HB_TAG ('c', 'c', 'm', 'p'),87HB_TAG ('l', 'i', 'g', 'a'),88HB_TAG ('l', 'o', 'c', 'l'),89HB_TAG ('m', 'a', 'r', 'k'),90HB_TAG ('m', 'k', 'm', 'k'),91HB_TAG ('r', 'l', 'i', 'g'),92
93//fractions94HB_TAG ('f', 'r', 'a', 'c'),95HB_TAG ('n', 'u', 'm', 'r'),96HB_TAG ('d', 'n', 'o', 'm'),97
98//horizontal99HB_TAG ('c', 'a', 'l', 't'),100HB_TAG ('c', 'l', 'i', 'g'),101HB_TAG ('c', 'u', 'r', 's'),102HB_TAG ('k', 'e', 'r', 'n'),103HB_TAG ('r', 'c', 'l', 't'),104
105//vertical106HB_TAG ('v', 'a', 'l', 't'),107HB_TAG ('v', 'e', 'r', 't'),108HB_TAG ('v', 'k', 'r', 'n'),109HB_TAG ('v', 'p', 'a', 'l'),110HB_TAG ('v', 'r', 't', '2'),111
112//ltr113HB_TAG ('l', 't', 'r', 'a'),114HB_TAG ('l', 't', 'r', 'm'),115
116//rtl117HB_TAG ('r', 't', 'l', 'a'),118HB_TAG ('r', 't', 'l', 'm'),119
120//random121HB_TAG ('r', 'a', 'n', 'd'),122
123//justify124HB_TAG ('j', 'a', 'l', 't'), // HarfBuzz doesn't use; others might125
126//private127HB_TAG ('H', 'a', 'r', 'f'),128HB_TAG ('H', 'A', 'R', 'F'),129HB_TAG ('B', 'u', 'z', 'z'),130HB_TAG ('B', 'U', 'Z', 'Z'),131
132//shapers133
134//arabic135HB_TAG ('i', 'n', 'i', 't'),136HB_TAG ('m', 'e', 'd', 'i'),137HB_TAG ('f', 'i', 'n', 'a'),138HB_TAG ('i', 's', 'o', 'l'),139HB_TAG ('m', 'e', 'd', '2'),140HB_TAG ('f', 'i', 'n', '2'),141HB_TAG ('f', 'i', 'n', '3'),142HB_TAG ('c', 's', 'w', 'h'),143HB_TAG ('m', 's', 'e', 't'),144HB_TAG ('s', 't', 'c', 'h'),145
146//hangul147HB_TAG ('l', 'j', 'm', 'o'),148HB_TAG ('v', 'j', 'm', 'o'),149HB_TAG ('t', 'j', 'm', 'o'),150
151//tibetan152HB_TAG ('a', 'b', 'v', 's'),153HB_TAG ('b', 'l', 'w', 's'),154HB_TAG ('a', 'b', 'v', 'm'),155HB_TAG ('b', 'l', 'w', 'm'),156
157//indic158HB_TAG ('n', 'u', 'k', 't'),159HB_TAG ('a', 'k', 'h', 'n'),160HB_TAG ('r', 'p', 'h', 'f'),161HB_TAG ('r', 'k', 'r', 'f'),162HB_TAG ('p', 'r', 'e', 'f'),163HB_TAG ('b', 'l', 'w', 'f'),164HB_TAG ('h', 'a', 'l', 'f'),165HB_TAG ('a', 'b', 'v', 'f'),166HB_TAG ('p', 's', 't', 'f'),167HB_TAG ('c', 'f', 'a', 'r'),168HB_TAG ('v', 'a', 't', 'u'),169HB_TAG ('c', 'j', 'c', 't'),170HB_TAG ('i', 'n', 'i', 't'),171HB_TAG ('p', 'r', 'e', 's'),172HB_TAG ('a', 'b', 'v', 's'),173HB_TAG ('b', 'l', 'w', 's'),174HB_TAG ('p', 's', 't', 's'),175HB_TAG ('h', 'a', 'l', 'n'),176HB_TAG ('d', 'i', 's', 't'),177HB_TAG ('a', 'b', 'v', 'm'),178HB_TAG ('b', 'l', 'w', 'm'),179};180
181sets.layout_features->add_array (default_layout_features, ARRAY_LENGTH (default_layout_features));182
183sets.layout_scripts->invert (); // Default to all scripts.184}
185
186/**
187* hb_subset_input_create_or_fail:
188*
189* Creates a new subset input object.
190*
191* Return value: (transfer full): New subset input, or `NULL` if failed. Destroy
192* with hb_subset_input_destroy().
193*
194* Since: 1.8.0
195**/
196hb_subset_input_t *197hb_subset_input_create_or_fail (void)198{
199hb_subset_input_t *input = hb_object_create<hb_subset_input_t>();200
201if (unlikely (!input))202return nullptr;203
204if (input->in_error ())205{206hb_subset_input_destroy (input);207return nullptr;208}209
210return input;211}
212
213/**
214* hb_subset_input_reference: (skip)
215* @input: a #hb_subset_input_t object.
216*
217* Increases the reference count on @input.
218*
219* Return value: @input.
220*
221* Since: 1.8.0
222**/
223hb_subset_input_t *224hb_subset_input_reference (hb_subset_input_t *input)225{
226return hb_object_reference (input);227}
228
229/**
230* hb_subset_input_destroy:
231* @input: a #hb_subset_input_t object.
232*
233* Decreases the reference count on @input, and if it reaches zero, destroys
234* @input, freeing all memory.
235*
236* Since: 1.8.0
237**/
238void
239hb_subset_input_destroy (hb_subset_input_t *input)240{
241if (!hb_object_destroy (input)) return;242
243hb_free (input);244}
245
246/**
247* hb_subset_input_unicode_set:
248* @input: a #hb_subset_input_t object.
249*
250* Gets the set of Unicode code points to retain, the caller should modify the
251* set as needed.
252*
253* Return value: (transfer none): pointer to the #hb_set_t of Unicode code
254* points.
255*
256* Since: 1.8.0
257**/
258HB_EXTERN hb_set_t *259hb_subset_input_unicode_set (hb_subset_input_t *input)260{
261return input->sets.unicodes;262}
263
264/**
265* hb_subset_input_glyph_set:
266* @input: a #hb_subset_input_t object.
267*
268* Gets the set of glyph IDs to retain, the caller should modify the set as
269* needed.
270*
271* Return value: (transfer none): pointer to the #hb_set_t of glyph IDs.
272*
273* Since: 1.8.0
274**/
275HB_EXTERN hb_set_t *276hb_subset_input_glyph_set (hb_subset_input_t *input)277{
278return input->sets.glyphs;279}
280
281/**
282* hb_subset_input_set:
283* @input: a #hb_subset_input_t object.
284* @set_type: a #hb_subset_sets_t set type.
285*
286* Gets the set of the specified type.
287*
288* Return value: (transfer none): pointer to the #hb_set_t of the specified type.
289*
290* Since: 2.9.1
291**/
292HB_EXTERN hb_set_t *293hb_subset_input_set (hb_subset_input_t *input, hb_subset_sets_t set_type)294{
295return input->sets_iter () [set_type];296}
297
298/**
299* hb_subset_input_get_flags:
300* @input: a #hb_subset_input_t object.
301*
302* Gets all of the subsetting flags in the input object.
303*
304* Return value: the subsetting flags bit field.
305*
306* Since: 2.9.0
307**/
308HB_EXTERN hb_subset_flags_t
309hb_subset_input_get_flags (hb_subset_input_t *input)310{
311return (hb_subset_flags_t) input->flags;312}
313
314/**
315* hb_subset_input_set_flags:
316* @input: a #hb_subset_input_t object.
317* @value: bit field of flags
318*
319* Sets all of the flags in the input object to the values specified by the bit
320* field.
321*
322* Since: 2.9.0
323**/
324HB_EXTERN void325hb_subset_input_set_flags (hb_subset_input_t *input,326unsigned value)327{
328input->flags = (hb_subset_flags_t) value;329}
330
331/**
332* hb_subset_input_set_user_data: (skip)
333* @input: a #hb_subset_input_t object.
334* @key: The user-data key to set
335* @data: A pointer to the user data
336* @destroy: (nullable): A callback to call when @data is not needed anymore
337* @replace: Whether to replace an existing data with the same key
338*
339* Attaches a user-data key/data pair to the given subset input object.
340*
341* Return value: `true` if success, `false` otherwise
342*
343* Since: 2.9.0
344**/
345hb_bool_t
346hb_subset_input_set_user_data (hb_subset_input_t *input,347hb_user_data_key_t *key,348void * data,349hb_destroy_func_t destroy,350hb_bool_t replace)351{
352return hb_object_set_user_data (input, key, data, destroy, replace);353}
354
355/**
356* hb_subset_input_get_user_data: (skip)
357* @input: a #hb_subset_input_t object.
358* @key: The user-data key to query
359*
360* Fetches the user data associated with the specified key,
361* attached to the specified subset input object.
362*
363* Return value: (transfer none): A pointer to the user data
364*
365* Since: 2.9.0
366**/
367void *368hb_subset_input_get_user_data (const hb_subset_input_t *input,369hb_user_data_key_t *key)370{
371return hb_object_get_user_data (input, key);372}
373
374/**
375* hb_subset_input_keep_everything:
376* @input: a #hb_subset_input_t object
377*
378* Configure input object to keep everything in the font face.
379* That is, all Unicodes, glyphs, names, layout items,
380* glyph names, etc.
381*
382* The input can be tailored afterwards by the caller.
383*
384* Since: 7.0.0
385*/
386void
387hb_subset_input_keep_everything (hb_subset_input_t *input)388{
389const hb_subset_sets_t indices[] = {HB_SUBSET_SETS_UNICODE,390HB_SUBSET_SETS_GLYPH_INDEX,391HB_SUBSET_SETS_NAME_ID,392HB_SUBSET_SETS_NAME_LANG_ID,393HB_SUBSET_SETS_LAYOUT_FEATURE_TAG,394HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG};395
396for (auto idx : hb_iter (indices))397{398hb_set_t *set = hb_subset_input_set (input, idx);399hb_set_clear (set);400hb_set_invert (set);401}402
403// Don't drop any tables404hb_set_clear (hb_subset_input_set (input, HB_SUBSET_SETS_DROP_TABLE_TAG));405
406hb_subset_input_set_flags (input,407HB_SUBSET_FLAGS_NOTDEF_OUTLINE |408HB_SUBSET_FLAGS_GLYPH_NAMES |409HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES |410HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED);411}
412
413#ifndef HB_NO_VAR414/**
415* hb_subset_input_pin_axis_to_default: (skip)
416* @input: a #hb_subset_input_t object.
417* @face: a #hb_face_t object.
418* @axis_tag: Tag of the axis to be pinned
419*
420* Pin an axis to its default location in the given subset input object.
421*
422* All axes in a font must be pinned. Additionally, `CFF2` table, if present,
423* will be de-subroutinized.
424*
425* Return value: `true` if success, `false` otherwise
426*
427* Since: 6.0.0
428**/
429HB_EXTERN hb_bool_t
430hb_subset_input_pin_axis_to_default (hb_subset_input_t *input,431hb_face_t *face,432hb_tag_t axis_tag)433{
434hb_ot_var_axis_info_t axis_info;435if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info))436return false;437
438float default_val = axis_info.default_value;439return input->axes_location.set (axis_tag, Triple (default_val, default_val, default_val));440}
441
442/**
443* hb_subset_input_pin_axis_location: (skip)
444* @input: a #hb_subset_input_t object.
445* @face: a #hb_face_t object.
446* @axis_tag: Tag of the axis to be pinned
447* @axis_value: Location on the axis to be pinned at
448*
449* Pin an axis to a fixed location in the given subset input object.
450*
451* All axes in a font must be pinned. Additionally, `CFF2` table, if present,
452* will be de-subroutinized.
453*
454* Return value: `true` if success, `false` otherwise
455*
456* Since: 6.0.0
457**/
458HB_EXTERN hb_bool_t
459hb_subset_input_pin_axis_location (hb_subset_input_t *input,460hb_face_t *face,461hb_tag_t axis_tag,462float axis_value)463{
464hb_ot_var_axis_info_t axis_info;465if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info))466return false;467
468float val = hb_clamp(axis_value, axis_info.min_value, axis_info.max_value);469return input->axes_location.set (axis_tag, Triple (val, val, val));470}
471
472#ifdef HB_EXPERIMENTAL_API473/**
474* hb_subset_input_set_axis_range: (skip)
475* @input: a #hb_subset_input_t object.
476* @face: a #hb_face_t object.
477* @axis_tag: Tag of the axis
478* @axis_min_value: Minimum value of the axis variation range to set
479* @axis_max_value: Maximum value of the axis variation range to set
480* @axis_def_value: Default value of the axis variation range to set, in case of
481* null, it'll be determined automatically
482*
483* Restricting the range of variation on an axis in the given subset input object.
484* New min/default/max values will be clamped if they're not within the fvar axis range.
485* If the new default value is null:
486* If the fvar axis default value is within the new range, then new default
487* value is the same as original default value.
488* If the fvar axis default value is not within the new range, the new default
489* value will be changed to the new min or max value, whichever is closer to the fvar
490* axis default.
491*
492* Note: input min value can not be bigger than input max value. If the input
493* default value is not within the new min/max range, it'll be clamped.
494* Note: currently it supports gvar and cvar tables only.
495*
496* Return value: `true` if success, `false` otherwise
497*
498* XSince: EXPERIMENTAL
499**/
500HB_EXTERN hb_bool_t
501hb_subset_input_set_axis_range (hb_subset_input_t *input,502hb_face_t *face,503hb_tag_t axis_tag,504float axis_min_value,505float axis_max_value,506float *axis_def_value /* IN, maybe NULL */)507{
508if (axis_min_value > axis_max_value)509return false;510
511hb_ot_var_axis_info_t axis_info;512if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info))513return false;514
515float new_min_val = hb_clamp(axis_min_value, axis_info.min_value, axis_info.max_value);516float new_max_val = hb_clamp(axis_max_value, axis_info.min_value, axis_info.max_value);517float new_default_val = axis_def_value ? *axis_def_value : axis_info.default_value;518new_default_val = hb_clamp(new_default_val, new_min_val, new_max_val);519return input->axes_location.set (axis_tag, Triple (new_min_val, new_default_val, new_max_val));520}
521#endif522#endif523
524/**
525* hb_subset_preprocess:
526* @source: a #hb_face_t object.
527*
528* Preprocesses the face and attaches data that will be needed by the
529* subsetter. Future subsetting operations can then use the precomputed data
530* to speed up the subsetting operation.
531*
532* See [subset-preprocessing](https://github.com/harfbuzz/harfbuzz/blob/main/docs/subset-preprocessing.md)
533* for more information.
534*
535* Note: the preprocessed face may contain sub-blobs that reference the memory
536* backing the source #hb_face_t. Therefore in the case that this memory is not
537* owned by the source face you will need to ensure that memory lives
538* as long as the returned #hb_face_t.
539*
540* Returns: a new #hb_face_t.
541*
542* Since: 6.0.0
543**/
544
545HB_EXTERN hb_face_t *546hb_subset_preprocess (hb_face_t *source)547{
548hb_subset_input_t* input = hb_subset_input_create_or_fail ();549if (!input)550return hb_face_reference (source);551
552hb_subset_input_keep_everything (input);553
554input->attach_accelerator_data = true;555
556// Always use long loca in the preprocessed version. This allows557// us to store the glyph bytes unpadded which allows the future subset558// operation to run faster by skipping the trim padding step.559input->force_long_loca = true;560
561hb_face_t* new_source = hb_subset_or_fail (source, input);562hb_subset_input_destroy (input);563
564if (!new_source) {565DEBUG_MSG (SUBSET, nullptr, "Preprocessing failed due to subset failure.");566return hb_face_reference (source);567}568
569return new_source;570}
571
572/**
573* hb_subset_input_old_to_new_glyph_mapping:
574* @input: a #hb_subset_input_t object.
575*
576* Returns a map which can be used to provide an explicit mapping from old to new glyph
577* id's in the produced subset. The caller should populate the map as desired.
578* If this map is left empty then glyph ids will be automatically mapped to new
579* values by the subsetter. If populated, the mapping must be unique. That
580* is no two original glyph ids can be mapped to the same new id.
581* Additionally, if a mapping is provided then the retain gids option cannot
582* be enabled.
583*
584* Any glyphs that are retained in the subset which are not specified
585* in this mapping will be assigned glyph ids after the highest glyph
586* id in the mapping.
587*
588* Note: this will accept and apply non-monotonic mappings, however this
589* may result in unsorted Coverage tables. Such fonts may not work for all
590* use cases (for example ots will reject unsorted coverage tables). So it's
591* recommended, if possible, to supply a monotonic mapping.
592*
593* Return value: (transfer none): pointer to the #hb_map_t of the custom glyphs ID map.
594*
595* Since: 7.3.0
596**/
597HB_EXTERN hb_map_t*598hb_subset_input_old_to_new_glyph_mapping (hb_subset_input_t *input)599{
600return &input->glyph_map;601}
602
603#ifdef HB_EXPERIMENTAL_API604/**
605* hb_subset_input_override_name_table:
606* @input: a #hb_subset_input_t object.
607* @name_id: name_id of a nameRecord
608* @platform_id: platform ID of a nameRecord
609* @encoding_id: encoding ID of a nameRecord
610* @language_id: language ID of a nameRecord
611* @name_str: pointer to name string new value or null to indicate should remove
612* @str_len: the size of @name_str, or -1 if it is `NULL`-terminated
613*
614* Override the name string of the NameRecord identified by name_id,
615* platform_id, encoding_id and language_id. If a record with that name_id
616* doesn't exist, create it and insert to the name table.
617*
618* Note: for mac platform, we only support name_str with all ascii characters,
619* name_str with non-ascii characters will be ignored.
620*
621* XSince: EXPERIMENTAL
622**/
623HB_EXTERN hb_bool_t
624hb_subset_input_override_name_table (hb_subset_input_t *input,625hb_ot_name_id_t name_id,626unsigned platform_id,627unsigned encoding_id,628unsigned language_id,629const char *name_str,630int str_len /* -1 means nul-terminated */)631{
632if (!name_str)633{634str_len = 0;635}636else if (str_len == -1)637{638str_len = strlen (name_str);639}640
641hb_bytes_t name_bytes (nullptr, 0);642if (str_len)643{644if (platform_id == 1)645{646const uint8_t *src = reinterpret_cast<const uint8_t*> (name_str);647const uint8_t *src_end = src + str_len;648
649hb_codepoint_t unicode;650const hb_codepoint_t replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;651while (src < src_end)652{653src = hb_utf8_t::next (src, src_end, &unicode, replacement);654if (unicode >= 0x0080u)655{656printf ("Non-ascii character detected, ignored...This API supports acsii characters only for mac platform\n");657return false;658}659}660}661char *override_name = (char *) hb_malloc (str_len);662if (unlikely (!override_name)) return false;663
664hb_memcpy (override_name, name_str, str_len);665name_bytes = hb_bytes_t (override_name, str_len);666}667input->name_table_overrides.set (hb_ot_name_record_ids_t (platform_id, encoding_id, language_id, name_id), name_bytes);668return true;669}
670
671#endif672