Merge pull request #4895 from harfbuzz/coretext-font

Coretext font
pull/4905/head
Behdad Esfahbod 4 months ago committed by GitHub
commit 35f67618e8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 5
      docs/harfbuzz-sections.txt
  2. 44
      perf/benchmark-font.cc
  3. 9
      perf/benchmark-map.cc
  4. 7
      perf/benchmark-ot.cc
  5. 9
      perf/benchmark-set.cc
  6. 21
      perf/benchmark-shape.cc
  7. 17
      perf/benchmark-subset.cc
  8. 76
      perf/hb-benchmark.hh
  9. 8
      perf/meson.build
  10. 3
      src/harfbuzz.cc
  11. 5
      src/hb-blob.cc
  12. 461
      src/hb-coretext-font.cc
  13. 71
      src/hb-coretext-shape.cc
  14. 17
      src/hb-coretext.h
  15. 55
      src/hb-face.cc
  16. 8
      src/hb-face.h
  17. 125
      src/hb-ft.cc
  18. 3
      src/hb-ft.h
  19. 2
      src/hb-ms-feature-ranges.hh
  20. 4
      src/hb-ot-font.cc
  21. 2
      src/meson.build
  22. 3
      test/shape/data/in-house/tests/collections.tests
  23. 103
      util/face-options.hh
  24. 19
      util/font-options.hh
  25. 2
      util/hb-info.cc
  26. 24
      util/helper-cairo-ft.hh
  27. 8
      util/test-hb-subset-parsing.c

@ -340,9 +340,11 @@ HB_CORETEXT_TAG_KERX
HB_CORETEXT_TAG_MORT
HB_CORETEXT_TAG_MORX
hb_coretext_face_create
hb_coretext_face_create_from_file_or_fail
hb_coretext_font_create
hb_coretext_face_get_cg_font
hb_coretext_font_get_ct_font
hb_coretext_font_set_funcs
</SECTION>
<SECTION>
@ -356,6 +358,8 @@ hb_directwrite_face_get_font_face
hb_face_count
hb_face_t
hb_face_create
hb_face_create_or_fail
hb_face_create_from_file_or_fail
hb_reference_table_func_t
hb_face_create_for_tables
hb_face_get_empty
@ -513,6 +517,7 @@ hb_glyph_extents_t
hb_ft_face_create
hb_ft_face_create_cached
hb_ft_face_create_referenced
hb_ft_face_create_from_file_or_fail
hb_ft_font_create
hb_ft_font_create_referenced
hb_ft_font_changed

@ -1,17 +1,4 @@
#include "benchmark/benchmark.h"
#include <cassert>
#include <cstring>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "hb.h"
#include "hb-ot.h"
#ifdef HAVE_FREETYPE
#include "hb-ft.h"
#endif
#include "hb-benchmark.hh"
#define SUBSET_FONT_BASE_PATH "test/subset/data/fonts/"
@ -34,7 +21,7 @@ struct test_input_t
static test_input_t *tests = default_tests;
static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]);
enum backend_t { HARFBUZZ, FREETYPE };
enum backend_t { HARFBUZZ, FREETYPE, CORETEXT };
enum operation_t
{
@ -100,10 +87,8 @@ static void BM_Font (benchmark::State &state,
hb_font_t *font;
unsigned num_glyphs;
{
hb_blob_t *blob = hb_blob_create_from_file_or_fail (test_input.font_path);
assert (blob);
hb_face_t *face = hb_face_create (blob, 0);
hb_blob_destroy (blob);
hb_face_t *face = hb_benchmark_face_create_from_file_or_fail (test_input.font_path, 0);
assert (face);
num_glyphs = hb_face_get_glyph_count (face);
font = hb_font_create (face);
hb_face_destroy (face);
@ -124,6 +109,12 @@ static void BM_Font (benchmark::State &state,
case FREETYPE:
#ifdef HAVE_FREETYPE
hb_ft_font_set_funcs (font);
#endif
break;
case CORETEXT:
#ifdef HAVE_CORETEXT
hb_coretext_font_set_funcs (font);
#endif
break;
}
@ -208,10 +199,8 @@ static void BM_Font (benchmark::State &state,
{
for (auto _ : state)
{
hb_blob_t *blob = hb_blob_create_from_file_or_fail (test_input.font_path);
assert (blob);
hb_face_t *face = hb_face_create (blob, 0);
hb_blob_destroy (blob);
hb_face_t *face = hb_benchmark_face_create_from_file_or_fail (test_input.font_path, 0);
assert (face);
hb_font_t *font = hb_font_create (face);
hb_face_destroy (face);
@ -224,6 +213,12 @@ static void BM_Font (benchmark::State &state,
case FREETYPE:
#ifdef HAVE_FREETYPE
hb_ft_font_set_funcs (font);
#endif
break;
case CORETEXT:
#ifdef HAVE_CORETEXT
hb_coretext_font_set_funcs (font);
#endif
break;
}
@ -280,6 +275,9 @@ static void test_operation (operation_t op,
test_backend (HARFBUZZ, "hb", is_var, op, op_name, time_unit, test_input);
#ifdef HAVE_FREETYPE
test_backend (FREETYPE, "ft", is_var, op, op_name, time_unit, test_input);
#endif
#ifdef HAVE_CORETEXT
test_backend (CORETEXT, "coretext", is_var, op, op_name, time_unit, test_input);
#endif
}
}

@ -1,11 +1,4 @@
/*
* Benchmarks for hb_map_t operations.
*/
#include "benchmark/benchmark.h"
#include <cassert>
#include <cstdlib>
#include "hb.h"
#include "hb-benchmark.hh"
void RandomMap(unsigned size, hb_map_t* out, hb_set_t* key_sample) {
hb_map_clear(out);

@ -1,9 +1,4 @@
/*
* Benchmarks for hb_set_t operations.
*/
#include "benchmark/benchmark.h"
#include "hb-ot.h"
#include "hb-benchmark.hh"
static void BM_hb_ot_tags_from_script_and_language (benchmark::State& state,
hb_script_t script,

@ -1,11 +1,4 @@
/*
* Benchmarks for hb_set_t operations.
*/
#include "benchmark/benchmark.h"
#include <cassert>
#include <cstdlib>
#include "hb.h"
#include "hb-benchmark.hh"
void RandomSet(unsigned size, unsigned max_value, hb_set_t* out) {
hb_set_clear(out);

@ -1,17 +1,4 @@
#include "benchmark/benchmark.h"
#include <cstring>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <cassert>
#include "hb.h"
#include "hb-ot.h"
#ifdef HAVE_FREETYPE
#include "hb-ft.h"
#endif
#include "hb-benchmark.hh"
#define SUBSET_FONT_BASE_PATH "test/subset/data/fonts/"
@ -64,10 +51,8 @@ static void BM_Shape (benchmark::State &state,
{
hb_font_t *font;
{
hb_blob_t *blob = hb_blob_create_from_file_or_fail (input.font_path);
assert (blob);
hb_face_t *face = hb_face_create (blob, 0);
hb_blob_destroy (blob);
hb_face_t *face = hb_benchmark_face_create_from_file_or_fail (input.font_path, 0);
assert (face);
font = hb_font_create (face);
hb_face_destroy (face);
}

@ -1,13 +1,4 @@
#include "benchmark/benchmark.h"
#include <cassert>
#include <cstring>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "hb-subset.h"
#include "hb-benchmark.hh"
enum operation_t
{
@ -148,10 +139,8 @@ static void BM_subset (benchmark::State &state,
if (!cached_font_path || strcmp (cached_font_path, test_input.font_path))
{
hb_blob_t *blob = hb_blob_create_from_file_or_fail (test_input.font_path);
assert (blob);
face = hb_face_create (blob, 0);
hb_blob_destroy (blob);
hb_face_t *face = hb_benchmark_face_create_from_file_or_fail (test_input.font_path, 0);
assert (face);
face = preprocess_face (face);

@ -0,0 +1,76 @@
/*
* Copyright © 2024 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Author(s): Behdad Esfahbod
*/
#ifndef HB_BENCHMARK_HH
#define HB_BENCHMARK_HH
#include <hb-config.hh>
#include <hb.h>
#include <hb-subset.h>
#include <hb-ot.h>
#ifdef HAVE_FREETYPE
#include <hb-ft.h>
#endif
#ifdef HAVE_CORETEXT
#include <hb-coretext.h>
#endif
#include <benchmark/benchmark.h>
#include <cassert>
#include <cstdlib>
#include <cstring>
HB_BEGIN_DECLS
static inline hb_face_t *
hb_benchmark_face_create_from_file_or_fail (const char *font_path,
unsigned face_index)
{
const char *loader = getenv ("HB_FACE_LOADER");
if (loader && !*loader)
loader = nullptr;
#ifdef HAVE_FREETYPE
if (loader && !strcmp (loader, "ft"))
return hb_ft_face_create_from_file_or_fail (font_path, face_index);
#endif
#ifdef HAVE_CORETEXT
if (loader && !strcmp (loader, "coretext"))
return hb_coretext_face_create_from_file_or_fail (font_path, face_index);
#endif
if (!loader || !strcmp (loader, "ot"))
return hb_face_create_from_file_or_fail (font_path, face_index);
assert (false);
}
HB_END_DECLS
#endif /* HB_BENCHMARK_HH */

@ -13,7 +13,7 @@ benchmark('benchmark-font', executable('benchmark-font', 'benchmark-font.cc',
benchmark('benchmark-map', executable('benchmark-map', 'benchmark-map.cc',
dependencies: [
google_benchmark_dep,
google_benchmark_dep, freetype_dep,
],
cpp_args: [],
include_directories: [incconfig, incsrc],
@ -23,7 +23,7 @@ benchmark('benchmark-map', executable('benchmark-map', 'benchmark-map.cc',
benchmark('benchmark-ot', executable('benchmark-ot', 'benchmark-ot.cc',
dependencies: [
google_benchmark_dep,
google_benchmark_dep, freetype_dep,
],
cpp_args: [],
include_directories: [incconfig, incsrc],
@ -33,7 +33,7 @@ benchmark('benchmark-ot', executable('benchmark-ot', 'benchmark-ot.cc',
benchmark('benchmark-set', executable('benchmark-set', 'benchmark-set.cc',
dependencies: [
google_benchmark_dep,
google_benchmark_dep, freetype_dep,
],
cpp_args: [],
include_directories: [incconfig, incsrc],
@ -53,7 +53,7 @@ benchmark('benchmark-shape', executable('benchmark-shape', 'benchmark-shape.cc',
benchmark('benchmark-subset', executable('benchmark-subset', 'benchmark-subset.cc',
dependencies: [
google_benchmark_dep,
google_benchmark_dep, freetype_dep,
],
cpp_args: [],
include_directories: [incconfig, incsrc],

@ -6,7 +6,8 @@
#include "hb-buffer-verify.cc"
#include "hb-buffer.cc"
#include "hb-common.cc"
#include "hb-coretext.cc"
#include "hb-coretext-font.cc"
#include "hb-coretext-shape.cc"
#include "hb-directwrite.cc"
#include "hb-draw.cc"
#include "hb-face-builder.cc"

@ -617,10 +617,9 @@ hb_blob_create_from_file (const char *file_name)
/**
* hb_blob_create_from_file_or_fail:
* @file_name: A font filename
* @file_name: A filename
*
* Creates a new blob containing the data from the
* specified binary font file.
* Creates a new blob containing the data from the specified file.
*
* The filename is passed directly to the system on all platforms,
* except on Windows, where the filename is interpreted as UTF-8.

@ -0,0 +1,461 @@
/*
* Copyright © 2024 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Author(s): Behdad Esfahbod
*/
#include "hb.hh"
#ifdef HAVE_CORETEXT
#include "hb-coretext.h"
#include "hb-draw.hh"
#include "hb-font.hh"
#include "hb-machinery.hh"
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101100
# define kCTFontOrientationDefault kCTFontDefaultOrientation
#endif
#define MAX_GLYPHS 64u
static void
_hb_coretext_font_destroy (void *font_data)
{
CTFontRef ct_font = (CTFontRef) font_data;
CFRelease (ct_font);
}
static hb_bool_t
hb_coretext_get_nominal_glyph (hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t unicode,
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
CTFontRef ct_font = (CTFontRef) font_data;
UniChar ch = unicode;
CGGlyph cg_glyph;
if (CTFontGetGlyphsForCharacters (ct_font, &ch, &cg_glyph, 1))
{
*glyph = cg_glyph;
return true;
}
return false;
}
static unsigned int
hb_coretext_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
void *font_data,
unsigned int count,
const hb_codepoint_t *first_unicode,
unsigned int unicode_stride,
hb_codepoint_t *first_glyph,
unsigned int glyph_stride,
void *user_data HB_UNUSED)
{
CTFontRef ct_font = (CTFontRef) font_data;
UniChar ch[MAX_GLYPHS];
CGGlyph cg_glyph[MAX_GLYPHS];
for (unsigned i = 0; i < count; i += MAX_GLYPHS)
{
unsigned c = (unsigned) hb_min ((int) MAX_GLYPHS, (int) count - (int) i);
for (unsigned j = 0; j < c; j++)
{
ch[j] = *first_unicode;
first_unicode = &StructAtOffset<const hb_codepoint_t> (first_unicode, unicode_stride);
}
CTFontGetGlyphsForCharacters (ct_font, ch, cg_glyph, c);
for (unsigned j = 0; j < c; j++)
{
*first_glyph = cg_glyph[j];
first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
}
}
return count;
}
static hb_bool_t
hb_coretext_get_variation_glyph (hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t unicode,
hb_codepoint_t variation_selector,
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
CTFontRef ct_font = (CTFontRef) font_data;
UniChar ch[2] = { unicode, variation_selector };
CGGlyph cg_glyph[2];
CTFontGetGlyphsForCharacters (ct_font, ch, cg_glyph, 2);
if (cg_glyph[1])
return false;
*glyph = cg_glyph[0];
return true;
}
static void
hb_coretext_get_glyph_h_advances (hb_font_t* font, void* font_data,
unsigned count,
const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride,
void *user_data HB_UNUSED)
{
CTFontRef ct_font = (CTFontRef) font_data;
CGFloat ct_font_size = CTFontGetSize (ct_font);
CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
CGGlyph cg_glyph[MAX_GLYPHS];
CGSize advances[MAX_GLYPHS];
for (unsigned i = 0; i < count; i += MAX_GLYPHS)
{
unsigned c = (unsigned) hb_min ((int) MAX_GLYPHS, (int) count - (int) i);
for (unsigned j = 0; j < c; j++)
{
cg_glyph[j] = *first_glyph;
first_glyph = &StructAtOffset<const hb_codepoint_t> (first_glyph, glyph_stride);
}
CTFontGetAdvancesForGlyphs (ct_font, kCTFontOrientationHorizontal, cg_glyph, advances, c);
for (unsigned j = 0; j < c; j++)
{
*first_advance = round (advances[j].width * x_mult);
first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
}
}
}
#ifndef HB_NO_VERTICAL
static void
hb_coretext_get_glyph_v_advances (hb_font_t* font, void* font_data,
unsigned count,
const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride,
void *user_data HB_UNUSED)
{
CTFontRef ct_font = (CTFontRef) font_data;
CGFloat ct_font_size = CTFontGetSize (ct_font);
CGFloat y_mult = (CGFloat) -font->y_scale / ct_font_size;
CGGlyph cg_glyph[MAX_GLYPHS];
CGSize advances[MAX_GLYPHS];
for (unsigned i = 0; i < count; i += MAX_GLYPHS)
{
unsigned c = (unsigned) hb_min ((int) MAX_GLYPHS, (int) count - (int) i);
for (unsigned j = 0; j < c; j++)
{
cg_glyph[j] = *first_glyph;
first_glyph = &StructAtOffset<const hb_codepoint_t> (first_glyph, glyph_stride);
}
CTFontGetAdvancesForGlyphs (ct_font, kCTFontOrientationVertical, cg_glyph, advances, c);
for (unsigned j = 0; j < c; j++)
{
*first_advance = round (advances[j].width * y_mult);
first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
}
}
}
#endif
#ifndef HB_NO_VERTICAL
static hb_bool_t
hb_coretext_get_glyph_v_origin (hb_font_t *font,
void *font_data,
hb_codepoint_t glyph,
hb_position_t *x,
hb_position_t *y,
void *user_data HB_UNUSED)
{
CTFontRef ct_font = (CTFontRef) font_data;
CGFloat ct_font_size = CTFontGetSize (ct_font);
CGFloat x_mult = (CGFloat) -font->x_scale / ct_font_size;
CGFloat y_mult = (CGFloat) -font->y_scale / ct_font_size;
const CGGlyph glyphs = glyph;
CGSize origin;
CTFontGetVerticalTranslationsForGlyphs (ct_font, &glyphs, &origin, 1);
*x = round (x_mult * origin.width);
*y = round (y_mult * origin.height);
return true;
}
#endif
static hb_bool_t
hb_coretext_get_glyph_extents (hb_font_t *font,
void *font_data,
hb_codepoint_t glyph,
hb_glyph_extents_t *extents,
void *user_data HB_UNUSED)
{
CTFontRef ct_font = (CTFontRef) font_data;
CGFloat ct_font_size = CTFontGetSize (ct_font);
CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size;
CGGlyph glyphs[1] = { glyph };
CGRect bounds = ::CTFontGetBoundingRectsForGlyphs(ct_font,
kCTFontOrientationDefault, glyphs, NULL, 1);
extents->x_bearing = round (bounds.origin.x * x_mult);
extents->y_bearing = round (bounds.origin.y * y_mult);
extents->width = round (bounds.size.width * x_mult);
extents->height = round (bounds.size.height * y_mult);
return true;
}
static hb_bool_t
hb_coretext_get_font_h_extents (hb_font_t *font,
void *font_data,
hb_font_extents_t *metrics,
void *user_data HB_UNUSED)
{
CTFontRef ct_font = (CTFontRef) font_data;
CGFloat ct_font_size = CTFontGetSize (ct_font);
CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size;
metrics->ascender = round (CTFontGetAscent (ct_font) * y_mult);
metrics->descender = -round (CTFontGetDescent (ct_font) * y_mult);
metrics->line_gap = round (CTFontGetLeading (ct_font) * y_mult);
return true;
}
#ifndef HB_NO_DRAW
static void
ct_apply_func (void *info, const CGPathElement *element)
{
hb_draw_session_t *draws = (hb_draw_session_t *) info;
switch (element->type)
{
case kCGPathElementMoveToPoint:
draws->move_to (element->points[0].x, element->points[0].y);
break;
case kCGPathElementAddLineToPoint:
draws->line_to (element->points[0].x, element->points[0].y);
break;
case kCGPathElementAddQuadCurveToPoint:
draws->quadratic_to (element->points[0].x, element->points[0].y,
element->points[1].x, element->points[1].y);
break;
case kCGPathElementAddCurveToPoint:
draws->cubic_to (element->points[0].x, element->points[0].y,
element->points[1].x, element->points[1].y,
element->points[2].x, element->points[2].y);
break;
case kCGPathElementCloseSubpath:
draws->close_path ();
break;
}
}
static void
hb_coretext_draw_glyph (hb_font_t *font,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
hb_draw_funcs_t *draw_funcs, void *draw_data,
void *user_data)
{
CTFontRef ct_font = (CTFontRef) font_data;
CGFloat ct_font_size = CTFontGetSize (ct_font);
CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size;
CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformScale (transform, x_mult, y_mult);
CGPathRef path = CTFontCreatePathForGlyph (ct_font, glyph, &transform);
if (!path)
return;
hb_draw_session_t drawing = {draw_funcs, draw_data, font->slant};
CGPathApply (path, &drawing, ct_apply_func);
CFRelease (path);
}
#endif
static hb_bool_t
hb_coretext_get_glyph_name (hb_font_t *font,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
char *name, unsigned int size,
void *user_data HB_UNUSED)
{
CGFontRef cg_font = (CGFontRef) (const void *) font->face->data.coretext;
CGGlyph cg_glyph = glyph;
CFStringRef cf_name = CGFontCopyGlyphNameForGlyph (cg_font, cg_glyph);
if (!cf_name)
return false;
CFIndex len = CFStringGetLength (cf_name);
if (len > size - 1)
len = size - 1;
CFStringGetBytes (cf_name, CFRangeMake (0, len),
kCFStringEncodingUTF8, 0, false,
(UInt8 *) name, size, &len);
name[len] = '\0';
return true;
}
static hb_bool_t
hb_coretext_get_glyph_from_name (hb_font_t *font HB_UNUSED,
void *font_data,
const char *name, int len,
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
CTFontRef ct_font = (CTFontRef) font_data;
if (len == -1)
len = strlen (name);
CFStringRef cf_name = CFStringCreateWithBytes (kCFAllocatorDefault,
(const UInt8 *) name, len,
kCFStringEncodingUTF8, false);
CGGlyph cg_glyph = CTFontGetGlyphWithName (ct_font, cf_name);
*glyph = cg_glyph;
CFRelease (cf_name);
// TODO Return true for .notdef; hb-ft does that.
return cg_glyph != 0;
}
static inline void free_static_coretext_funcs ();
static struct hb_coretext_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_coretext_font_funcs_lazy_loader_t>
{
static hb_font_funcs_t *create ()
{
hb_font_funcs_t *funcs = hb_font_funcs_create ();
hb_font_funcs_set_nominal_glyph_func (funcs, hb_coretext_get_nominal_glyph, nullptr, nullptr);
hb_font_funcs_set_nominal_glyphs_func (funcs, hb_coretext_get_nominal_glyphs, nullptr, nullptr);
hb_font_funcs_set_variation_glyph_func (funcs, hb_coretext_get_variation_glyph, nullptr, nullptr);
hb_font_funcs_set_font_h_extents_func (funcs, hb_coretext_get_font_h_extents, nullptr, nullptr);
hb_font_funcs_set_glyph_h_advances_func (funcs, hb_coretext_get_glyph_h_advances, nullptr, nullptr);
//hb_font_funcs_set_glyph_h_origin_func (funcs, hb_coretext_get_glyph_h_origin, nullptr, nullptr);
#ifndef HB_NO_VERTICAL
//hb_font_funcs_set_font_v_extents_func (funcs, hb_coretext_get_font_v_extents, nullptr, nullptr);
hb_font_funcs_set_glyph_v_advances_func (funcs, hb_coretext_get_glyph_v_advances, nullptr, nullptr);
hb_font_funcs_set_glyph_v_origin_func (funcs, hb_coretext_get_glyph_v_origin, nullptr, nullptr);
#endif
#ifndef HB_NO_DRAW
hb_font_funcs_set_draw_glyph_func (funcs, hb_coretext_draw_glyph, nullptr, nullptr);
#endif
hb_font_funcs_set_glyph_extents_func (funcs, hb_coretext_get_glyph_extents, nullptr, nullptr);
#ifndef HB_NO_OT_FONT_GLYPH_NAMES
hb_font_funcs_set_glyph_name_func (funcs, hb_coretext_get_glyph_name, nullptr, nullptr);
hb_font_funcs_set_glyph_from_name_func (funcs, hb_coretext_get_glyph_from_name, nullptr, nullptr);
#endif
hb_font_funcs_make_immutable (funcs);
hb_atexit (free_static_coretext_funcs);
return funcs;
}
} static_coretext_funcs;
static inline
void free_static_coretext_funcs ()
{
static_coretext_funcs.free_instance ();
}
static hb_font_funcs_t *
_hb_coretext_get_font_funcs ()
{
return static_coretext_funcs.get_unconst ();
}
/**
* hb_coretext_font_set_funcs:
* @font: #hb_font_t to work upon
*
* Configures the font-functions structure of the specified
* #hb_font_t font object to use CoreText font functions.
*
* In particular, you can use this function to configure an
* existing #hb_face_t face object for use with CoreText font
* functions even if that #hb_face_t face object was initially
* created with hb_face_create(), and therefore was not
* initially configured to use CoreText font functions.
*
* An #hb_font_t object created with hb_coretext_font_create()
* is preconfigured for CoreText font functions and does not
* require this function to be used.
*
* <note>Note: Internally, this function creates a CTFont.
* </note>
*
* XSince: REPLACEME
**/
void
hb_coretext_font_set_funcs (hb_font_t *font)
{
CTFontRef ct_font = hb_coretext_font_get_ct_font (font);
if (unlikely (!ct_font))
return;
hb_font_set_funcs (font,
_hb_coretext_get_font_funcs (),
(void *) CFRetain (ct_font),
_hb_coretext_font_destroy);
}
#undef MAX_GLYPHS
#endif

@ -335,7 +335,7 @@ _hb_coretext_shaper_face_data_destroy (hb_coretext_face_data_t *data)
* Creates an #hb_face_t face object from the specified
* CGFontRef.
*
* Return value: the new #hb_face_t face object
* Return value: (transfer full): The new face object
*
* Since: 0.9.10
*/
@ -347,6 +347,65 @@ hb_coretext_face_create (CGFontRef cg_font)
return face;
}
/**
* hb_coretext_face_create_from_file_or_fail:
* @file_name: A font filename
* @index: The index of the face within the file
*
* Creates an #hb_face_t face object from the specified
* font file and face index.
*
* This is similar in functionality to hb_face_create_for_from_file_or_fail(),
* but uses the CoreText library for loading the font file.
*
* Return value: (transfer full): The new face object, or `NULL` if
* no face is found at the specified index or the file cannot be read.
*
* XSince: REPLACEME
*/
hb_face_t *
hb_coretext_face_create_from_file_or_fail (const char *file_name,
unsigned int index)
{
auto url = CFURLCreateFromFileSystemRepresentation (nullptr,
(const UInt8 *) file_name,
strlen (file_name),
false);
if (unlikely (!url))
return nullptr;
auto ct_font_desc_array = CTFontManagerCreateFontDescriptorsFromURL (url);
if (unlikely (!ct_font_desc_array))
{
CFRelease (url);
return nullptr;
}
auto ct_font_desc = (CFArrayGetCount (ct_font_desc_array) > index) ?
(CTFontDescriptorRef) CFArrayGetValueAtIndex (ct_font_desc_array, index) : nullptr;
if (unlikely (!ct_font_desc))
{
CFRelease (ct_font_desc_array);
CFRelease (url);
return nullptr;
}
CFRelease (url);
auto ct_font = ct_font_desc ? CTFontCreateWithFontDescriptor (ct_font_desc, 0, nullptr) : nullptr;
CFRelease (ct_font_desc_array);
if (unlikely (!ct_font))
return nullptr;
auto cg_font = ct_font ? CTFontCopyGraphicsFont (ct_font, nullptr) : nullptr;
CFRelease (ct_font);
if (unlikely (!cg_font))
return nullptr;
hb_face_t *face = hb_coretext_face_create (cg_font);
if (unlikely (hb_face_is_immutable (face)))
return nullptr;
return face;
}
/**
* hb_coretext_face_get_cg_font:
* @face: The #hb_face_t to work upon
@ -439,7 +498,12 @@ _hb_coretext_shaper_font_data_destroy (hb_coretext_font_data_t *data)
* Creates an #hb_font_t font object from the specified
* CTFontRef.
*
* Return value: the new #hb_font_t font object
* The created font uses the default font functions implemented
* navitely by HarfBuzz. If you want to use the CoreText font functions
* instead (rarely needed), you can do so by calling
* by hb_coretext_font_set_funcs().
*
* Return value: (transfer full): The new font object
*
* Since: 1.7.2
**/
@ -460,6 +524,9 @@ hb_coretext_font_create (CTFontRef ct_font)
/* Let there be dragons here... */
font->data.coretext.cmpexch (nullptr, (hb_coretext_font_data_t *) CFRetain (ct_font));
// https://github.com/harfbuzz/harfbuzz/pull/4895#issuecomment-2408471254
//hb_coretext_font_set_funcs (font);
return font;
}

@ -44,9 +44,9 @@ HB_BEGIN_DECLS
* HB_CORETEXT_TAG_MORT:
*
* The #hb_tag_t tag for the `mort` (glyph metamorphosis) table,
* which holds AAT features.
* which holds AAT features.
*
* For more information, see
* For more information, see
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6mort.html
*
**/
@ -56,7 +56,7 @@ HB_BEGIN_DECLS
* HB_CORETEXT_TAG_MORX:
*
* The #hb_tag_t tag for the `morx` (extended glyph metamorphosis)
* table, which holds AAT features.
* table, which holds AAT features.
*
* For more information, see
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6morx.html
@ -68,9 +68,9 @@ HB_BEGIN_DECLS
* HB_CORETEXT_TAG_KERX:
*
* The #hb_tag_t tag for the `kerx` (extended kerning) table, which
* holds AAT kerning information.
* holds AAT kerning information.
*
* For more information, see
* For more information, see
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kerx.html
*
**/
@ -80,6 +80,10 @@ HB_BEGIN_DECLS
HB_EXTERN hb_face_t *
hb_coretext_face_create (CGFontRef cg_font);
HB_EXTERN hb_face_t *
hb_coretext_face_create_from_file_or_fail (const char *file_name,
unsigned int index);
HB_EXTERN hb_font_t *
hb_coretext_font_create (CTFontRef ct_font);
@ -90,6 +94,9 @@ hb_coretext_face_get_cg_font (hb_face_t *face);
HB_EXTERN CTFontRef
hb_coretext_font_get_ct_font (hb_font_t *font);
HB_EXTERN void
hb_coretext_font_set_funcs (hb_font_t *font);
HB_END_DECLS

@ -263,6 +263,61 @@ hb_face_create (hb_blob_t *blob,
return face;
}
/**
* hb_face_create_or_fail:
* @blob: #hb_blob_t to work upon
* @index: The index of the face within @blob
*
* Like hb_face_create(), but returns `NULL` if the blob data
* contains no usable font face at the specified index.
*
* Return value: (transfer full): The new face object, or `NULL` if
* no face is found at the specified index.
*
* XSince: REPLACEME
**/
hb_face_t *
hb_face_create_or_fail (hb_blob_t *blob,
unsigned int index)
{
unsigned num_faces = hb_face_count (blob);
if (index >= num_faces)
return nullptr;
hb_face_t *face = hb_face_create (blob, index);
if (hb_object_is_immutable (face))
return nullptr;
return face;
}
/**
* hb_face_create_from_file_or_fail:
* @file_name: A font filename
* @index: The index of the face within the file
*
* A thin wrapper around hb_blob_create_from_file_or_fail()
* followed by hb_face_create_or_fail().
*
* Return value: (transfer full): The new face object, or `NULL` if
* no face is found at the specified index or the file cannot be read.
*
* XSince: REPLACEME
**/
HB_EXTERN hb_face_t *
hb_face_create_from_file_or_fail (const char *file_name,
unsigned int index)
{
hb_blob_t *blob = hb_blob_create_from_file_or_fail (file_name);
if (unlikely (!blob))
return nullptr;
hb_face_t *face = hb_face_create_or_fail (blob, index);
hb_blob_destroy (blob);
return face;
}
/**
* hb_face_get_empty:
*

@ -59,6 +59,14 @@ HB_EXTERN hb_face_t *
hb_face_create (hb_blob_t *blob,
unsigned int index);
HB_EXTERN hb_face_t *
hb_face_create_or_fail (hb_blob_t *blob,
unsigned int index);
HB_EXTERN hb_face_t *
hb_face_create_from_file_or_fail (const char *file_name,
unsigned int index);
/**
* hb_reference_table_func_t:
* @face: an #hb_face_t to reference table for

@ -41,6 +41,7 @@
#include "hb-ot-shaper-arabic-pua.hh"
#include "hb-paint.hh"
#include FT_MODULE_H
#include FT_ADVANCES_H
#include FT_MULTIPLE_MASTERS_H
#include FT_OUTLINE_H
@ -1432,6 +1433,24 @@ hb_ft_font_create_referenced (FT_Face ft_face)
return hb_ft_font_create (ft_face, _hb_ft_face_destroy);
}
static void * _hb_ft_alloc (FT_Memory memory, long size)
{ return hb_malloc (size); }
static void _hb_ft_free (FT_Memory memory, void *block)
{ hb_free (block); }
static void * _hb_ft_realloc (FT_Memory memory, long cur_size, long new_size, void *block)
{ return hb_realloc (block, new_size); }
static FT_MemoryRec_ m =
{
nullptr,
_hb_ft_alloc,
_hb_ft_free,
_hb_ft_realloc
};
static inline void free_static_ft_library ();
static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<FT_Library>,
@ -1440,16 +1459,19 @@ static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<F
static FT_Library create ()
{
FT_Library l;
if (FT_Init_FreeType (&l))
if (FT_New_Library (&m, &l))
return nullptr;
FT_Add_Default_Modules (l);
FT_Set_Default_Properties (l);
hb_atexit (free_static_ft_library);
return l;
}
static void destroy (FT_Library l)
{
FT_Done_FreeType (l);
FT_Done_Library (l);
}
static FT_Library get_null ()
{
@ -1464,9 +1486,76 @@ void free_static_ft_library ()
}
static FT_Library
get_ft_library ()
reference_ft_library ()
{
FT_Library l = static_ft_library.get_unconst ();
if (unlikely (FT_Reference_Library (l)))
{
DEBUG_MSG (FT, l, "FT_Reference_Library() failed");
return nullptr;
}
return l;
}
static hb_user_data_key_t ft_library_key = {0};
static void
finalize_ft_library (void *arg)
{
FT_Face ft_face = (FT_Face) arg;
FT_Done_Library ((FT_Library) ft_face->generic.data);
}
static void
destroy_ft_library (void *arg)
{
FT_Done_Library ((FT_Library) arg);
}
/**
* hb_ft_face_create_from_file_or_fail:
* @file_name: A font filename
* @index: The index of the face within the file
*
* Creates an #hb_face_t face object from the specified
* font file and face index.
*
* This is similar in functionality to hb_face_create_for_from_file_or_fail(),
* but uses the FreeType library for loading the font file.
*
* Return value: (transfer full): The new face object, or `NULL` if
* no face is found at the specified index or the file cannot be read.
*
* XSince: REPLACEME
*/
hb_face_t *
hb_ft_face_create_from_file_or_fail (const char *file_name,
unsigned int index)
{
return static_ft_library.get_unconst ();
FT_Library ft_library = reference_ft_library ();
if (unlikely (!ft_library))
{
DEBUG_MSG (FT, ft_library, "reference_ft_library failed");
return nullptr;
}
FT_Face ft_face;
if (unlikely (FT_New_Face (ft_library,
file_name,
index,
&ft_face)))
return nullptr;
hb_face_t *face = hb_ft_face_create_referenced (ft_face);
FT_Done_Face (ft_face);
ft_face->generic.data = ft_library;
ft_face->generic.finalizer = finalize_ft_library;
if (hb_face_is_immutable (face))
return nullptr;
return face;
}
static void
@ -1511,26 +1600,36 @@ hb_ft_font_set_funcs (hb_font_t *font)
if (unlikely (!blob_length))
DEBUG_MSG (FT, font, "Font face has empty blob");
FT_Face ft_face = nullptr;
FT_Error err = FT_New_Memory_Face (get_ft_library (),
(const FT_Byte *) blob_data,
blob_length,
hb_face_get_index (font->face),
&ft_face);
FT_Library ft_library = reference_ft_library ();
if (unlikely (!ft_library))
{
hb_blob_destroy (blob);
DEBUG_MSG (FT, font, "reference_ft_library failed");
return;
}
if (unlikely (err)) {
FT_Face ft_face = nullptr;
if (unlikely (FT_New_Memory_Face (ft_library,
(const FT_Byte *) blob_data,
blob_length,
hb_face_get_index (font->face),
&ft_face)))
{
hb_blob_destroy (blob);
DEBUG_MSG (FT, font, "Font face FT_New_Memory_Face() failed");
DEBUG_MSG (FT, font, "FT_New_Memory_Face() failed");
return;
}
if (FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL))
FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE);
// Hook the blob to the FT_Face
ft_face->generic.data = blob;
ft_face->generic.finalizer = _release_blob;
// And the FT_Library to the blob
hb_blob_set_user_data (blob, &ft_library_key, ft_library, destroy_ft_library, true);
_hb_ft_font_set_funcs (font, ft_face, true);
hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);

@ -84,6 +84,9 @@ hb_ft_face_create_cached (FT_Face ft_face);
HB_EXTERN hb_face_t *
hb_ft_face_create_referenced (FT_Face ft_face);
HB_EXTERN hb_face_t *
hb_ft_face_create_from_file_or_fail (const char *file_name,
unsigned int index);
/*
* hb-font from ft-face.

@ -30,7 +30,7 @@
#include "hb.hh"
/* Variations of this code exist in hb-coretext.cc as well
/* Variations of this code exist in hb-coretext-shape.cc as well
* as hb-aat-map.cc... */
typedef struct hb_ms_feature_t {

@ -642,7 +642,9 @@ _hb_ot_get_font_funcs ()
* hb_ot_font_set_funcs:
* @font: #hb_font_t to work upon
*
* Sets the font functions to use when working with @font.
* Sets the font functions to use when working with @font to
* the HarfBuzz's native implementation. This is the default
* for fonts newly created.
*
* Since: 0.9.28
**/

@ -346,7 +346,7 @@ hb_wasm_headers = files()
# System-dependent sources and headers
hb_coretext_sources = files('hb-coretext.cc')
hb_coretext_sources = files('hb-coretext-shape.cc', 'hb-coretext-font.cc')
hb_coretext_headers = files('hb-coretext.h')
hb_directwrite_sources = files('hb-directwrite.cc')

@ -1,6 +1,3 @@
../fonts/DFONT.dfont;--face-index=0 --font-funcs=ot;U+2026,U+0020,U+002E;[ellipsis=0+723|space=1+250|period=2+241]
../fonts/DFONT.dfont;--face-index=1 --font-funcs=ot;U+2026,U+0020,U+002E;[gid0=0+500|gid0=1+500|gid0=2+500]
../fonts/DFONT.dfont;--face-index=2 --font-funcs=ot;U+2026,U+0020,U+002E;[gid0=0+500|gid0=1+500|gid0=2+500]
../fonts/TTC.ttc;--face-index=0 --font-funcs=ot;U+2026,U+0020,U+002E;[ellipsis=0+723|space=1+250|period=2+241]
../fonts/TTC.ttc;--face-index=1 --font-funcs=ot;U+2026,U+0020,U+002E;[ellipsis=0+723|space=1+250|period=2+241]
../fonts/TTC.ttc;--face-index=2 --font-funcs=ot;U+2026,U+0020,U+002E;[gid0=0+500|gid0=1+500|gid0=2+500]

@ -29,10 +29,18 @@
#include "options.hh"
#ifdef HAVE_FREETYPE
#include <hb-ft.h>
#endif
#ifdef HAVE_CORETEXT
#include <hb-coretext.h>
#endif
struct face_options_t
{
~face_options_t ()
{
g_free (face_loader);
g_free (font_file);
}
@ -48,26 +56,38 @@ struct face_options_t
~cache_t ()
{
g_free (font_path);
hb_blob_destroy (blob);
hb_face_destroy (face);
}
char *font_path = nullptr;
hb_blob_t *blob = nullptr;
unsigned face_index = (unsigned) -1;
hb_face_t *face = nullptr;
} cache;
char *font_file = nullptr;
unsigned face_index = 0;
char *face_loader = nullptr;
hb_blob_t *blob = nullptr;
hb_face_t *face = nullptr;
};
face_options_t::cache_t face_options_t::cache {};
static struct supported_face_loaders_t {
char name[9];
hb_face_t * (*func) (const char *font_file, unsigned face_index);
} supported_face_loaders[] =
{
{"ot", hb_face_create_from_file_or_fail},
#ifdef HAVE_FREETYPE
{"ft", hb_ft_face_create_from_file_or_fail},
#endif
#ifdef HAVE_CORETEXT
{"coretext", hb_coretext_face_create_from_file_or_fail},
#endif
};
void
face_options_t::post_parse (GError **error)
{
@ -92,44 +112,87 @@ face_options_t::post_parse (GError **error)
#endif
}
if (!cache.font_path || 0 != strcmp (cache.font_path, font_path))
hb_face_t * (*face_load) (const char *file_name, unsigned face_index) = nullptr;
if (!face_loader)
{
hb_blob_destroy (cache.blob);
cache.blob = hb_blob_create_from_file_or_fail (font_path);
free ((char *) cache.font_path);
cache.font_path = g_strdup (font_path);
if (!cache.blob)
face_load = supported_face_loaders[0].func;
}
else
{
for (unsigned int i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++)
if (0 == g_ascii_strcasecmp (face_loader, supported_face_loaders[i].name))
{
face_load = supported_face_loaders[i].func;
break;
}
if (!face_load)
{
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
"%s: Failed reading file", font_path);
GString *s = g_string_new (nullptr);
for (unsigned int i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++)
{
if (i)
g_string_append_c (s, '/');
g_string_append (s, supported_face_loaders[i].name);
}
g_string_append_c (s, '\n');
char *p = g_string_free (s, FALSE);
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
"Unknown face loader `%s'; supported values are: %s; default is %s",
face_loader,
p,
supported_face_loaders[0].name);
free (p);
return;
}
hb_face_destroy (cache.face);
cache.face = nullptr;
cache.face_index = (unsigned) -1;
}
if (cache.face_index != face_index)
if (!cache.font_path ||
0 != strcmp (cache.font_path, font_path) ||
cache.face_index != face_index)
{
hb_face_destroy (cache.face);
cache.face = hb_face_create (cache.blob, face_index);
cache.face = face_load (font_path, face_index);
cache.face_index = face_index;
free ((char *) cache.font_path);
cache.font_path = g_strdup (font_path);
if (!cache.face)
{
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
"%s: Failed loading font face", font_path);
return;
}
}
blob = cache.blob;
face = cache.face;
}
void
face_options_t::add_options (option_parser_t *parser)
{
char *face_loaders_text = nullptr;
{
static_assert ((ARRAY_LENGTH_CONST (supported_face_loaders) > 0),
"No supported face-loaders found.");
GString *s = g_string_new (nullptr);
g_string_printf (s, "Set face loader to use (default: %s)\n\n Supported face loaders are: %s",
supported_face_loaders[0].name,
supported_face_loaders[0].name);
for (unsigned int i = 1; i < ARRAY_LENGTH (supported_face_loaders); i++)
{
g_string_append_c (s, '/');
g_string_append (s, supported_face_loaders[i].name);
}
face_loaders_text = g_string_free (s, FALSE);
parser->free_later (face_loaders_text);
}
GOptionEntry entries[] =
{
{"font-file", 0, 0, G_OPTION_ARG_STRING, &this->font_file, "Set font file-name", "filename"},
{"face-index", 'y', 0, G_OPTION_ARG_INT, &this->face_index, "Set face index (default: 0)", "index"},
{"face-loader", 0, 0, G_OPTION_ARG_STRING, &this->face_loader, face_loaders_text, "loader"},
{nullptr}
};
parser->add_group (entries,

@ -29,10 +29,13 @@
#include "face-options.hh"
#include <hb-ot.h>
#ifdef HAVE_FREETYPE
#include <hb-ft.h>
#endif
#include <hb-ot.h>
#ifdef HAVE_CORETEXT
#include <hb-coretext.h>
#endif
#define FONT_SIZE_UPEM 0x7FFFFFFF
#define FONT_SIZE_NONE 0
@ -79,7 +82,7 @@ struct font_options_t : face_options_t
static struct supported_font_funcs_t {
char name[4];
char name[9];
void (*func) (hb_font_t *);
} supported_font_funcs[] =
{
@ -87,6 +90,9 @@ static struct supported_font_funcs_t {
#ifdef HAVE_FREETYPE
{"ft", hb_ft_font_set_funcs},
#endif
#ifdef HAVE_CORETEXT
{"coretext", hb_coretext_font_set_funcs},
#endif
};
@ -296,8 +302,7 @@ font_options_t::add_options (option_parser_t *parser)
{
face_options_t::add_options (parser);
char *text = nullptr;
char *font_funcs_text = nullptr;
{
static_assert ((ARRAY_LENGTH_CONST (supported_font_funcs) > 0),
"No supported font-funcs found.");
@ -310,8 +315,8 @@ font_options_t::add_options (option_parser_t *parser)
g_string_append_c (s, '/');
g_string_append (s, supported_font_funcs[i].name);
}
text = g_string_free (s, FALSE);
parser->free_later (text);
font_funcs_text = g_string_free (s, FALSE);
parser->free_later (font_funcs_text);
}
char *font_size_text;
@ -338,7 +343,7 @@ font_options_t::add_options (option_parser_t *parser)
G_OPTION_ARG_CALLBACK, (gpointer) &parse_font_grade, "Set synthetic grade (default: 0)", "1/2 numbers; eg. 0.05"},
{"font-slant", 0, font_size_flags,
G_OPTION_ARG_DOUBLE, &this->slant, "Set synthetic slant (default: 0)", "slant ratio; eg. 0.2"},
{"font-funcs", 0, 0, G_OPTION_ARG_STRING, &this->font_funcs, text, "impl"},
{"font-funcs", 0, 0, G_OPTION_ARG_STRING, &this->font_funcs, font_funcs_text, "impl"},
{"sub-font", 0, G_OPTION_FLAG_HIDDEN,
G_OPTION_ARG_NONE, &this->sub_font, "Create a sub-font (default: false)", "boolean"},
{"ft-load-flags", 0, 0, G_OPTION_ARG_INT, &this->ft_load_flags, "Set FreeType load-flags (default: 2)", "integer"},

@ -349,7 +349,9 @@ struct info_t :
void
_show_face_count ()
{
hb_blob_t *blob = hb_blob_create_from_file (font_file);
printf ("Face count: %u\n", hb_face_count (blob));
hb_blob_destroy (blob);
}
void

@ -43,13 +43,6 @@ void free_ft_library ()
}
#endif
static void
_release_blob (void *arg)
{
FT_Face ft_face = (FT_Face) arg;
hb_blob_destroy ((hb_blob_t *) ft_face->generic.data);
}
static inline cairo_font_face_t *
helper_cairo_create_ft_font_face (const font_options_t *font_opts)
{
@ -68,15 +61,11 @@ helper_cairo_create_ft_font_face (const font_options_t *font_opts)
#endif
}
unsigned int blob_length;
const char *blob_data = hb_blob_get_data (font_opts->blob, &blob_length);
if (FT_New_Memory_Face (ft_library,
(const FT_Byte *) blob_data,
blob_length,
font_opts->face_index,
&ft_face))
fail (false, "FT_New_Memory_Face fail");
if (FT_New_Face (ft_library,
font_opts->font_file,
font_opts->face_index,
&ft_face))
fail (false, "FT_New_Face fail");
}
if (!ft_face)
{
@ -87,9 +76,6 @@ helper_cairo_create_ft_font_face (const font_options_t *font_opts)
}
else
{
ft_face->generic.data = hb_blob_reference (font_opts->blob);
ft_face->generic.finalizer = _release_blob;
#if !defined(HB_NO_VAR) && defined(HAVE_FT_SET_VAR_BLEND_COORDINATES)
unsigned int num_coords;
const float *coords = hb_font_get_var_coords_design (font_opts->font, &num_coords);

@ -7,11 +7,8 @@
static
hb_face_t* open_font(const char* path)
{
hb_blob_t *blob = hb_blob_create_from_file_or_fail (path);
g_assert(blob);
hb_face_t* face = hb_face_create(blob, 0);
hb_blob_destroy(blob);
hb_face_t *face = hb_face_create_from_file_or_fail (path, 0);
g_assert (face);
return face;
}
@ -99,6 +96,7 @@ test_parse_instancing_spec (void)
g_assert(check_parsing(roboto, "wght=200:", wght, 200, 400, 900));
hb_face_destroy(face);
hb_face_destroy(roboto);
}

Loading…
Cancel
Save