#include "hb.hh"
#ifdef HAVE_DIRECTWRITE
#include "hb-directwrite.hh"
#include "hb-font.hh"
static inline void free_static_directwrite_global ();
static struct hb_directwrite_global_lazy_loader_t : hb_lazy_loader_t<hb_directwrite_global_t,
hb_directwrite_global_lazy_loader_t>
{
static hb_directwrite_global_t * create ()
{
hb_directwrite_global_t *global = new hb_directwrite_global_t;
if (unlikely (!global))
return nullptr;
if (unlikely (!global->success))
{
delete global;
return nullptr;
}
hb_atexit (free_static_directwrite_global);
return global;
}
static void destroy (hb_directwrite_global_t *l)
{
delete l;
}
static hb_directwrite_global_t * get_null ()
{
return nullptr;
}
} static_directwrite_global;
static inline
void free_static_directwrite_global ()
{
static_directwrite_global.free_instance ();
}
hb_directwrite_global_t *
get_directwrite_global ()
{
return static_directwrite_global.get_unconst ();
}
DWriteFontFileStream::DWriteFontFileStream (hb_blob_t *blob)
{
auto *global = get_directwrite_global ();
mLoader = global->fontFileLoader;
mRefCount.init ();
mLoader->AddRef ();
hb_blob_make_immutable (blob);
mBlob = hb_blob_reference (blob);
mData = (uint8_t *) hb_blob_get_data (blob, &mSize);
fontFileKey = mLoader->RegisterFontFileStream (this);
}
DWriteFontFileStream::~DWriteFontFileStream()
{
mLoader->UnregisterFontFileStream (fontFileKey);
mLoader->Release ();
hb_blob_destroy (mBlob);
}
IDWriteFontFace *
dw_face_create (hb_blob_t *blob, unsigned index)
{
#define FAIL(...) \
HB_STMT_START { \
DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \
return nullptr; \
} HB_STMT_END
auto *global = get_directwrite_global ();
if (unlikely (!global))
FAIL ("Couldn't load DirectWrite!");
DWriteFontFileStream *fontFileStream = new DWriteFontFileStream (blob);
IDWriteFontFile *fontFile;
auto hr = global->dwriteFactory->CreateCustomFontFileReference (&fontFileStream->fontFileKey, sizeof (fontFileStream->fontFileKey),
global->fontFileLoader, &fontFile);
fontFileStream->Release ();
if (FAILED (hr))
FAIL ("Failed to load font file from data!");
BOOL isSupported;
DWRITE_FONT_FILE_TYPE fileType;
DWRITE_FONT_FACE_TYPE faceType;
uint32_t numberOfFaces;
hr = fontFile->Analyze (&isSupported, &fileType, &faceType, &numberOfFaces);
if (FAILED (hr) || !isSupported)
{
fontFile->Release ();
FAIL ("Font file is not supported.");
}
#undef FAIL
IDWriteFontFace *fontFace = nullptr;
global->dwriteFactory->CreateFontFace (faceType, 1, &fontFile, index,
DWRITE_FONT_SIMULATIONS_NONE, &fontFace);
fontFile->Release ();
return fontFace;
}
struct _hb_directwrite_font_table_context {
IDWriteFontFace *face;
void *table_context;
};
static void
_hb_directwrite_table_data_release (void *data)
{
_hb_directwrite_font_table_context *context = (_hb_directwrite_font_table_context *) data;
context->face->ReleaseFontTable (context->table_context);
hb_free (context);
}
static hb_blob_t *
_hb_directwrite_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
{
IDWriteFontFace *dw_face = ((IDWriteFontFace *) user_data);
const void *data;
uint32_t length;
void *table_context;
BOOL exists;
if (FAILED (dw_face->TryGetFontTable (hb_uint32_swap (tag), &data,
&length, &table_context, &exists)))
return nullptr;
if (!data || !exists || !length)
{
dw_face->ReleaseFontTable (table_context);
return nullptr;
}
_hb_directwrite_font_table_context *context = (_hb_directwrite_font_table_context *) hb_malloc (sizeof (_hb_directwrite_font_table_context));
if (unlikely (!context))
{
dw_face->ReleaseFontTable (table_context);
return nullptr;
}
context->face = dw_face;
context->table_context = table_context;
return hb_blob_create ((const char *) data, length, HB_MEMORY_MODE_READONLY,
context, _hb_directwrite_table_data_release);
}
static void
_hb_directwrite_face_release (void *data)
{
((IDWriteFontFace *) data)->Release ();
}
hb_face_t *
hb_directwrite_face_create (IDWriteFontFace *dw_face)
{
if (!dw_face)
return hb_face_get_empty ();
dw_face->AddRef ();
hb_face_t *face = hb_face_create_for_tables (_hb_directwrite_reference_table,
dw_face,
_hb_directwrite_face_release);
hb_face_set_index (face, dw_face->GetIndex ());
hb_face_set_glyph_count (face, dw_face->GetGlyphCount ());
return face;
}
hb_face_t *
hb_directwrite_face_create_from_file_or_fail (const char *file_name,
unsigned int index)
{
auto *blob = hb_blob_create_from_file_or_fail (file_name);
if (unlikely (!blob))
return nullptr;
return hb_directwrite_face_create_from_blob_or_fail (blob, index);
}
HB_EXTERN hb_face_t *
hb_directwrite_face_create_from_blob_or_fail (hb_blob_t *blob,
unsigned int index)
{
IDWriteFontFace *dw_face = dw_face_create (blob, index);
if (unlikely (!dw_face))
return nullptr;
hb_face_t *face = hb_directwrite_face_create (dw_face);
if (unlikely (hb_object_is_immutable (face)))
{
dw_face->Release ();
return face;
}
face->data.directwrite.cmpexch (nullptr, (hb_directwrite_face_data_t *) dw_face);
return face;
}
IDWriteFontFace *
hb_directwrite_face_get_dw_font_face (hb_face_t *face)
{
return (IDWriteFontFace *) (const void *) face->data.directwrite;
}
#ifndef HB_DISABLE_DEPRECATED
IDWriteFontFace *
hb_directwrite_face_get_font_face (hb_face_t *face)
{
return hb_directwrite_face_get_dw_font_face (face);
}
#endif
hb_font_t *
hb_directwrite_font_create (IDWriteFontFace *dw_face)
{
IDWriteFontFace5 *dw_face5 = nullptr;
hb_face_t *face = hb_directwrite_face_create (dw_face);
hb_font_t *font = hb_font_create (face);
hb_face_destroy (face);
if (unlikely (hb_object_is_immutable (font)))
return font;
if (SUCCEEDED (dw_face->QueryInterface (__uuidof (IDWriteFontFace5), (void**) &dw_face5)))
{
if (dw_face5->HasVariations ())
{
hb_vector_t<DWRITE_FONT_AXIS_VALUE> values;
uint32_t count = dw_face5->GetFontAxisValueCount ();
if (likely (values.resize_exact (count)) &&
SUCCEEDED (dw_face5->GetFontAxisValues (values.arrayZ, count)))
{
hb_vector_t<hb_variation_t> vars;
if (likely (vars.resize_exact (count)))
{
for (uint32_t i = 0; i < count; ++i)
{
hb_tag_t tag = hb_uint32_swap (values[i].axisTag);
float value = values[i].value;
vars[i] = {tag, value};
}
hb_font_set_variations (font, vars.arrayZ, vars.length);
}
}
}
dw_face5->Release ();
}
dw_face->AddRef ();
font->data.directwrite.cmpexch (nullptr, (hb_directwrite_font_data_t *) dw_face);
return font;
}
IDWriteFontFace *
hb_directwrite_font_get_dw_font_face (hb_font_t *font)
{
return (IDWriteFontFace *) (const void *) font->data.directwrite;
}
IDWriteFont *
hb_directwrite_font_get_dw_font (hb_font_t *font)
{
return nullptr;
}
#endif