comparison libinterp/corefcn/ft-text-renderer.cc @ 30124:3161a1ee0045

maint: use "m_" prefix for member variables in file ft-text-renderer.cc. ft-text-renderer.cc: Use "m_" prefix for member variables. Move private member variables to bottom of private access section.
author Rik <rik@octave.org>
date Sun, 05 Sep 2021 20:01:16 -0700
parents f148aff802b6
children a61e1a0f6024
comparison
equal deleted inserted replaced
30123:d809b99f1280 30124:3161a1ee0045
148 148
149 static bool instance_ok (void) 149 static bool instance_ok (void)
150 { 150 {
151 bool retval = true; 151 bool retval = true;
152 152
153 if (! instance) 153 if (! m_instance)
154 { 154 {
155 instance = new ft_manager (); 155 m_instance = new ft_manager ();
156 singleton_cleanup_list::add (cleanup_instance); 156 singleton_cleanup_list::add (cleanup_instance);
157 } 157 }
158 158
159 return retval; 159 return retval;
160 } 160 }
161 161
162 static void cleanup_instance (void) { delete instance; instance = nullptr; } 162 static void cleanup_instance (void)
163 { delete m_instance; m_instance = nullptr; }
163 164
164 static FT_Face get_font (const std::string& name, const std::string& weight, 165 static FT_Face get_font (const std::string& name, const std::string& weight,
165 const std::string& angle, double size, 166 const std::string& angle, double size,
166 FT_ULong c = 0) 167 FT_ULong c = 0)
167 { 168 {
168 return (instance_ok () 169 return (instance_ok ()
169 ? instance->do_get_font (name, weight, angle, size, c) 170 ? m_instance->do_get_font (name, weight, angle, size, c)
170 : nullptr); 171 : nullptr);
171 } 172 }
172 173
173 static octave_map get_system_fonts (void) 174 static octave_map get_system_fonts (void)
174 { 175 {
175 return (instance_ok () 176 return (instance_ok ()
176 ? instance->do_get_system_fonts () 177 ? m_instance->do_get_system_fonts ()
177 : octave_map ()); 178 : octave_map ());
178 } 179 }
179 180
180 static void font_destroyed (FT_Face face) 181 static void font_destroyed (FT_Face face)
181 { 182 {
182 if (instance_ok ()) 183 if (instance_ok ())
183 instance->do_font_destroyed (face); 184 m_instance->do_font_destroyed (face);
184 } 185 }
185 186
186 private: 187 private:
187
188 static ft_manager *instance;
189 188
190 typedef std::pair<std::string, double> ft_key; 189 typedef std::pair<std::string, double> ft_key;
191 typedef std::map<ft_key, FT_Face> ft_cache; 190 typedef std::map<ft_key, FT_Face> ft_cache;
192
193 // Cache the fonts loaded by FreeType. This cache only contains
194 // weak references to the fonts, strong references are only present
195 // in class text_renderer.
196 ft_cache cache;
197 191
198 static octave_map do_get_system_fonts (void) 192 static octave_map do_get_system_fonts (void)
199 { 193 {
200 static octave_map font_map; 194 static octave_map font_map;
201 195
289 // Look first into the font cache, then use fontconfig. If the font 283 // Look first into the font cache, then use fontconfig. If the font
290 // is present in the cache, simply add a reference and return it. 284 // is present in the cache, simply add a reference and return it.
291 285
292 ft_key key (name + ':' + weight + ':' + angle + ':' 286 ft_key key (name + ':' + weight + ':' + angle + ':'
293 + std::to_string (search_code_point), size); 287 + std::to_string (search_code_point), size);
294 ft_cache::const_iterator it = cache.find (key); 288 ft_cache::const_iterator it = m_cache.find (key);
295 289
296 if (it != cache.end ()) 290 if (it != m_cache.end ())
297 { 291 {
298 FT_Reference_Face (it->second); 292 FT_Reference_Face (it->second);
299 return it->second; 293 return it->second;
300 } 294 }
301 #endif 295 #endif
415 retval->generic.data = new ft_key (key); 409 retval->generic.data = new ft_key (key);
416 retval->generic.finalizer = ft_face_destroyed; 410 retval->generic.finalizer = ft_face_destroyed;
417 411
418 // Insert loaded font into the cache. 412 // Insert loaded font into the cache.
419 if (FT_Reference_Face (retval) == 0) 413 if (FT_Reference_Face (retval) == 0)
420 cache[key] = retval; 414 m_cache[key] = retval;
421 } 415 }
422 #endif 416 #endif
423 } 417 }
424 418
425 return retval; 419 return retval;
429 { 423 {
430 if (face->generic.data) 424 if (face->generic.data)
431 { 425 {
432 ft_key *pkey = reinterpret_cast<ft_key *> (face->generic.data); 426 ft_key *pkey = reinterpret_cast<ft_key *> (face->generic.data);
433 427
434 cache.erase (*pkey); 428 m_cache.erase (*pkey);
435 delete pkey; 429 delete pkey;
436 face->generic.data = nullptr; 430 face->generic.data = nullptr;
437 FT_Done_Face (face); 431 FT_Done_Face (face);
438 } 432 }
439 } 433 }
440 434
441 private: 435 //--------
436
437 static ft_manager *m_instance;
438
439 // Cache the fonts loaded by FreeType. This cache only contains
440 // weak references to the fonts, strong references are only present
441 // in class text_renderer.
442 ft_cache m_cache;
443
442 FT_Library m_library; 444 FT_Library m_library;
443 bool m_freetype_initialized; 445 bool m_freetype_initialized;
444 bool m_fontconfig_initialized; 446 bool m_fontconfig_initialized;
445 }; 447 };
446 448
447 ft_manager *ft_manager::instance = nullptr; 449 ft_manager *ft_manager::m_instance = nullptr;
448 450
449 static void 451 static void
450 ft_face_destroyed (void *object) 452 ft_face_destroyed (void *object)
451 { 453 {
452 ft_manager::font_destroyed (reinterpret_cast<FT_Face> (object)); 454 ft_manager::font_destroyed (reinterpret_cast<FT_Face> (object));
502 504
503 void visit (text_element_combined& e); 505 void visit (text_element_combined& e);
504 506
505 void reset (void); 507 void reset (void);
506 508
507 uint8NDArray get_pixels (void) const { return pixels; } 509 uint8NDArray get_pixels (void) const { return m_pixels; }
508 510
509 Matrix get_boundingbox (void) const { return m_bbox; } 511 Matrix get_boundingbox (void) const { return m_bbox; }
510 512
511 uint8NDArray render (text_element *elt, Matrix& box, 513 uint8NDArray render (text_element *elt, Matrix& box,
512 int rotation = ROTATION_0); 514 int rotation = ROTATION_0);
598 // multiple lines, the value y is usually negative. 600 // multiple lines, the value y is usually negative.
599 Matrix m_bbox; 601 Matrix m_bbox;
600 602
601 // Used to stored the rendered text. It's a 3D matrix with size MxNx4 603 // Used to stored the rendered text. It's a 3D matrix with size MxNx4
602 // where M and N are the width and height of the bounding box. 604 // where M and N are the width and height of the bounding box.
603 uint8NDArray pixels; 605 uint8NDArray m_pixels;
604 606
605 // Used to store the bounding box of each line. This is used to layout 607 // Used to store the bounding box of each line. This is used to layout
606 // multiline text properly. 608 // multiline text properly.
607 std::list<Matrix> line_bbox; 609 std::list<Matrix> m_line_bbox;
608 610
609 // The current horizontal alignment. This is used to align multi-line text. 611 // The current horizontal alignment. This is used to align multi-line text.
610 int m_halign; 612 int m_halign;
611 613
612 // The X offset for the next glyph. 614 // The X offset for the next glyph.
676 678
677 if (face) 679 if (face)
678 { 680 {
679 Matrix bb (1, 5, 0.0); 681 Matrix bb (1, 5, 0.0);
680 682
681 line_bbox.push_back (bb); 683 m_line_bbox.push_back (bb);
682 684
683 m_xoffset = m_yoffset = 0; 685 m_xoffset = m_yoffset = 0;
684 m_ymin = m_ymax = m_deltax = 0; 686 m_ymin = m_ymax = m_deltax = 0;
685 } 687 }
686 } 688 }
689 case MODE_RENDER: 691 case MODE_RENDER:
690 { 692 {
691 // Move to the next line bbox, adjust xoffset based on alignment 693 // Move to the next line bbox, adjust xoffset based on alignment
692 // and yoffset based on the old and new line bbox. 694 // and yoffset based on the old and new line bbox.
693 695
694 Matrix old_bbox = line_bbox.front (); 696 Matrix old_bbox = m_line_bbox.front ();
695 line_bbox.pop_front (); 697 m_line_bbox.pop_front ();
696 Matrix new_bbox = line_bbox.front (); 698 Matrix new_bbox = m_line_bbox.front ();
697 699
698 m_xoffset = m_line_xoffset = compute_line_xoffset (new_bbox); 700 m_xoffset = m_line_xoffset = compute_line_xoffset (new_bbox);
699 m_line_yoffset -= (-old_bbox(1) + math::round (0.4 * m_max_fontsize) 701 m_line_yoffset -= (-old_bbox(1) + math::round (0.4 * m_max_fontsize)
700 + (new_bbox(3) + new_bbox(1))); 702 + (new_bbox(3) + new_bbox(1)));
701 m_yoffset = 0; 703 m_yoffset = 0;
730 // Stack the various line bbox together and compute the final 732 // Stack the various line bbox together and compute the final
731 // bounding box for the entire text string. 733 // bounding box for the entire text string.
732 734
733 m_bbox = Matrix (); 735 m_bbox = Matrix ();
734 736
735 switch (line_bbox.size ()) 737 switch (m_line_bbox.size ())
736 { 738 {
737 case 0: 739 case 0:
738 break; 740 break;
739 741
740 case 1: 742 case 1:
741 m_bbox = line_bbox.front ().extract (0, 0, 0, 3); 743 m_bbox = m_line_bbox.front ().extract (0, 0, 0, 3);
742 break; 744 break;
743 745
744 default: 746 default:
745 for (const auto& lbox : line_bbox) 747 for (const auto& lbox : m_line_bbox)
746 { 748 {
747 if (m_bbox.isempty ()) 749 if (m_bbox.isempty ())
748 m_bbox = lbox.extract (0, 0, 0, 3); 750 m_bbox = lbox.extract (0, 0, 0, 3);
749 else 751 else
750 { 752 {
766 // current yoffset, that is the offset of the current glyph's baseline 768 // current yoffset, that is the offset of the current glyph's baseline
767 // the line's baseline. 769 // the line's baseline.
768 770
769 if (m_mode == MODE_BBOX) 771 if (m_mode == MODE_BBOX)
770 { 772 {
771 Matrix& bb = line_bbox.back (); 773 Matrix& bb = m_line_bbox.back ();
772 bb(1) = m_ymin; 774 bb(1) = m_ymin;
773 // Add one pixel to the bbox height to avoid occasional text clipping. 775 // Add one pixel to the bbox height to avoid occasional text clipping.
774 // See bug #55328. 776 // See bug #55328.
775 bb(3) = (m_ymax + 1) - m_ymin; 777 bb(3) = (m_ymax + 1) - m_ymin;
776 if (m_deltax > 0) 778 if (m_deltax > 0)
787 { 789 {
788 case MODE_BBOX: 790 case MODE_BBOX:
789 m_xoffset = m_line_yoffset = m_yoffset = 0; 791 m_xoffset = m_line_yoffset = m_yoffset = 0;
790 m_max_fontsize = 0.0; 792 m_max_fontsize = 0.0;
791 m_bbox = Matrix (1, 4, 0.0); 793 m_bbox = Matrix (1, 4, 0.0);
792 line_bbox.clear (); 794 m_line_bbox.clear ();
793 push_new_line (); 795 push_new_line ();
794 break; 796 break;
795 797
796 case MODE_RENDER: 798 case MODE_RENDER:
797 if (m_bbox.numel () != 4) 799 if (m_bbox.numel () != 4)
798 { 800 {
799 ::error ("ft_text_renderer: invalid bounding box, cannot render"); 801 ::error ("ft_text_renderer: invalid bounding box, cannot render");
800 802
801 m_xoffset = m_line_yoffset = m_yoffset = 0; 803 m_xoffset = m_line_yoffset = m_yoffset = 0;
802 pixels = uint8NDArray (); 804 m_pixels = uint8NDArray ();
803 } 805 }
804 else 806 else
805 { 807 {
806 dim_vector d (4, octave_idx_type (m_bbox(2)), 808 dim_vector d (4, octave_idx_type (m_bbox(2)),
807 octave_idx_type (m_bbox(3))); 809 octave_idx_type (m_bbox(3)));
808 pixels = uint8NDArray (d, static_cast<uint8_t> (0)); 810 m_pixels = uint8NDArray (d, static_cast<uint8_t> (0));
809 m_xoffset = compute_line_xoffset (line_bbox.front ()); 811 m_xoffset = compute_line_xoffset (m_line_bbox.front ());
810 m_line_yoffset = -m_bbox(1); 812 m_line_yoffset = -m_bbox(1);
811 m_yoffset = 0; 813 m_yoffset = 0;
812 } 814 }
813 break; 815 break;
814 816
815 default: 817 default:
816 error ("ft_text_renderer: invalid mode '%d'", m_mode); 818 error ("ft_text_renderer: invalid mode '%d'", m_mode);
817 break; 819 break;
818 } 820 }
819 } 821 }
822
820 bool is_opaque (const FT_GlyphSlot &glyph, const int x, const int y) 823 bool is_opaque (const FT_GlyphSlot &glyph, const int x, const int y)
821 { 824 {
822 // Borrowed from https://stackoverflow.com/questions/14800827/ 825 // Borrowed from https://stackoverflow.com/questions/14800827/
823 // indexing-pixels-in-a-monochrome-freetype-glyph-buffer 826 // indexing-pixels-in-a-monochrome-freetype-glyph-buffer
824 int pitch = std::abs (glyph->bitmap.pitch); 827 int pitch = std::abs (glyph->bitmap.pitch);
964 unsigned char pix 967 unsigned char pix
965 = (m_antialias 968 = (m_antialias
966 ? bitmap.buffer[r*bitmap.width+c] 969 ? bitmap.buffer[r*bitmap.width+c]
967 : (is_opaque (face->glyph, c, r) ? 255 : 0)); 970 : (is_opaque (face->glyph, c, r) ? 255 : 0));
968 971
969 if (x0+c < 0 || x0+c >= pixels.dim2 () 972 if (x0+c < 0 || x0+c >= m_pixels.dim2 ()
970 || y0-r < 0 || y0-r >= pixels.dim3 ()) 973 || y0-r < 0 || y0-r >= m_pixels.dim3 ())
971 { 974 {
972 // ::warning ("ft_text_renderer: x %d, y %d", 975 // ::warning ("ft_text_renderer: x %d, y %d",
973 // x0+c, y0-r); 976 // x0+c, y0-r);
974 } 977 }
975 else if (pixels(3, x0+c, y0-r).value () == 0) 978 else if (m_pixels(3, x0+c, y0-r).value () == 0)
976 { 979 {
977 pixels(0, x0+c, y0-r) = m_color(0); 980 m_pixels(0, x0+c, y0-r) = m_color(0);
978 pixels(1, x0+c, y0-r) = m_color(1); 981 m_pixels(1, x0+c, y0-r) = m_color(1);
979 pixels(2, x0+c, y0-r) = m_color(2); 982 m_pixels(2, x0+c, y0-r) = m_color(2);
980 pixels(3, x0+c, y0-r) = pix; 983 m_pixels(3, x0+c, y0-r) = pix;
981 } 984 }
982 } 985 }
983 986
984 m_xoffset += (face->glyph->advance.x >> 6); 987 m_xoffset += (face->glyph->advance.x >> 6);
985 } 988 }
986 break; 989 break;
987 990
988 case MODE_BBOX: 991 case MODE_BBOX:
989 Matrix& bb = line_bbox.back (); 992 Matrix& bb = m_line_bbox.back ();
990 993
991 // If we have a previous glyph, use kerning information. This 994 // If we have a previous glyph, use kerning information. This
992 // usually means moving a bit backward before adding the next 995 // usually means moving a bit backward before adding the next
993 // glyph. That is, "delta.x" is usually < 0. 996 // glyph. That is, "delta.x" is usually < 0.
994 if (previous) 997 if (previous)
1393 compute_bbox (); 1396 compute_bbox ();
1394 box = m_bbox; 1397 box = m_bbox;
1395 1398
1396 set_mode (MODE_RENDER); 1399 set_mode (MODE_RENDER);
1397 1400
1398 if (pixels.numel () > 0) 1401 if (m_pixels.numel () > 0)
1399 { 1402 {
1400 elt->accept (*this); 1403 elt->accept (*this);
1401 1404
1402 rotate_pixels (pixels, rotation); 1405 rotate_pixels (m_pixels, rotation);
1403 } 1406 }
1404 1407
1405 return pixels; 1408 return m_pixels;
1406 } 1409 }
1407 1410
1408 // Note: 1411 // Note:
1409 // x-extent accurately measures width of glyphs. 1412 // x-extent accurately measures width of glyphs.
1410 // y-extent is overly large because it is measured from baseline-to-baseline. 1413 // y-extent is overly large because it is measured from baseline-to-baseline.