Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 9 additions & 28 deletions src/CanvasRenderingContext2d.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2457,35 +2457,16 @@ Context2d::paintText(const Napi::CallbackInfo& info, bool stroke) {
double fontSize = state->fontProperties.size;
double toPx = fontSize / 1000;

FT_Face ftface;
FT_Error newFaceResult = FT_New_Memory_Face(
data->ft,
reinterpret_cast<const FT_Byte *>(run.face->data.get()),
run.face->data_len,
run.face->index,
&ftface
);

if (newFaceResult != 0) continue;

cairo_font_face_t* crface = cairo_ft_font_face_create_for_ft_face(ftface, 0);

static const cairo_user_data_key_t key{0};
cairo_status_t setDataResult = cairo_font_face_set_user_data(
crface,
&key,
ftface,
(cairo_destroy_func_t) FT_Done_Face
);

if (setDataResult) {
cairo_font_face_destroy(crface);
FT_Done_Face (ftface);
continue;
}

cairo_font_face_t* crface = cairo_ft_font_face_create_for_ft_face(run.face->ftface.get(), 0);
cairo_set_font_face(context(), crface);
cairo_set_font_size(context(), fontSize);

// Be shy about cairo_set_font_size. This always recreates a scaled font,
// which destroys lots of caching. Scaled fonts are associated with the
// font's matrix, which is both for scaling from em to Cairo space and for
// fake italics. Just checking xx should therefore be reliable.
cairo_matrix_t m;
cairo_get_font_matrix(context(), &m);
if (m.xx != fontSize) cairo_set_font_size(context(), fontSize);

size_t hbGlyphIndex = 0;
while (hbGlyphIndex < run.glyphs.size()) {
Expand Down
34 changes: 32 additions & 2 deletions src/Font.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

#include <hb.h>
#include <hb-ot.h>
#include <freetype/freetype.h>
#include <type_traits>

enum class FontStyle {
Normal,
Expand Down Expand Up @@ -42,6 +44,14 @@ struct HbFontDeleter {
}
};

struct FT_FaceDeleter {
void operator()(FT_Face face) {
FT_Done_Face(face);
}
};

using FT_Face_Type = std::remove_pointer<FT_Face>::type;

// Descriptors describe real fonts on the OS
struct FontDescriptor : FontBase {
std::unique_ptr<char[]> family;
Expand All @@ -53,6 +63,7 @@ struct FontDescriptor : FontBase {
std::unique_ptr<file_char[]> url = nullptr;
std::unique_ptr<uint8_t[]> data = nullptr;
std::unique_ptr<hb_font_t, HbFontDeleter> hbfont = nullptr;
std::unique_ptr<FT_Face_Type, FT_FaceDeleter> ftface = nullptr;
size_t data_len = 0;
size_t index = 0;
FontStatus status = FontStatus::Unloaded;
Expand Down Expand Up @@ -95,6 +106,22 @@ struct FontDescriptor : FontBase {
hb_font_set_scale(hbfont.get(), 1000, 1000);
}

void loadFtFont(FT_Library ft) {
FT_Face ftface;
FT_Error newFaceResult = FT_New_Memory_Face(
ft,
reinterpret_cast<const FT_Byte *>(data.get()),
data_len,
index,
&ftface
);
if (newFaceResult) {
status = FontStatus::Error;
} else {
this->ftface = std::unique_ptr<FT_Face_Type, FT_FaceDeleter>(ftface);
}
}

void loadData() {
FILE* file = nullptr;
long file_size = 0;
Expand Down Expand Up @@ -134,9 +161,12 @@ struct FontDescriptor : FontBase {
if (file) fclose(file);
}

void load() {
void load(FT_Library ft) {
if (status == FontStatus::Unloaded) loadData();
if (status == FontStatus::Loaded && hbfont == nullptr) loadHbFont();
if (status == FontStatus::Loaded && hbfont == nullptr) {
loadHbFont();
loadFtFont(ft);
}
}
};

Expand Down
2 changes: 1 addition & 1 deletion src/FontLayout.cc
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ layoutText(

while (shapingWorkList.size() && matchIndex < matches.size()) {
auto face = matches[matchIndex];
face->load();
face->load(data->ft());
if (!face->hbfont) {
matchIndex++;
continue;
Expand Down
24 changes: 15 additions & 9 deletions src/InstanceData.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@ using PlatformFontManager = FontManagerMacos;
using PlatformFontManager = FontManagerLinux;
#endif

struct FT_Wrapper {
FT_Library ft;
FT_Wrapper() {
FT_Init_FreeType(&ft);
}
~FT_Wrapper() {
FT_Done_FreeType(ft);
}
};

struct InstanceData {
Napi::FunctionReference CanvasCtor;
Napi::FunctionReference CanvasGradientCtor;
Expand All @@ -27,14 +37,10 @@ struct InstanceData {
Napi::FunctionReference FontFaceCtor;
Napi::ObjectReference jsFontSet;
FontFaceSet* cppFontSet;
FT_Library ft;
// FT_Wrapper exists because, and it is located here so that, FT_Done_FreeType
// is called after ~PlatformFontManager. FT_Faces are all freed in
// FT_Done_FreeType. That can't happen before their backing buffers are freed.
FT_Wrapper _ft;
inline FT_Library ft() { return _ft.ft; }
PlatformFontManager fontManager;

InstanceData() {
FT_Init_FreeType(&ft);
}

~InstanceData() {
FT_Done_FreeType(ft);
}
};
Loading