Mercurial > jwe > octave
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. |