@@ -325,10 +325,12 @@ FT2Font::get_path()
325
325
326
326
FT2Font::FT2Font (FT_Open_Args &open_args,
327
327
long hinting_factor_,
328
- std::vector<FT2Font *> &fallback_list)
328
+ std::vector<FT2Font *> &fallback_list,
329
+ PyFT2Font *py_pointer)
329
330
: image(), face(NULL )
330
331
{
331
332
clear ();
333
+ py_font = py_pointer;
332
334
333
335
FT_Error error = FT_Open_Face (_ft2Library, &open_args, 0 , &face);
334
336
@@ -372,12 +374,9 @@ FT2Font::~FT2Font()
372
374
}
373
375
374
376
if (face) {
377
+ printf (" Deleting face from: %lu\n " , face->num_glyphs );
375
378
FT_Done_Face (face);
376
379
}
377
-
378
- for (uint i = 0 ; i < fallbacks.size (); i ++) {
379
- fallbacks[i]->~FT2Font ();
380
- }
381
380
}
382
381
383
382
void FT2Font::clear ()
@@ -390,6 +389,8 @@ void FT2Font::clear()
390
389
}
391
390
392
391
glyphs.clear ();
392
+ glyph_to_font.clear ();
393
+ char_to_font.clear ();
393
394
394
395
for (uint i = 0 ; i < fallbacks.size (); i ++) {
395
396
fallbacks[i]->clear ();
@@ -435,8 +436,19 @@ void FT2Font::select_charmap(unsigned long i)
435
436
}
436
437
}
437
438
438
- int FT2Font::get_kerning (FT_UInt left, FT_UInt right, FT_UInt mode)
439
+ int FT2Font::get_kerning (FT_UInt left, FT_UInt right, FT_UInt mode, bool fallback = false )
439
440
{
441
+ if (fallback && glyph_to_font.find (left) != glyph_to_font.end () &&
442
+ glyph_to_font.find (right) != glyph_to_font.end ()) {
443
+ FT2Font *left_ft_object = glyph_to_font[left];
444
+ FT2Font *right_ft_object = glyph_to_font[right];
445
+ if (left_ft_object != right_ft_object) {
446
+ printf (" Prev FT2Font != Curr FT2Font!\n " );
447
+ }
448
+ // if left_ft_object is not the same the right_ft_object,
449
+ // do the exact same thing which set_text does.
450
+ return right_ft_object->get_kerning (left, right, mode, false );
451
+ }
440
452
if (!FT_HAS_KERNING (face)) {
441
453
return 0 ;
442
454
}
@@ -499,11 +511,12 @@ void FT2Font::set_text(
499
511
FT_UInt final_glyph_index;
500
512
FT_Error charcode_error, glyph_error;
501
513
FT2Font *ft_object_with_glyph = this ;
502
- load_char_with_fallback (ft_object_with_glyph, final_glyph_index, glyphs, codepoints[n],
503
- flags, charcode_error, glyph_error);
504
- if (charcode_error || glyph_error) {
514
+ bool was_found = load_char_with_fallback (ft_object_with_glyph, final_glyph_index, glyphs,
515
+ char_to_font, glyph_to_font, codepoints[n], flags,
516
+ charcode_error, glyph_error, false );
517
+ if (!was_found) {
505
518
ft_glyph_warn ((FT_ULong)codepoints[n]);
506
- return ;
519
+ continue ;
507
520
}
508
521
509
522
glyph_index = final_glyph_index;
@@ -544,50 +557,175 @@ void FT2Font::set_text(
544
557
}
545
558
}
546
559
547
- void FT2Font::load_char (long charcode, FT_Int32 flags)
560
+ void FT2Font::fill_glyphs (
561
+ size_t N, uint32_t *codepoints, double angle, FT_Int32 flags, bool warn = false )
548
562
{
549
- FT_UInt glyph_index = ft_get_char_index_or_warn (face, (FT_ULong)charcode);
550
- if (FT_Error error = FT_Load_Glyph (face, glyph_index, flags)) {
551
- throw_ft_error (" Could not load charcode" , error);
563
+ FT_Matrix matrix; /* transformation matrix */
564
+
565
+ angle = angle / 360.0 * 2 * M_PI;
566
+
567
+ // this computes width and height in subpixels so we have to divide by 64
568
+ matrix.xx = (FT_Fixed)(cos (angle) * 0x10000L );
569
+ matrix.xy = (FT_Fixed)(-sin (angle) * 0x10000L );
570
+ matrix.yx = (FT_Fixed)(sin (angle) * 0x10000L );
571
+ matrix.yy = (FT_Fixed)(cos (angle) * 0x10000L );
572
+
573
+ FT_Bool use_kerning = FT_HAS_KERNING (face);
574
+ FT_UInt previous = 0 ;
575
+
576
+ clear ();
577
+
578
+ bbox.xMin = bbox.yMin = 32000 ;
579
+ bbox.xMax = bbox.yMax = -32000 ;
580
+
581
+ for (unsigned int n = 0 ; n < N; n++) {
582
+ FT_UInt glyph_index;
583
+ FT_BBox glyph_bbox;
584
+ FT_Pos last_advance;
585
+
586
+ FT_UInt final_glyph_index;
587
+ FT_Error charcode_error, glyph_error;
588
+ FT2Font *ft_object_with_glyph = this ;
589
+ bool was_found = load_char_with_fallback (ft_object_with_glyph, final_glyph_index, glyphs,
590
+ char_to_font, glyph_to_font, codepoints[n], flags,
591
+ charcode_error, glyph_error, false );
592
+ if (!was_found) {
593
+ if (warn) ft_glyph_warn ((FT_ULong)codepoints[n]);
594
+ continue ;
595
+ }
596
+
597
+ glyph_index = final_glyph_index;
598
+
599
+ // retrieve kerning distance and move pen position
600
+ if (use_kerning && previous && glyph_index) {
601
+ FT_Vector delta;
602
+ ft_object_with_glyph->get_kerning (previous, glyph_index, FT_KERNING_DEFAULT, delta);
603
+ pen.x += delta.x / (hinting_factor << kerning_factor);
604
+ }
605
+
606
+ // extract glyph image and store it in our table
607
+
608
+ FT_Glyph &thisGlyph = glyphs[glyphs.size () - 1 ];
609
+
610
+ last_advance = ft_object_with_glyph->get_face ()->glyph ->advance .x ;
611
+ FT_Glyph_Transform (thisGlyph, 0 , &pen);
612
+ FT_Glyph_Transform (thisGlyph, &matrix, 0 );
613
+
614
+ FT_Glyph_Get_CBox (thisGlyph, FT_GLYPH_BBOX_SUBPIXELS, &glyph_bbox);
615
+
616
+ bbox.xMin = std::min (bbox.xMin , glyph_bbox.xMin );
617
+ bbox.xMax = std::max (bbox.xMax , glyph_bbox.xMax );
618
+ bbox.yMin = std::min (bbox.yMin , glyph_bbox.yMin );
619
+ bbox.yMax = std::max (bbox.yMax , glyph_bbox.yMax );
620
+
621
+ pen.x += last_advance;
622
+
623
+ previous = glyph_index;
552
624
}
553
- FT_Glyph thisGlyph;
554
- if (FT_Error error = FT_Get_Glyph (face->glyph , &thisGlyph)) {
555
- throw_ft_error (" Could not get glyph" , error);
625
+
626
+ FT_Vector_Transform (&pen, &matrix);
627
+ advance = pen.x ;
628
+
629
+ if (bbox.xMin > bbox.xMax ) {
630
+ bbox.xMin = bbox.yMin = bbox.xMax = bbox.yMax = 0 ;
556
631
}
557
- glyphs.push_back (thisGlyph);
558
632
}
559
633
560
- void FT2Font::load_char_with_fallback (FT2Font* &ft_object_with_glyph,
634
+ void FT2Font::load_char (long charcode, FT_Int32 flags, FT2Font *&ft_object, bool fallback = false )
635
+ {
636
+ // if this is parent FT2Font, cache will be filled in 2 ways:
637
+ // 1. set_text was previously called
638
+ // 2. set_text was not called and fallback was enabled
639
+ if (fallback && char_to_font.find (charcode) != char_to_font.end ()) {
640
+ ft_object = char_to_font[charcode];
641
+ // since it will be assigned to this object anyway
642
+ FT2Font *throwaway = NULL ;
643
+ ft_object->load_char (charcode, flags, throwaway, false );
644
+ } else if (fallback) {
645
+ FT_UInt final_glyph_index;
646
+ FT_Error charcode_error, glyph_error;
647
+ FT2Font *ft_object_with_glyph = this ;
648
+ bool was_found = load_char_with_fallback (ft_object_with_glyph, final_glyph_index, glyphs, char_to_font,
649
+ glyph_to_font, charcode, flags, charcode_error, glyph_error, true );
650
+ if (!was_found) {
651
+ ft_glyph_warn (charcode);
652
+ if (charcode_error) throw_ft_error (" Could not load charcode" , charcode_error);
653
+ else if (glyph_error) throw_ft_error (" Could not load charcode" , glyph_error);
654
+ }
655
+ ft_object = ft_object_with_glyph;
656
+ } else {
657
+ ft_object = this ;
658
+ FT_UInt glyph_index = ft_get_char_index_or_warn (face, (FT_ULong)charcode);
659
+
660
+ if (FT_Error error = FT_Load_Glyph (face, glyph_index, flags)) {
661
+ throw_ft_error (" Could not load charcode" , error);
662
+ }
663
+ FT_Glyph thisGlyph;
664
+ if (FT_Error error = FT_Get_Glyph (face->glyph , &thisGlyph)) {
665
+ throw_ft_error (" Could not get glyph" , error);
666
+ }
667
+ glyphs.push_back (thisGlyph);
668
+ }
669
+ }
670
+
671
+ bool FT2Font::load_char_with_fallback (FT2Font *&ft_object_with_glyph,
561
672
FT_UInt &final_glyph_index,
562
673
std::vector<FT_Glyph> &parent_glyphs,
674
+ std::unordered_map<long , FT2Font *> &parent_char_to_font,
675
+ std::unordered_map<FT_UInt, FT2Font *> &parent_glyph_to_font,
563
676
long charcode,
564
677
FT_Int32 flags,
565
678
FT_Error &charcode_error,
566
- FT_Error &glyph_error)
679
+ FT_Error &glyph_error,
680
+ bool override = false )
567
681
{
568
682
FT_UInt glyph_index = FT_Get_Char_Index (face, charcode);
569
683
570
- if (glyph_index) {
684
+ if (glyph_index || override ) {
571
685
charcode_error = FT_Load_Glyph (face, glyph_index, flags);
572
686
FT_Glyph thisGlyph;
573
687
glyph_error = FT_Get_Glyph (face->glyph , &thisGlyph);
688
+
689
+ if (charcode_error || glyph_error) {
690
+ return false ;
691
+ }
574
692
final_glyph_index = glyph_index;
693
+
694
+ // cache the result for future
695
+ // need to store this for anytime a character is loaded from a parent
696
+ // FT2Font object or to generate a mapping of individual characters to fonts
697
+ ft_object_with_glyph = this ;
698
+ parent_glyph_to_font[final_glyph_index] = this ;
699
+ parent_char_to_font[charcode] = this ;
575
700
parent_glyphs.push_back (thisGlyph);
701
+ return true ;
576
702
}
577
703
578
704
else {
579
705
for (uint i = 0 ; i < fallbacks.size (); ++i) {
580
- uint current_size = parent_glyphs.size ();
581
- fallbacks[i]->load_char_with_fallback (ft_object_with_glyph, final_glyph_index,
582
- parent_glyphs, charcode, flags, charcode_error,
583
- glyph_error);
584
- // jump out if glyph size increased
585
- if (parent_glyphs.size () == current_size + 1 ) {
586
- ft_object_with_glyph = fallbacks[i];
587
- return ;
588
- }
706
+ bool was_found = fallbacks[i]->load_char_with_fallback (
707
+ ft_object_with_glyph, final_glyph_index, parent_glyphs, parent_char_to_font,
708
+ parent_glyph_to_font, charcode, flags, charcode_error, glyph_error, override );
709
+ if (was_found)
710
+ return true ;
589
711
}
712
+ return false ;
713
+ }
714
+ }
715
+
716
+ void FT2Font::load_glyph (FT_UInt glyph_index,
717
+ FT_Int32 flags,
718
+ FT2Font *&ft_object,
719
+ bool fallback = false )
720
+ {
721
+ // cache is only for parent FT2Font
722
+ if (fallback && glyph_to_font.find (glyph_index) != glyph_to_font.end ()) {
723
+ ft_object = glyph_to_font[glyph_index];
724
+ } else {
725
+ ft_object = this ;
590
726
}
727
+
728
+ ft_object->load_glyph (glyph_index, flags);
591
729
}
592
730
593
731
void FT2Font::load_glyph (FT_UInt glyph_index, FT_Int32 flags)
@@ -602,6 +740,27 @@ void FT2Font::load_glyph(FT_UInt glyph_index, FT_Int32 flags)
602
740
glyphs.push_back (thisGlyph);
603
741
}
604
742
743
+ FT_UInt FT2Font::get_char_index (FT_ULong charcode, bool fallback = false )
744
+ {
745
+ FT2Font *ft_object = NULL ;
746
+ if (fallback && char_to_font.find (charcode) != char_to_font.end ()) {
747
+ // fallback denotes whether we want to search fallback list.
748
+ // should call set_text/load_char_with_fallback to parent FT2Font before
749
+ // wanting to use fallback list here. (since that populates the cache)
750
+ ft_object = char_to_font[charcode];
751
+ } else {
752
+ // set as self
753
+ ft_object = this ;
754
+ }
755
+
756
+ return ft_get_char_index_or_warn (ft_object->get_face (), charcode);
757
+ }
758
+
759
+ void FT2Font::get_cbox (FT_BBox &bbox)
760
+ {
761
+ FT_Glyph_Get_CBox (glyphs.back (), ft_glyph_bbox_subpixels, &bbox);
762
+ }
763
+
605
764
void FT2Font::get_width_height (long *width, long *height)
606
765
{
607
766
*width = advance;
@@ -692,8 +851,14 @@ void FT2Font::draw_glyph_to_bitmap(FT2Image &im, int x, int y, size_t glyphInd,
692
851
im.draw_bitmap (&bitmap->bitmap , x + bitmap->left , y);
693
852
}
694
853
695
- void FT2Font::get_glyph_name (unsigned int glyph_number, char *buffer)
854
+ void FT2Font::get_glyph_name (unsigned int glyph_number, char *buffer, bool fallback = false )
696
855
{
856
+ if (fallback && glyph_to_font.find (glyph_number) != glyph_to_font.end ()) {
857
+ // cache is only for parent FT2Font
858
+ FT2Font *ft_object = glyph_to_font[glyph_number];
859
+ ft_object->get_glyph_name (glyph_number, buffer, false );
860
+ return ;
861
+ }
697
862
if (!FT_HAS_GLYPH_NAMES (face)) {
698
863
/* Note that this generated name must match the name that
699
864
is generated by ttconv in ttfont_CharStrings_getname. */
0 commit comments