diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h
index 9838835349c..52e5eabf222 100644
--- a/source/blender/blenfont/BLF_api.h
+++ b/source/blender/blenfont/BLF_api.h
@@ -71,6 +71,21 @@ void BLF_unload_all(void);
char *BLF_display_name_from_file(const char *filepath) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+char *BLF_display_name_from_id(int fontid);
+
+/**
+ * Get the metrics needed for the initial sizing of text objects.
+ */
+bool BLF_get_vfont_metrics(int fontid, float *ascend_ratio, float *em_ratio, float *scale);
+
+/**
+ * Convert a character's outlines into curves.
+ */
+float BLF_character_to_curves(int fontid,
+ unsigned int unicode,
+ struct ListBase *nurbsbase,
+ const float scale);
+
/**
* Check if font supports a particular glyph.
*/
diff --git a/source/blender/blenfont/intern/blf.cc b/source/blender/blenfont/intern/blf.cc
index 1ab4bcb8b19..cc4314aff2b 100644
--- a/source/blender/blenfont/intern/blf.cc
+++ b/source/blender/blenfont/intern/blf.cc
@@ -952,6 +952,71 @@ char *BLF_display_name_from_file(const char *filepath)
return name;
}
+char *BLF_display_name_from_id(int fontid)
+{
+ FontBLF *font = blf_get(fontid);
+ if (!font) {
+ return nullptr;
+ }
+
+ return blf_display_name(font);
+}
+
+bool BLF_get_vfont_metrics(int fontid, float *ascend_ratio, float *em_ratio, float *scale)
+{
+ FontBLF *font = blf_get(fontid);
+ if (!font) {
+ return false;
+ }
+
+ if (!blf_ensure_face(font)) {
+ return false;
+ }
+
+ /* Copied without change from vfontdata_freetype.cc to ensure consistant sizing. */
+
+ /* Blender default BFont is not "complete". */
+ const bool complete_font = (font->face->ascender != 0) && (font->face->descender != 0) &&
+ (font->face->ascender != font->face->descender);
+
+ if (complete_font) {
+ /* We can get descender as well, but we simple store descender in relation to the ascender.
+ * Also note that descender is stored as a negative number. */
+ *ascend_ratio = float(font->face->ascender) / (font->face->ascender - font->face->descender);
+ }
+ else {
+ *ascend_ratio = 0.8f;
+ *em_ratio = 1.0f;
+ }
+
+ /* Adjust font size */
+ if (font->face->bbox.yMax != font->face->bbox.yMin) {
+ *scale = float(1.0 / double(font->face->bbox.yMax - font->face->bbox.yMin));
+
+ if (complete_font) {
+ *em_ratio = float(font->face->ascender - font->face->descender) /
+ (font->face->bbox.yMax - font->face->bbox.yMin);
+ }
+ }
+ else {
+ *scale = 1.0f / 1000.0f;
+ }
+
+ return true;
+}
+
+float BLF_character_to_curves(int fontid,
+ unsigned int unicode,
+ ListBase *nurbsbase,
+ const float scale)
+{
+ FontBLF *font = blf_get(fontid);
+ if (!font) {
+ return 0.0f;
+ }
+ return blf_character_to_curves(font, unicode, nurbsbase, scale);
+}
+
#ifdef DEBUG
void BLF_state_print(int fontid)
{
diff --git a/source/blender/blenfont/intern/blf_glyph.cc b/source/blender/blenfont/intern/blf_glyph.cc
index f03fd9e3f2e..4dc54409e93 100644
--- a/source/blender/blenfont/intern/blf_glyph.cc
+++ b/source/blender/blenfont/intern/blf_glyph.cc
@@ -30,6 +30,8 @@
#include "BLF_api.h"
+#include "DNA_curve_types.h"
+
#include "GPU_capabilities.h"
#include "blf_internal.h"
@@ -718,11 +720,14 @@ static FT_UInt blf_glyph_index_from_charcode(FontBLF **font, const uint charcode
/**
* Load a glyph into the glyph slot of a font's face object.
*/
-static FT_GlyphSlot blf_glyph_load(FontBLF *font, FT_UInt glyph_index)
+static FT_GlyphSlot blf_glyph_load(FontBLF *font, FT_UInt glyph_index, bool outline_only)
{
int load_flags;
- if (font->flags & BLF_MONOCHROME) {
+ if (outline_only) {
+ load_flags = FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP;
+ }
+ else if (font->flags & BLF_MONOCHROME) {
load_flags = FT_LOAD_TARGET_MONO;
}
else {
@@ -1117,7 +1122,8 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font,
FT_UInt glyph_index,
uint charcode,
uint8_t subpixel,
- int fixed_width)
+ int fixed_width,
+ bool outline_only)
{
if (glyph_font != settings_font) {
blf_font_size(glyph_font, settings_font->size);
@@ -1161,7 +1167,7 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font,
FT_Set_Var_Design_Coordinates(glyph_font->face, BLF_VARIATIONS_MAX, &coords[0]);
}
- FT_GlyphSlot glyph = blf_glyph_load(glyph_font, glyph_index);
+ FT_GlyphSlot glyph = blf_glyph_load(glyph_font, glyph_index, outline_only);
if (!glyph) {
return nullptr;
}
@@ -1188,6 +1194,10 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font,
blf_glyph_transform_spacing(glyph, spacing_target - spacing);
}
+ if (outline_only) {
+ return glyph;
+ }
+
FT_Outline_Translate(&glyph->outline, (FT_Pos)subpixel, 0);
if (blf_glyph_render_bitmap(glyph_font, glyph)) {
@@ -1215,7 +1225,7 @@ static GlyphBLF *blf_glyph_ensure_ex(FontBLF *font,
}
FT_GlyphSlot glyph = blf_glyph_render(
- font, font_with_glyph, glyph_index, charcode, subpixel, gc->fixed_width);
+ font, font_with_glyph, glyph_index, charcode, subpixel, gc->fixed_width, false);
if (glyph) {
/* Save this glyph in the initial font's cache. */
@@ -1476,4 +1486,306 @@ void blf_glyph_draw(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, const int x,
#endif
}
+/* -------------------------------------------------------------------- */
+/** \name Convert Glyph to Curves
+ * \{ */
+
+/**
+ * from: http://www.freetype.org/freetype2/docs/glyphs/glyphs-6.html#section-1
+ *
+ * Vectorial representation of Freetype glyphs
+ *
+ * The source format of outlines is a collection of closed paths called "contours". Each contour is
+ * made of a series of line segments and bezier arcs. Depending on the file format, these can be
+ * second-order or third-order polynomials. The former are also called quadratic or conic arcs, and
+ * they come from the TrueType format. The latter are called cubic arcs and mostly come from the
+ * Type1 format.
+ *
+ * Each arc is described through a series of start, end and control points.
+ * Each point of the outline has a specific tag which indicates whether it is
+ * used to describe a line segment or an arc.
+ * The following rules are applied to decompose the contour's points into segments and arcs :
+ *
+ * # two successive "on" points indicate a line segment joining them.
+ *
+ * # one conic "off" point midst two "on" points indicates a conic bezier arc,
+ * the "off" point being the control point, and the "on" ones the start and end points.
+ *
+ * # Two successive cubic "off" points midst two "on" points indicate a cubic bezier arc.
+ * There must be exactly two cubic control points and two on points for each cubic arc
+ * (using a single cubic "off" point between two "on" points is forbidden, for example).
+ *
+ * # finally, two successive conic "off" points forces the rasterizer to create
+ * (during the scan-line conversion process exclusively) a virtual "on" point midst them,
+ * at their exact middle.
+ * This greatly facilitates the definition of successive conic bezier arcs.
+ * Moreover, it's the way outlines are described in the TrueType specification.
+ *
+ * Note that it is possible to mix conic and cubic arcs in a single contour, even though no current
+ * font driver produces such outlines.
+ *
+ *
+ * * # on
+ * * off
+ * __---__
+ * #-__ _-- -_
+ * --__ _- -
+ * --__ # \
+ * --__ #
+ * -#
+ * Two "on" points
+ * Two "on" points and one "conic" point
+ * between them
+ * *
+ * # __ Two "on" points with two "conic"
+ * \ - - points between them. The point
+ * \ / \ marked '0' is the middle of the
+ * - 0 \ "off" points, and is a 'virtual'
+ * -_ _- # "on" point where the curve passes.
+ * -- It does not appear in the point
+ * list.
+ * *
+ * * # on
+ * * * off
+ * __---__
+ * _-- -_
+ * _- -
+ * # \
+ * #
+ *
+ * Two "on" points
+ * and two "cubic" point
+ * between them
+ *
+ *
+ * Each glyphs original outline points are located on a grid of indivisible units.
+ * The points are stored in the font file as 16-bit integer grid coordinates,
+ * with the grid origin's being at (0, 0); they thus range from -16384 to 16383.
+ *
+ * Convert conic to bezier arcs:
+ * Conic P0 P1 P2
+ * Bezier B0 B1 B2 B3
+ * B0=P0
+ * B1=(P0+2*P1)/3
+ * B2=(P2+2*P1)/3
+ * B3=P2
+ */
+
+static void blf_glyph_to_curves(FT_Outline ftoutline, ListBase *nurbsbase, const float scale)
+{
+ const float eps = 0.0001f;
+ const float eps_sq = eps * eps;
+ Nurb *nu;
+ BezTriple *bezt;
+ float dx, dy;
+ int j, k, l, l_first = 0;
+
+ /* initialize as -1 to add 1 on first loop each time */
+ int contour_prev;
+
+ /* Start converting the FT data */
+ int *onpoints = static_cast(
+ MEM_callocN(size_t(ftoutline.n_contours) * sizeof(int), "onpoints"));
+
+ /* Get number of on-curve points for bezier-triples (including conic virtual on-points). */
+ for (j = 0, contour_prev = -1; j < ftoutline.n_contours; j++) {
+ const int n = ftoutline.contours[j] - contour_prev;
+ contour_prev = ftoutline.contours[j];
+
+ for (k = 0; k < n; k++) {
+ l = (j > 0) ? (k + ftoutline.contours[j - 1] + 1) : k;
+ if (k == 0) {
+ l_first = l;
+ }
+
+ if (ftoutline.tags[l] == FT_Curve_Tag_On) {
+ onpoints[j]++;
+ }
+
+ {
+ const int l_next = (k < n - 1) ? (l + 1) : l_first;
+ if (ftoutline.tags[l] == FT_Curve_Tag_Conic &&
+ ftoutline.tags[l_next] == FT_Curve_Tag_Conic) {
+ onpoints[j]++;
+ }
+ }
+ }
+ }
+
+ /* contour loop, bezier & conic styles merged */
+ for (j = 0, contour_prev = -1; j < ftoutline.n_contours; j++) {
+ const int n = ftoutline.contours[j] - contour_prev;
+ contour_prev = ftoutline.contours[j];
+
+ /* add new curve */
+ nu = (Nurb *)MEM_callocN(sizeof(Nurb), "objfnt_nurb");
+ bezt = static_cast(
+ MEM_callocN(size_t(onpoints[j]) * sizeof(BezTriple), "objfnt_bezt"));
+ BLI_addtail(nurbsbase, nu);
+
+ nu->type = CU_BEZIER;
+ nu->pntsu = onpoints[j];
+ nu->resolu = 8;
+ nu->flagu = CU_NURB_CYCLIC;
+ nu->bezt = bezt;
+
+ /* individual curve loop, start-end */
+ for (k = 0; k < n; k++) {
+ l = (j > 0) ? (k + ftoutline.contours[j - 1] + 1) : k;
+ if (k == 0) {
+ l_first = l;
+ }
+
+ /* virtual conic on-curve points */
+ {
+ const int l_next = (k < n - 1) ? (l + 1) : l_first;
+ if (ftoutline.tags[l] == FT_Curve_Tag_Conic &&
+ ftoutline.tags[l_next] == FT_Curve_Tag_Conic) {
+ dx = float(ftoutline.points[l].x + ftoutline.points[l_next].x) * scale / 2.0f;
+ dy = float(ftoutline.points[l].y + ftoutline.points[l_next].y) * scale / 2.0f;
+
+ /* left handle */
+ bezt->vec[0][0] = (dx + (2.0f * float(ftoutline.points[l].x)) * scale) / 3.0f;
+ bezt->vec[0][1] = (dy + (2.0f * float(ftoutline.points[l].y)) * scale) / 3.0f;
+
+ /* midpoint (virtual on-curve point) */
+ bezt->vec[1][0] = dx;
+ bezt->vec[1][1] = dy;
+
+ /* right handle */
+ bezt->vec[2][0] = (dx + (2.0f * float(ftoutline.points[l_next].x)) * scale) / 3.0f;
+ bezt->vec[2][1] = (dy + (2.0f * float(ftoutline.points[l_next].y)) * scale) / 3.0f;
+
+ bezt->h1 = bezt->h2 = HD_ALIGN;
+ bezt->radius = 1.0f;
+ bezt++;
+ }
+ }
+
+ /* on-curve points */
+ if (ftoutline.tags[l] == FT_Curve_Tag_On) {
+ const int l_prev = (k > 0) ? (l - 1) : ftoutline.contours[j];
+ const int l_next = (k < n - 1) ? (l + 1) : l_first;
+
+ /* left handle */
+ if (ftoutline.tags[l_prev] == FT_Curve_Tag_Cubic) {
+ bezt->vec[0][0] = float(ftoutline.points[l_prev].x) * scale;
+ bezt->vec[0][1] = float(ftoutline.points[l_prev].y) * scale;
+ bezt->h1 = HD_FREE;
+ }
+ else if (ftoutline.tags[l_prev] == FT_Curve_Tag_Conic) {
+ bezt->vec[0][0] = (float(ftoutline.points[l].x) +
+ (2.0f * float(ftoutline.points[l_prev].x))) *
+ scale / 3.0f;
+ bezt->vec[0][1] = (float(ftoutline.points[l].y) +
+ (2.0f * float(ftoutline.points[l_prev].y))) *
+ scale / 3.0f;
+ bezt->h1 = HD_FREE;
+ }
+ else {
+ bezt->vec[0][0] = float(ftoutline.points[l].x) * scale -
+ (float(ftoutline.points[l].x) - float(ftoutline.points[l_prev].x)) *
+ scale / 3.0f;
+ bezt->vec[0][1] = float(ftoutline.points[l].y) * scale -
+ (float(ftoutline.points[l].y) - float(ftoutline.points[l_prev].y)) *
+ scale / 3.0f;
+ bezt->h1 = HD_VECT;
+ }
+
+ /* midpoint (on-curve point) */
+ bezt->vec[1][0] = float(ftoutline.points[l].x) * scale;
+ bezt->vec[1][1] = float(ftoutline.points[l].y) * scale;
+
+ /* right handle */
+ if (ftoutline.tags[l_next] == FT_Curve_Tag_Cubic) {
+ bezt->vec[2][0] = float(ftoutline.points[l_next].x) * scale;
+ bezt->vec[2][1] = float(ftoutline.points[l_next].y) * scale;
+ bezt->h2 = HD_FREE;
+ }
+ else if (ftoutline.tags[l_next] == FT_Curve_Tag_Conic) {
+ bezt->vec[2][0] = (float(ftoutline.points[l].x) +
+ (2.0f * float(ftoutline.points[l_next].x))) *
+ scale / 3.0f;
+ bezt->vec[2][1] = (float(ftoutline.points[l].y) +
+ (2.0f * float(ftoutline.points[l_next].y))) *
+ scale / 3.0f;
+ bezt->h2 = HD_FREE;
+ }
+ else {
+ bezt->vec[2][0] = float(ftoutline.points[l].x) * scale -
+ (float(ftoutline.points[l].x) - float(ftoutline.points[l_next].x)) *
+ scale / 3.0f;
+ bezt->vec[2][1] = float(ftoutline.points[l].y) * scale -
+ (float(ftoutline.points[l].y) - float(ftoutline.points[l_next].y)) *
+ scale / 3.0f;
+ bezt->h2 = HD_VECT;
+ }
+
+ /* get the handles that are aligned, tricky...
+ * - check if one of them is a vector handle.
+ * - dist_squared_to_line_v2, check if the three beztriple points are on one line
+ * - len_squared_v2v2, see if there's a distance between the three points
+ * - len_squared_v2v2 again, to check the angle between the handles
+ */
+ if ((bezt->h1 != HD_VECT && bezt->h2 != HD_VECT) &&
+ (dist_squared_to_line_v2(bezt->vec[0], bezt->vec[1], bezt->vec[2]) <
+ (0.001f * 0.001f)) &&
+ (len_squared_v2v2(bezt->vec[0], bezt->vec[1]) > eps_sq) &&
+ (len_squared_v2v2(bezt->vec[1], bezt->vec[2]) > eps_sq) &&
+ (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) > eps_sq) &&
+ (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) >
+ max_ff(len_squared_v2v2(bezt->vec[0], bezt->vec[1]),
+ len_squared_v2v2(bezt->vec[1], bezt->vec[2]))))
+ {
+ bezt->h1 = bezt->h2 = HD_ALIGN;
+ }
+ bezt->radius = 1.0f;
+ bezt++;
+ }
+ }
+ }
+
+ MEM_freeN(onpoints);
+}
+
+static FT_GlyphSlot blf_glyphslot_ensure_outline(FontBLF *font, const uint charcode)
+{
+ /* Glyph might not come from the initial font. */
+ FontBLF *font_with_glyph = font;
+ FT_UInt glyph_index = blf_glyph_index_from_charcode(&font_with_glyph, charcode);
+
+ if (!blf_ensure_face(font_with_glyph)) {
+ return nullptr;
+ }
+
+ FT_GlyphSlot glyph = blf_glyph_render(font, font_with_glyph, glyph_index, charcode, 0, 0, true);
+
+ if (font != font_with_glyph) {
+ if (!blf_ensure_face(font)) {
+ return nullptr;
+ }
+ double ratio = float(font->face->units_per_EM) / float(font_with_glyph->face->units_per_EM);
+ FT_Matrix transform = {to_16dot16(ratio), 0, 0, to_16dot16(ratio)};
+ FT_Outline_Transform(&glyph->outline, &transform);
+ glyph->advance.x = int(float(glyph->advance.x) * ratio);
+ glyph->metrics.horiAdvance = int(float(glyph->metrics.horiAdvance) * ratio);
+ }
+
+ return glyph;
+}
+
+float blf_character_to_curves(FontBLF *font,
+ unsigned int unicode,
+ ListBase *nurbsbase,
+ const float scale)
+{
+ FT_GlyphSlot glyph = blf_glyphslot_ensure_outline(font, unicode);
+ if (!glyph) {
+ return 0.0f;
+ }
+
+ blf_glyph_to_curves(glyph->outline, nurbsbase, scale);
+ return float(glyph->advance.x) * scale;
+}
+
/** \} */
diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h
index 01346613881..bdc43270eb3 100644
--- a/source/blender/blenfont/intern/blf_internal.h
+++ b/source/blender/blenfont/intern/blf_internal.h
@@ -186,6 +186,14 @@ struct GlyphBLF *blf_glyph_ensure_subpixel(struct FontBLF *font,
int32_t pen_x);
#endif
+/**
+ * Convert a character's outlines into curves.
+ */
+float blf_character_to_curves(FontBLF *font,
+ unsigned int unicode,
+ struct ListBase *nurbsbase,
+ const float scale);
+
void blf_glyph_free(struct GlyphBLF *g);
void blf_glyph_draw(
struct FontBLF *font, struct GlyphCacheBLF *gc, struct GlyphBLF *g, int x, int y);
diff --git a/source/blender/blenkernel/intern/vfont.cc b/source/blender/blenkernel/intern/vfont.cc
index 7d2945ac89e..e164944719c 100644
--- a/source/blender/blenkernel/intern/vfont.cc
+++ b/source/blender/blenkernel/intern/vfont.cc
@@ -58,6 +58,9 @@ static PackedFile *get_builtin_packedfile(void);
/****************************** VFont Datablock ************************/
+const void *builtin_font_data = nullptr;
+int builtin_font_size = 0;
+
static void vfont_init_data(ID *id)
{
VFont *vfont = (VFont *)id;
@@ -218,9 +221,6 @@ void BKE_vfont_free_data(VFont *vfont)
}
}
-static const void *builtin_font_data = nullptr;
-static int builtin_font_size = 0;
-
bool BKE_vfont_is_builtin(const VFont *vfont)
{
return STREQ(vfont->filepath, FO_BUILTIN_NAME);
@@ -1004,10 +1004,8 @@ static bool vfont_to_curve(Object *ob,
che = find_vfont_char(vfd, ascii);
BLI_rw_mutex_unlock(&vfont_rwlock);
- /* The character wasn't in the current curve base so load it.
- * But if the font is built-in then do not try loading since
- * whole font is in the memory already. */
- if (che == nullptr && BKE_vfont_is_builtin(vfont) == false) {
+ /* The character wasn't in the current curve base so load it. */
+ if (che == nullptr) {
BLI_rw_mutex_lock(&vfont_rwlock, THREAD_LOCK_WRITE);
/* Check it once again, char might have been already load
* between previous #BLI_rw_mutex_unlock() and this #BLI_rw_mutex_lock().
diff --git a/source/blender/blenkernel/intern/vfontdata_freetype.cc b/source/blender/blenkernel/intern/vfontdata_freetype.cc
index 7ab71c29422..94bda6cb19b 100644
--- a/source/blender/blenkernel/intern/vfontdata_freetype.cc
+++ b/source/blender/blenkernel/intern/vfontdata_freetype.cc
@@ -12,321 +12,48 @@
* Code that uses exotic character maps is present but commented out.
*/
-#include
-#include FT_FREETYPE_H
-/* not needed yet */
-// #include FT_GLYPH_H
-// #include FT_BBOX_H
-// #include FT_SIZES_H
-// #include
-
#include "MEM_guardedalloc.h"
+#include "BLF_api.h"
+
#include "BLI_ghash.h"
#include "BLI_listbase.h"
-#include "BLI_math_geom.h"
-#include "BLI_math_vector.h"
#include "BLI_string.h"
#include "BLI_string_utf8.h"
-#include "BLI_utildefines.h"
#include "BKE_curve.hh"
+#include "BKE_vfont.h"
#include "BKE_vfontdata.h"
-#include "DNA_curve_types.h"
#include "DNA_packedFile_types.h"
#include "DNA_vfont_types.h"
-static void freetype_outline_to_curves(FT_Outline ftoutline,
- ListBase *nurbsbase,
- const float scale)
-{
- const float eps = 0.0001f;
- const float eps_sq = eps * eps;
- Nurb *nu;
- BezTriple *bezt;
- float dx, dy;
- int j, k, l, l_first = 0;
-
- /* initialize as -1 to add 1 on first loop each time */
- int contour_prev;
-
- /* Start converting the FT data */
- int *onpoints = (int *)MEM_callocN((ftoutline.n_contours) * sizeof(int), "onpoints");
-
- /* Get number of on-curve points for bezier-triples (including conic virtual on-points). */
- for (j = 0, contour_prev = -1; j < ftoutline.n_contours; j++) {
- const int n = ftoutline.contours[j] - contour_prev;
- contour_prev = ftoutline.contours[j];
-
- for (k = 0; k < n; k++) {
- l = (j > 0) ? (k + ftoutline.contours[j - 1] + 1) : k;
- if (k == 0) {
- l_first = l;
- }
-
- if (ftoutline.tags[l] == FT_Curve_Tag_On) {
- onpoints[j]++;
- }
-
- {
- const int l_next = (k < n - 1) ? (l + 1) : l_first;
- if (ftoutline.tags[l] == FT_Curve_Tag_Conic &&
- ftoutline.tags[l_next] == FT_Curve_Tag_Conic) {
- onpoints[j]++;
- }
- }
- }
- }
-
- /* contour loop, bezier & conic styles merged */
- for (j = 0, contour_prev = -1; j < ftoutline.n_contours; j++) {
- const int n = ftoutline.contours[j] - contour_prev;
- contour_prev = ftoutline.contours[j];
-
- /* add new curve */
- nu = (Nurb *)MEM_callocN(sizeof(Nurb), "objfnt_nurb");
- bezt = (BezTriple *)MEM_callocN((onpoints[j]) * sizeof(BezTriple), "objfnt_bezt");
- BLI_addtail(nurbsbase, nu);
-
- nu->type = CU_BEZIER;
- nu->pntsu = onpoints[j];
- nu->resolu = 8;
- nu->flagu = CU_NURB_CYCLIC;
- nu->bezt = bezt;
-
- /* individual curve loop, start-end */
- for (k = 0; k < n; k++) {
- l = (j > 0) ? (k + ftoutline.contours[j - 1] + 1) : k;
- if (k == 0) {
- l_first = l;
- }
-
- /* virtual conic on-curve points */
- {
- const int l_next = (k < n - 1) ? (l + 1) : l_first;
- if (ftoutline.tags[l] == FT_Curve_Tag_Conic &&
- ftoutline.tags[l_next] == FT_Curve_Tag_Conic) {
- dx = (ftoutline.points[l].x + ftoutline.points[l_next].x) * scale / 2.0f;
- dy = (ftoutline.points[l].y + ftoutline.points[l_next].y) * scale / 2.0f;
-
- /* left handle */
- bezt->vec[0][0] = (dx + (2 * ftoutline.points[l].x) * scale) / 3.0f;
- bezt->vec[0][1] = (dy + (2 * ftoutline.points[l].y) * scale) / 3.0f;
-
- /* midpoint (virtual on-curve point) */
- bezt->vec[1][0] = dx;
- bezt->vec[1][1] = dy;
-
- /* right handle */
- bezt->vec[2][0] = (dx + (2 * ftoutline.points[l_next].x) * scale) / 3.0f;
- bezt->vec[2][1] = (dy + (2 * ftoutline.points[l_next].y) * scale) / 3.0f;
-
- bezt->h1 = bezt->h2 = HD_ALIGN;
- bezt->radius = 1.0f;
- bezt++;
- }
- }
-
- /* on-curve points */
- if (ftoutline.tags[l] == FT_Curve_Tag_On) {
- const int l_prev = (k > 0) ? (l - 1) : ftoutline.contours[j];
- const int l_next = (k < n - 1) ? (l + 1) : l_first;
-
- /* left handle */
- if (ftoutline.tags[l_prev] == FT_Curve_Tag_Cubic) {
- bezt->vec[0][0] = ftoutline.points[l_prev].x * scale;
- bezt->vec[0][1] = ftoutline.points[l_prev].y * scale;
- bezt->h1 = HD_FREE;
- }
- else if (ftoutline.tags[l_prev] == FT_Curve_Tag_Conic) {
- bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l_prev].x)) * scale /
- 3.0f;
- bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l_prev].y)) * scale /
- 3.0f;
- bezt->h1 = HD_FREE;
- }
- else {
- bezt->vec[0][0] = ftoutline.points[l].x * scale -
- (ftoutline.points[l].x - ftoutline.points[l_prev].x) * scale / 3.0f;
- bezt->vec[0][1] = ftoutline.points[l].y * scale -
- (ftoutline.points[l].y - ftoutline.points[l_prev].y) * scale / 3.0f;
- bezt->h1 = HD_VECT;
- }
-
- /* midpoint (on-curve point) */
- bezt->vec[1][0] = ftoutline.points[l].x * scale;
- bezt->vec[1][1] = ftoutline.points[l].y * scale;
-
- /* right handle */
- if (ftoutline.tags[l_next] == FT_Curve_Tag_Cubic) {
- bezt->vec[2][0] = ftoutline.points[l_next].x * scale;
- bezt->vec[2][1] = ftoutline.points[l_next].y * scale;
- bezt->h2 = HD_FREE;
- }
- else if (ftoutline.tags[l_next] == FT_Curve_Tag_Conic) {
- bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l_next].x)) * scale /
- 3.0f;
- bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l_next].y)) * scale /
- 3.0f;
- bezt->h2 = HD_FREE;
- }
- else {
- bezt->vec[2][0] = ftoutline.points[l].x * scale -
- (ftoutline.points[l].x - ftoutline.points[l_next].x) * scale / 3.0f;
- bezt->vec[2][1] = ftoutline.points[l].y * scale -
- (ftoutline.points[l].y - ftoutline.points[l_next].y) * scale / 3.0f;
- bezt->h2 = HD_VECT;
- }
-
- /* get the handles that are aligned, tricky...
- * - check if one of them is a vector handle.
- * - dist_squared_to_line_v2, check if the three beztriple points are on one line
- * - len_squared_v2v2, see if there's a distance between the three points
- * - len_squared_v2v2 again, to check the angle between the handles
- */
- if ((bezt->h1 != HD_VECT && bezt->h2 != HD_VECT) &&
- (dist_squared_to_line_v2(bezt->vec[0], bezt->vec[1], bezt->vec[2]) <
- (0.001f * 0.001f)) &&
- (len_squared_v2v2(bezt->vec[0], bezt->vec[1]) > eps_sq) &&
- (len_squared_v2v2(bezt->vec[1], bezt->vec[2]) > eps_sq) &&
- (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) > eps_sq) &&
- (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) >
- max_ff(len_squared_v2v2(bezt->vec[0], bezt->vec[1]),
- len_squared_v2v2(bezt->vec[1], bezt->vec[2]))))
- {
- bezt->h1 = bezt->h2 = HD_ALIGN;
- }
- bezt->radius = 1.0f;
- bezt++;
- }
- }
- }
-
- MEM_freeN(onpoints);
-}
-
-static VChar *freetypechar_to_vchar(FT_Face face, FT_ULong charcode, const VFontData *vfd)
-{
- FT_UInt glyph_index = FT_Get_Char_Index(face, charcode);
- if (FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP) != FT_Err_Ok) {
- return nullptr;
- }
-
- VChar *che = (VChar *)MEM_callocN(sizeof(VChar), "objfnt_char");
- freetype_outline_to_curves(face->glyph->outline, &che->nurbsbase, vfd->scale);
- che->index = charcode;
- che->width = face->glyph->advance.x * vfd->scale;
- BLI_ghash_insert(vfd->characters, POINTER_FROM_UINT(che->index), che);
-
- return che;
-}
-
-static FT_Face vfont_face_load_from_packed_file(FT_Library library, PackedFile *pf)
-{
- FT_Face face = nullptr;
- FT_New_Memory_Face(library, static_cast(pf->data), pf->size, 0, &face);
- if (!face) {
- return nullptr;
- }
-
- /* Font must contain vectors, not bitmaps. */
- if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) {
- FT_Done_Face(face);
- return nullptr;
- }
-
- /* Select a character map. */
- FT_Error err = FT_Select_Charmap(face, FT_ENCODING_UNICODE);
- if (err) {
- err = FT_Select_Charmap(face, FT_ENCODING_APPLE_ROMAN);
- }
- if (err && face->num_charmaps > 0) {
- err = FT_Select_Charmap(face, face->charmaps[0]->encoding);
- }
- if (err) {
- FT_Done_Face(face);
- return nullptr;
- }
-
- /* Test that we can load glyphs from this font. */
- FT_UInt glyph_index = 0;
- FT_Get_First_Char(face, &glyph_index);
- if (!glyph_index ||
- FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP) != FT_Err_Ok)
- {
- FT_Done_Face(face);
- return nullptr;
- }
-
- return face;
-}
+extern const void *builtin_font_data;
+extern int builtin_font_size;
VFontData *BKE_vfontdata_from_freetypefont(PackedFile *pf)
{
- FT_Library library = nullptr;
- if (FT_Init_FreeType(&library) != FT_Err_Ok) {
- return nullptr;
- }
-
- FT_Face face = vfont_face_load_from_packed_file(library, pf);
- if (!face) {
- FT_Done_FreeType(library);
+ int fontid = BLF_load_mem("FTVFont", static_cast(pf->data), pf->size);
+ if (fontid == -1) {
return nullptr;
}
/* allocate blender font */
VFontData *vfd = static_cast(MEM_callocN(sizeof(*vfd), "FTVFontData"));
- /* Get the name. */
- if (face->family_name) {
- SNPRINTF(vfd->name, "%s %s", face->family_name, face->style_name);
- BLI_str_utf8_invalid_strip(vfd->name, strlen(vfd->name));
- }
+ /* Get the font name. */
+ char *name = BLF_display_name_from_id(fontid);
+ STRNCPY(vfd->name, name);
+ /* BLF_display_name result must be freed. */
+ MEM_freeN(name);
- /* Blender default BFont is not "complete". */
- const bool complete_font = (face->ascender != 0) && (face->descender != 0) &&
- (face->ascender != face->descender);
+ BLI_str_utf8_invalid_strip(vfd->name, ARRAY_SIZE(vfd->name));
- if (complete_font) {
- /* We can get descender as well, but we simple store descender in relation to the ascender.
- * Also note that descender is stored as a negative number. */
- vfd->ascender = float(face->ascender) / (face->ascender - face->descender);
- }
- else {
- vfd->ascender = 0.8f;
- vfd->em_height = 1.0f;
- }
+ BLF_get_vfont_metrics(fontid, &vfd->ascender, &vfd->em_height, &vfd->scale);
- /* Adjust font size */
- if (face->bbox.yMax != face->bbox.yMin) {
- vfd->scale = float(1.0 / double(face->bbox.yMax - face->bbox.yMin));
+ vfd->characters = BLI_ghash_int_new_ex(__func__, 255);
- if (complete_font) {
- vfd->em_height = float(face->ascender - face->descender) /
- (face->bbox.yMax - face->bbox.yMin);
- }
- }
- else {
- vfd->scale = 1.0f / 1000.0f;
- }
-
- /* Load the first 256 glyphs. */
-
- const FT_ULong preload_count = 256;
- vfd->characters = BLI_ghash_int_new_ex(__func__, preload_count);
-
- FT_ULong charcode = 0;
- FT_UInt glyph_index;
- for (int i = 0; i < preload_count; i++) {
- charcode = FT_Get_Next_Char(face, charcode, &glyph_index);
- if (!charcode || !glyph_index) {
- break;
- }
- freetypechar_to_vchar(face, charcode, vfd);
- }
-
- FT_Done_FreeType(library);
+ BLF_unload_id(fontid);
return vfd;
}
@@ -354,32 +81,33 @@ VChar *BKE_vfontdata_char_from_freetypefont(VFont *vfont, ulong character)
return nullptr;
}
- /* nullptr when the font file can't be found on disk. */
- if (vfont->temp_pf == nullptr) {
+ int font_id = -1;
+
+ if (BKE_vfont_is_builtin(vfont)) {
+ font_id = BLF_load_mem(vfont->data->name,
+ static_cast(builtin_font_data),
+ builtin_font_size);
+ }
+ else if (vfont->temp_pf) {
+ font_id = BLF_load_mem(vfont->data->name,
+ static_cast(vfont->temp_pf->data),
+ vfont->temp_pf->size);
+ }
+
+ if (font_id == -1) {
return nullptr;
}
- /* Initialize Freetype. */
- FT_Library library = nullptr;
- FT_Error err = FT_Init_FreeType(&library);
- if (err) {
- // error("Failed to load the Freetype font library");
- return nullptr;
- }
+ VChar *che = (VChar *)MEM_callocN(sizeof(VChar), "objfnt_char");
+ che->index = character;
- FT_Face face = vfont_face_load_from_packed_file(library, vfont->temp_pf);
- if (!face) {
- FT_Done_FreeType(library);
- return nullptr;
- }
+ /* need to set a size for embolden, etc. */
+ BLF_size(font_id, 16);
- /* Load the character */
- VChar *che = freetypechar_to_vchar(face, character, vfont->data);
-
- /* Free Freetype */
- FT_Done_Face(face);
- FT_Done_FreeType(library);
+ che->width = BLF_character_to_curves(font_id, character, &che->nurbsbase, vfont->data->scale);
+ BLI_ghash_insert(vfont->data->characters, POINTER_FROM_UINT(che->index), che);
+ BLF_unload_id(font_id);
return che;
}
@@ -392,84 +120,3 @@ VChar *BKE_vfontdata_char_copy(const VChar *vchar_src)
return vchar_dst;
}
-
-/**
- * from: http://www.freetype.org/freetype2/docs/glyphs/glyphs-6.html#section-1
- *
- * Vectorial representation of Freetype glyphs
- *
- * The source format of outlines is a collection of closed paths called "contours". Each contour is
- * made of a series of line segments and bezier arcs. Depending on the file format, these can be
- * second-order or third-order polynomials. The former are also called quadratic or conic arcs, and
- * they come from the TrueType format. The latter are called cubic arcs and mostly come from the
- * Type1 format.
- *
- * Each arc is described through a series of start, end and control points.
- * Each point of the outline has a specific tag which indicates whether it is
- * used to describe a line segment or an arc.
- * The following rules are applied to decompose the contour's points into segments and arcs :
- *
- * # two successive "on" points indicate a line segment joining them.
- *
- * # one conic "off" point midst two "on" points indicates a conic bezier arc,
- * the "off" point being the control point, and the "on" ones the start and end points.
- *
- * # Two successive cubic "off" points midst two "on" points indicate a cubic bezier arc.
- * There must be exactly two cubic control points and two on points for each cubic arc
- * (using a single cubic "off" point between two "on" points is forbidden, for example).
- *
- * # finally, two successive conic "off" points forces the rasterizer to create
- * (during the scan-line conversion process exclusively) a virtual "on" point midst them,
- * at their exact middle.
- * This greatly facilitates the definition of successive conic bezier arcs.
- * Moreover, it's the way outlines are described in the TrueType specification.
- *
- * Note that it is possible to mix conic and cubic arcs in a single contour, even though no current
- * font driver produces such outlines.
- *
- *
- * * # on
- * * off
- * __---__
- * #-__ _-- -_
- * --__ _- -
- * --__ # \
- * --__ #
- * -#
- * Two "on" points
- * Two "on" points and one "conic" point
- * between them
- * *
- * # __ Two "on" points with two "conic"
- * \ - - points between them. The point
- * \ / \ marked '0' is the middle of the
- * - 0 \ "off" points, and is a 'virtual'
- * -_ _- # "on" point where the curve passes.
- * -- It does not appear in the point
- * list.
- * *
- * * # on
- * * * off
- * __---__
- * _-- -_
- * _- -
- * # \
- * #
- *
- * Two "on" points
- * and two "cubic" point
- * between them
- *
- *
- * Each glyphs original outline points are located on a grid of indivisible units.
- * The points are stored in the font file as 16-bit integer grid coordinates,
- * with the grid origin's being at (0, 0); they thus range from -16384 to 16383.
- *
- * Convert conic to bezier arcs:
- * Conic P0 P1 P2
- * Bezier B0 B1 B2 B3
- * B0=P0
- * B1=(P0+2*P1)/3
- * B2=(P2+2*P1)/3
- * B3=P2
- */