@@ -499,6 +499,7 @@ PyFT2Font_init(py::object filename, long hinting_factor = 8,
499499
500500    self->x  = new  FT2Font (open_args, hinting_factor, fallback_fonts, ft_glyph_warn,
501501                          warn_if_used);
502+     self->x ->set_parent (self);
502503
503504    self->x ->set_kerning_factor (kerning_factor);
504505
@@ -1467,6 +1468,97 @@ PyFT2Font__get_type1_encoding_vector(PyFT2Font *self)
14671468    return  indices;
14681469}
14691470
1471+ /* *********************************************************************
1472+  * Layout items 
1473+  * */  
1474+ 
1475+ struct  LayoutItem  {
1476+     PyFT2Font *ft_object;
1477+     std::u32string character;
1478+     int  glyph_idx;
1479+     double  x;
1480+     double  y;
1481+     double  prev_kern;
1482+ 
1483+     LayoutItem (PyFT2Font *f, std::u32string c, int  i, double  x, double  y, double  k) :
1484+         ft_object (f), character(c), glyph_idx(i), x(x), y(y), prev_kern(k) {}
1485+ 
1486+     std::string to_string ()
1487+     {
1488+         std::ostringstream out;
1489+         out << " LayoutItem(ft_object=" PyFT2Font_fname (ft_object);
1490+         out << " , char=" 0 ];
1491+         out << " , glyph_idx=" 
1492+         out << " , x=" 
1493+         out << " , y=" 
1494+         out << " , prev_kern=" 
1495+         out << " )" 
1496+         return  out.str ();
1497+     }
1498+ };
1499+ 
1500+ const  char  *PyFT2Font_layout__doc__ = R"""( 
1501+     Layout a string and yield information about each used glyph. 
1502+ 
1503+     .. warning:: 
1504+         This API uses the fallback list and is both private and provisional: do not use 
1505+         it directly. 
1506+ 
1507+     Parameters 
1508+     ---------- 
1509+     text : str 
1510+         The characters for which to find fonts. 
1511+ 
1512+     Returns 
1513+     ------- 
1514+     list[LayoutItem] 
1515+ )""" 
1516+ 
1517+ static  auto 
1518+ PyFT2Font_layout (PyFT2Font *self, std::u32string text, LoadFlags flags)
1519+ {
1520+     const  auto  hinting_factor = self->x ->get_hinting_factor ();
1521+     const  auto  load_flags = static_cast <FT_Int32>(flags);
1522+ 
1523+     std::set<FT_String*> glyph_seen_fonts;
1524+     std::vector<raqm_glyph_t > glyphs;
1525+     self->x ->layout (text, load_flags, glyph_seen_fonts, glyphs);
1526+ 
1527+     std::vector<LayoutItem> items;
1528+ 
1529+     double  x = 0.0 ;
1530+     double  y = 0.0 ;
1531+     std::optional<double > prev_advance = std::nullopt ;
1532+     double  prev_x = 0.0 ;
1533+     for  (auto  &glyph : glyphs) {
1534+         auto  ft_object = static_cast <FT2Font *>(glyph.ftface ->generic .data );
1535+         auto  pyft_object = static_cast <PyFT2Font *>(ft_object->get_parent ());
1536+ 
1537+         ft_object->load_glyph (glyph.index , load_flags);
1538+ 
1539+         double  prev_kern = 0.0 ;
1540+         if  (prev_advance.has_value ()) {
1541+             double  actual_advance = (x + glyph.x_offset ) - prev_x;
1542+             prev_kern = actual_advance - prev_advance.value ();
1543+         }
1544+ 
1545+         items.emplace_back (pyft_object, text.substr (glyph.cluster , 1 ), glyph.index ,
1546+                            (x + glyph.x_offset ) / 64.0 , (y + glyph.y_offset ) / 64.0 ,
1547+                            prev_kern / 64.0 );
1548+         prev_x = x + glyph.x_offset ;
1549+         x += glyph.x_advance ;
1550+         y += glyph.y_advance ;
1551+         //  Note, linearHoriAdvance is a 16.16 instead of 26.6 fixed-point value.
1552+         prev_advance = ft_object->get_face ()->glyph ->linearHoriAdvance  / 1024.0  / hinting_factor;
1553+     }
1554+ 
1555+     return  items;
1556+ }
1557+ 
1558+ /* *********************************************************************
1559+  * Deprecations 
1560+  * */  
1561+ 
14701562static  py::object
14711563ft2font__getattr__ (std::string name) {
14721564    auto  api = py::module_::import (" matplotlib._api" 
@@ -1601,8 +1693,23 @@ PYBIND11_MODULE(ft2font, m, py::mod_gil_not_used())
16011693        .def_property_readonly (" bbox" 
16021694                               " The control box of the glyph." 
16031695
1604-         auto  cls = py::class_<PyFT2Font>(m, " FT2Font" py::is_final (), py::buffer_protocol (),
1605-                                          PyFT2Font__doc__)
1696+     py::class_<LayoutItem>(m, " LayoutItem" py::is_final ())
1697+         .def_readonly (" ft_object" 
1698+                       " The FT_Face of the item." 
1699+         .def_readonly (" char" 
1700+                       " The character code for the item." 
1701+         .def_readonly (" glyph_idx" 
1702+                       " The glyph index for the item." 
1703+         .def_readonly (" x" 
1704+                       " The x position of the item." 
1705+         .def_readonly (" y" 
1706+                       " The y position of the item." 
1707+         .def_readonly (" prev_kern" 
1708+                       " The kerning between this item and the previous one." 
1709+         .def (" __str__" 
1710+ 
1711+     auto  cls = py::class_<PyFT2Font>(m, " FT2Font" py::is_final (), py::buffer_protocol (),
1712+                                      PyFT2Font__doc__)
16061713        .def (py::init (&PyFT2Font_init),
16071714             " filename" " hinting_factor" 8 , py::kw_only (),
16081715             " _fallback_list" py::none (), " _kerning_factor" 0 ,
@@ -1617,6 +1724,8 @@ PYBIND11_MODULE(ft2font, m, py::mod_gil_not_used())
16171724             PyFT2Font_select_charmap__doc__)
16181725        .def (" get_kerning" " left" " right" " mode" 
16191726             PyFT2Font_get_kerning__doc__)
1727+         .def (" _layout" " string" " flags" 
1728+              PyFT2Font_layout__doc__)
16201729        .def (" set_text" 
16211730             " string" " angle" 0.0 , " flags" 
16221731             PyFT2Font_set_text__doc__)
0 commit comments