Path: blob/master/src/java.desktop/share/native/libharfbuzz/hb-face.cc
41149 views
/*1* Copyright © 2009 Red Hat, Inc.2* Copyright © 2012 Google, Inc.3*4* This is part of HarfBuzz, a text shaping library.5*6* Permission is hereby granted, without written agreement and without7* license or royalty fees, to use, copy, modify, and distribute this8* software and its documentation for any purpose, provided that the9* above copyright notice and the following two paragraphs appear in10* all copies of this software.11*12* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR13* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES14* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN15* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH16* DAMAGE.17*18* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,19* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND20* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS21* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO22* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.23*24* Red Hat Author(s): Behdad Esfahbod25* Google Author(s): Behdad Esfahbod26*/2728#include "hb.hh"2930#include "hb-face.hh"31#include "hb-blob.hh"32#include "hb-open-file.hh"33#include "hb-ot-face.hh"34#include "hb-ot-cmap-table.hh"353637/**38* SECTION:hb-face39* @title: hb-face40* @short_description: Font face objects41* @include: hb.h42*43* A font face is an object that represents a single face from within a44* font family.45*46* More precisely, a font face represents a single face in a binary font file.47* Font faces are typically built from a binary blob and a face index.48* Font faces are used to create fonts.49**/505152/**53* hb_face_count:54* @blob: a blob.55*56* Fetches the number of faces in a blob.57*58* Return value: Number of faces in @blob59*60* Since: 1.7.761**/62unsigned int63hb_face_count (hb_blob_t *blob)64{65if (unlikely (!blob))66return 0;6768/* TODO We shouldn't be sanitizing blob. Port to run sanitizer and return if not sane. */69/* Make API signature const after. */70hb_blob_t *sanitized = hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob));71const OT::OpenTypeFontFile& ot = *sanitized->as<OT::OpenTypeFontFile> ();72unsigned int ret = ot.get_face_count ();73hb_blob_destroy (sanitized);7475return ret;76}7778/*79* hb_face_t80*/8182DEFINE_NULL_INSTANCE (hb_face_t) =83{84HB_OBJECT_HEADER_STATIC,8586nullptr, /* reference_table_func */87nullptr, /* user_data */88nullptr, /* destroy */89900, /* index */911000, /* upem */920, /* num_glyphs */9394/* Zero for the rest is fine. */95};969798/**99* hb_face_create_for_tables:100* @reference_table_func: (closure user_data) (destroy destroy) (scope notified): Table-referencing function101* @user_data: A pointer to the user data102* @destroy: (nullable): A callback to call when @data is not needed anymore103*104* Variant of hb_face_create(), built for those cases where it is more105* convenient to provide data for individual tables instead of the whole font106* data. With the caveat that hb_face_get_table_tags() does not currently work107* with faces created this way.108*109* Creates a new face object from the specified @user_data and @reference_table_func,110* with the @destroy callback.111*112* Return value: (transfer full): The new face object113*114* Since: 0.9.2115**/116hb_face_t *117hb_face_create_for_tables (hb_reference_table_func_t reference_table_func,118void *user_data,119hb_destroy_func_t destroy)120{121hb_face_t *face;122123if (!reference_table_func || !(face = hb_object_create<hb_face_t> ())) {124if (destroy)125destroy (user_data);126return hb_face_get_empty ();127}128129face->reference_table_func = reference_table_func;130face->user_data = user_data;131face->destroy = destroy;132133face->num_glyphs.set_relaxed (-1);134135face->data.init0 (face);136face->table.init0 (face);137138return face;139}140141142typedef struct hb_face_for_data_closure_t {143hb_blob_t *blob;144unsigned int index;145} hb_face_for_data_closure_t;146147static hb_face_for_data_closure_t *148_hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index)149{150hb_face_for_data_closure_t *closure;151152closure = (hb_face_for_data_closure_t *) calloc (1, sizeof (hb_face_for_data_closure_t));153if (unlikely (!closure))154return nullptr;155156closure->blob = blob;157closure->index = index;158159return closure;160}161162static void163_hb_face_for_data_closure_destroy (void *data)164{165hb_face_for_data_closure_t *closure = (hb_face_for_data_closure_t *) data;166167hb_blob_destroy (closure->blob);168free (closure);169}170171static hb_blob_t *172_hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)173{174hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) user_data;175176if (tag == HB_TAG_NONE)177return hb_blob_reference (data->blob);178179const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> ();180unsigned int base_offset;181const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index, &base_offset);182183const OT::OpenTypeTable &table = ot_face.get_table_by_tag (tag);184185hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, base_offset + table.offset, table.length);186187return blob;188}189190/**191* hb_face_create: (Xconstructor)192* @blob: #hb_blob_t to work upon193* @index: The index of the face within @blob194*195* Constructs a new face object from the specified blob and196* a face index into that blob. This is used for blobs of197* file formats such as Dfont and TTC that can contain more198* than one face.199*200* Return value: (transfer full): The new face object201*202* Since: 0.9.2203**/204hb_face_t *205hb_face_create (hb_blob_t *blob,206unsigned int index)207{208hb_face_t *face;209210if (unlikely (!blob))211blob = hb_blob_get_empty ();212213blob = hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob));214215hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (blob, index);216217if (unlikely (!closure))218{219hb_blob_destroy (blob);220return hb_face_get_empty ();221}222223face = hb_face_create_for_tables (_hb_face_for_data_reference_table,224closure,225_hb_face_for_data_closure_destroy);226227face->index = index;228229return face;230}231232/**233* hb_face_get_empty:234*235* Fetches the singleton empty face object.236*237* Return value: (transfer full): The empty face object238*239* Since: 0.9.2240**/241hb_face_t *242hb_face_get_empty ()243{244return const_cast<hb_face_t *> (&Null (hb_face_t));245}246247248/**249* hb_face_reference: (skip)250* @face: A face object251*252* Increases the reference count on a face object.253*254* Return value: The @face object255*256* Since: 0.9.2257**/258hb_face_t *259hb_face_reference (hb_face_t *face)260{261return hb_object_reference (face);262}263264/**265* hb_face_destroy: (skip)266* @face: A face object267*268* Decreases the reference count on a face object. When the269* reference count reaches zero, the face is destroyed,270* freeing all memory.271*272* Since: 0.9.2273**/274void275hb_face_destroy (hb_face_t *face)276{277if (!hb_object_destroy (face)) return;278279for (hb_face_t::plan_node_t *node = face->shape_plans; node; )280{281hb_face_t::plan_node_t *next = node->next;282hb_shape_plan_destroy (node->shape_plan);283free (node);284node = next;285}286287face->data.fini ();288face->table.fini ();289290if (face->destroy)291face->destroy (face->user_data);292293free (face);294}295296/**297* hb_face_set_user_data: (skip)298* @face: A face object299* @key: The user-data key to set300* @data: A pointer to the user data301* @destroy: (nullable): A callback to call when @data is not needed anymore302* @replace: Whether to replace an existing data with the same key303*304* Attaches a user-data key/data pair to the given face object.305*306* Return value: %true if success, %false otherwise307*308* Since: 0.9.2309**/310hb_bool_t311hb_face_set_user_data (hb_face_t *face,312hb_user_data_key_t *key,313void * data,314hb_destroy_func_t destroy,315hb_bool_t replace)316{317return hb_object_set_user_data (face, key, data, destroy, replace);318}319320/**321* hb_face_get_user_data: (skip)322* @face: A face object323* @key: The user-data key to query324*325* Fetches the user data associated with the specified key,326* attached to the specified face object.327*328* Return value: (transfer none): A pointer to the user data329*330* Since: 0.9.2331**/332void *333hb_face_get_user_data (const hb_face_t *face,334hb_user_data_key_t *key)335{336return hb_object_get_user_data (face, key);337}338339/**340* hb_face_make_immutable:341* @face: A face object342*343* Makes the given face object immutable.344*345* Since: 0.9.2346**/347void348hb_face_make_immutable (hb_face_t *face)349{350if (hb_object_is_immutable (face))351return;352353hb_object_make_immutable (face);354}355356/**357* hb_face_is_immutable:358* @face: A face object359*360* Tests whether the given face object is immutable.361*362* Return value: %true is @face is immutable, %false otherwise363*364* Since: 0.9.2365**/366hb_bool_t367hb_face_is_immutable (const hb_face_t *face)368{369return hb_object_is_immutable (face);370}371372373/**374* hb_face_reference_table:375* @face: A face object376* @tag: The #hb_tag_t of the table to query377*378* Fetches a reference to the specified table within379* the specified face.380*381* Return value: (transfer full): A pointer to the @tag table within @face382*383* Since: 0.9.2384**/385hb_blob_t *386hb_face_reference_table (const hb_face_t *face,387hb_tag_t tag)388{389if (unlikely (tag == HB_TAG_NONE))390return hb_blob_get_empty ();391392return face->reference_table (tag);393}394395/**396* hb_face_reference_blob:397* @face: A face object398*399* Fetches a pointer to the binary blob that contains the400* specified face. Returns an empty blob if referencing face data is not401* possible.402*403* Return value: (transfer full): A pointer to the blob for @face404*405* Since: 0.9.2406**/407hb_blob_t *408hb_face_reference_blob (hb_face_t *face)409{410return face->reference_table (HB_TAG_NONE);411}412413/**414* hb_face_set_index:415* @face: A face object416* @index: The index to assign417*418* Assigns the specified face-index to @face. Fails if the419* face is immutable.420*421* <note>Note: face indices within a collection are zero-based.</note>422*423* Since: 0.9.2424**/425void426hb_face_set_index (hb_face_t *face,427unsigned int index)428{429if (hb_object_is_immutable (face))430return;431432face->index = index;433}434435/**436* hb_face_get_index:437* @face: A face object438*439* Fetches the face-index corresponding to the given face.440*441* <note>Note: face indices within a collection are zero-based.</note>442*443* Return value: The index of @face.444*445* Since: 0.9.2446**/447unsigned int448hb_face_get_index (const hb_face_t *face)449{450return face->index;451}452453/**454* hb_face_set_upem:455* @face: A face object456* @upem: The units-per-em value to assign457*458* Sets the units-per-em (upem) for a face object to the specified value.459*460* Since: 0.9.2461**/462void463hb_face_set_upem (hb_face_t *face,464unsigned int upem)465{466if (hb_object_is_immutable (face))467return;468469face->upem.set_relaxed (upem);470}471472/**473* hb_face_get_upem:474* @face: A face object475*476* Fetches the units-per-em (upem) value of the specified face object.477*478* Return value: The upem value of @face479*480* Since: 0.9.2481**/482unsigned int483hb_face_get_upem (const hb_face_t *face)484{485return face->get_upem ();486}487488/**489* hb_face_set_glyph_count:490* @face: A face object491* @glyph_count: The glyph-count value to assign492*493* Sets the glyph count for a face object to the specified value.494*495* Since: 0.9.7496**/497void498hb_face_set_glyph_count (hb_face_t *face,499unsigned int glyph_count)500{501if (hb_object_is_immutable (face))502return;503504face->num_glyphs.set_relaxed (glyph_count);505}506507/**508* hb_face_get_glyph_count:509* @face: A face object510*511* Fetches the glyph-count value of the specified face object.512*513* Return value: The glyph-count value of @face514*515* Since: 0.9.7516**/517unsigned int518hb_face_get_glyph_count (const hb_face_t *face)519{520return face->get_num_glyphs ();521}522523/**524* hb_face_get_table_tags:525* @face: A face object526* @start_offset: The index of first table tag to retrieve527* @table_count: (inout): Input = the maximum number of table tags to return;528* Output = the actual number of table tags returned (may be zero)529* @table_tags: (out) (array length=table_count): The array of table tags found530*531* Fetches a list of all table tags for a face, if possible. The list returned will532* begin at the offset provided533*534* Return value: Total number of tables, or zero if it is not possible to list535*536* Since: 1.6.0537**/538unsigned int539hb_face_get_table_tags (const hb_face_t *face,540unsigned int start_offset,541unsigned int *table_count, /* IN/OUT */542hb_tag_t *table_tags /* OUT */)543{544if (face->destroy != (hb_destroy_func_t) _hb_face_for_data_closure_destroy)545{546if (table_count)547*table_count = 0;548return 0;549}550551hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) face->user_data;552553const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> ();554const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index);555556return ot_face.get_table_tags (start_offset, table_count, table_tags);557}558559560/*561* Character set.562*/563564565#ifndef HB_NO_FACE_COLLECT_UNICODES566/**567* hb_face_collect_unicodes:568* @face: A face object569* @out: The set to add Unicode characters to570*571* Collects all of the Unicode characters covered by @face and adds572* them to the #hb_set_t set @out.573*574* Since: 1.9.0575*/576void577hb_face_collect_unicodes (hb_face_t *face,578hb_set_t *out)579{580face->table.cmap->collect_unicodes (out, face->get_num_glyphs ());581}582/**583* hb_face_collect_variation_selectors:584* @face: A face object585* @out: The set to add Variation Selector characters to586*587* Collects all Unicode "Variation Selector" characters covered by @face and adds588* them to the #hb_set_t set @out.589*590* Since: 1.9.0591*/592void593hb_face_collect_variation_selectors (hb_face_t *face,594hb_set_t *out)595{596face->table.cmap->collect_variation_selectors (out);597}598/**599* hb_face_collect_variation_unicodes:600* @face: A face object601* @variation_selector: The Variation Selector to query602* @out: The set to add Unicode characters to603*604* Collects all Unicode characters for @variation_selector covered by @face and adds605* them to the #hb_set_t set @out.606*607* Since: 1.9.0608*/609void610hb_face_collect_variation_unicodes (hb_face_t *face,611hb_codepoint_t variation_selector,612hb_set_t *out)613{614face->table.cmap->collect_variation_unicodes (variation_selector, out);615}616#endif617618619/*620* face-builder: A face that has add_table().621*/622623struct hb_face_builder_data_t624{625struct table_entry_t626{627int cmp (hb_tag_t t) const628{629if (t < tag) return -1;630if (t > tag) return -1;631return 0;632}633634hb_tag_t tag;635hb_blob_t *blob;636};637638hb_vector_t<table_entry_t> tables;639};640641static hb_face_builder_data_t *642_hb_face_builder_data_create ()643{644hb_face_builder_data_t *data = (hb_face_builder_data_t *) calloc (1, sizeof (hb_face_builder_data_t));645if (unlikely (!data))646return nullptr;647648data->tables.init ();649650return data;651}652653static void654_hb_face_builder_data_destroy (void *user_data)655{656hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;657658for (unsigned int i = 0; i < data->tables.length; i++)659hb_blob_destroy (data->tables[i].blob);660661data->tables.fini ();662663free (data);664}665666static hb_blob_t *667_hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)668{669670unsigned int table_count = data->tables.length;671unsigned int face_length = table_count * 16 + 12;672673for (unsigned int i = 0; i < table_count; i++)674face_length += hb_ceil_to_4 (hb_blob_get_length (data->tables[i].blob));675676char *buf = (char *) malloc (face_length);677if (unlikely (!buf))678return nullptr;679680hb_serialize_context_t c (buf, face_length);681c.propagate_error (data->tables);682OT::OpenTypeFontFile *f = c.start_serialize<OT::OpenTypeFontFile> ();683684bool is_cff = data->tables.lsearch (HB_TAG ('C','F','F',' ')) || data->tables.lsearch (HB_TAG ('C','F','F','2'));685hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag;686687bool ret = f->serialize_single (&c, sfnt_tag, data->tables.as_array ());688689c.end_serialize ();690691if (unlikely (!ret))692{693free (buf);694return nullptr;695}696697return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, free);698}699700static hb_blob_t *701_hb_face_builder_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)702{703hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;704705if (!tag)706return _hb_face_builder_data_reference_blob (data);707708hb_face_builder_data_t::table_entry_t *entry = data->tables.lsearch (tag);709if (entry)710return hb_blob_reference (entry->blob);711712return nullptr;713}714715716/**717* hb_face_builder_create:718*719* Creates a #hb_face_t that can be used with hb_face_builder_add_table().720* After tables are added to the face, it can be compiled to a binary721* font file by calling hb_face_reference_blob().722*723* Return value: (transfer full): New face.724*725* Since: 1.9.0726**/727hb_face_t *728hb_face_builder_create ()729{730hb_face_builder_data_t *data = _hb_face_builder_data_create ();731if (unlikely (!data)) return hb_face_get_empty ();732733return hb_face_create_for_tables (_hb_face_builder_reference_table,734data,735_hb_face_builder_data_destroy);736}737738/**739* hb_face_builder_add_table:740* @face: A face object created with hb_face_builder_create()741* @tag: The #hb_tag_t of the table to add742* @blob: The blob containing the table data to add743*744* Add table for @tag with data provided by @blob to the face. @face must745* be created using hb_face_builder_create().746*747* Since: 1.9.0748**/749hb_bool_t750hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)751{752if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy))753return false;754755hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;756757hb_face_builder_data_t::table_entry_t *entry = data->tables.push ();758if (unlikely (data->tables.in_error()))759return false;760761entry->tag = tag;762entry->blob = hb_blob_reference (blob);763764return true;765}766767768