|
13 | 13 | #include <ctime> |
14 | 14 | #include <glib.h> |
15 | 15 | #include "PNG.h" |
16 | | -#include "register_font.h" |
17 | 16 | #include <sstream> |
18 | 17 | #include <stdlib.h> |
19 | 18 | #include <string> |
|
27 | 26 | #include "JPEGStream.h" |
28 | 27 | #endif |
29 | 28 |
|
30 | | -#define GENERIC_FACE_ERROR \ |
31 | | - "The second argument to registerFont is required, and should be an object " \ |
32 | | - "with at least a family (string) and optionally weight (string/number) " \ |
33 | | - "and style (string)." |
34 | | - |
35 | 29 | #define CAIRO_MAX_SIZE 32767 |
36 | 30 |
|
37 | 31 | using namespace std; |
38 | 32 |
|
39 | | -std::vector<FontFace> Canvas::font_face_list; |
40 | | - |
41 | | -// Increases each time a font is (de)registered |
42 | | -int Canvas::fontSerial = 1; |
43 | | - |
44 | 33 | /* |
45 | 34 | * Initialize Canvas. |
46 | 35 | */ |
@@ -69,8 +58,6 @@ Canvas::Initialize(Napi::Env& env, Napi::Object& exports) { |
69 | 58 | StaticValue("PNG_FILTER_AVG", Napi::Number::New(env, PNG_FILTER_AVG), napi_default_jsproperty), |
70 | 59 | StaticValue("PNG_FILTER_PAETH", Napi::Number::New(env, PNG_FILTER_PAETH), napi_default_jsproperty), |
71 | 60 | StaticValue("PNG_ALL_FILTERS", Napi::Number::New(env, PNG_ALL_FILTERS), napi_default_jsproperty), |
72 | | - StaticMethod<&Canvas::RegisterFont>("_registerFont", napi_default_method), |
73 | | - StaticMethod<&Canvas::DeregisterAllFonts>("_deregisterAllFonts", napi_default_method), |
74 | 61 | StaticMethod<&Canvas::ParseFont>("parseFont", napi_default_method) |
75 | 62 | }); |
76 | 63 |
|
@@ -677,88 +664,6 @@ str_value(Napi::Maybe<Napi::Value> maybe, const char *fallback, bool can_be_numb |
677 | 664 | return NULL; |
678 | 665 | } |
679 | 666 |
|
680 | | -void |
681 | | -Canvas::RegisterFont(const Napi::CallbackInfo& info) { |
682 | | - Napi::Env env = info.Env(); |
683 | | - if (!info[0].IsString()) { |
684 | | - Napi::Error::New(env, "Wrong argument type").ThrowAsJavaScriptException(); |
685 | | - return; |
686 | | - } else if (!info[1].IsObject()) { |
687 | | - Napi::Error::New(env, GENERIC_FACE_ERROR).ThrowAsJavaScriptException(); |
688 | | - return; |
689 | | - } |
690 | | - |
691 | | - std::string filePath = info[0].As<Napi::String>(); |
692 | | - PangoFontDescription *sys_desc = get_pango_font_description((unsigned char *)(filePath.c_str())); |
693 | | - |
694 | | - if (!sys_desc) { |
695 | | - Napi::Error::New(env, "Could not parse font file").ThrowAsJavaScriptException(); |
696 | | - return; |
697 | | - } |
698 | | - |
699 | | - PangoFontDescription *user_desc = pango_font_description_new(); |
700 | | - |
701 | | - // now check the attrs, there are many ways to be wrong |
702 | | - Napi::Object js_user_desc = info[1].As<Napi::Object>(); |
703 | | - |
704 | | - // TODO: use FontParser on these values just like the FontFace API works |
705 | | - char *family = str_value(js_user_desc.Get("family"), NULL, false); |
706 | | - char *weight = str_value(js_user_desc.Get("weight"), "normal", true); |
707 | | - char *style = str_value(js_user_desc.Get("style"), "normal", false); |
708 | | - |
709 | | - if (family && weight && style) { |
710 | | - pango_font_description_set_weight(user_desc, Canvas::GetWeightFromCSSString(weight)); |
711 | | - pango_font_description_set_style(user_desc, Canvas::GetStyleFromCSSString(style)); |
712 | | - pango_font_description_set_family(user_desc, family); |
713 | | - |
714 | | - auto found = std::find_if(font_face_list.begin(), font_face_list.end(), [&](FontFace& f) { |
715 | | - return pango_font_description_equal(f.sys_desc, sys_desc); |
716 | | - }); |
717 | | - |
718 | | - if (found != font_face_list.end()) { |
719 | | - pango_font_description_free(found->user_desc); |
720 | | - found->user_desc = user_desc; |
721 | | - } else if (register_font((unsigned char *) filePath.c_str())) { |
722 | | - FontFace face; |
723 | | - face.user_desc = user_desc; |
724 | | - face.sys_desc = sys_desc; |
725 | | - strncpy((char *)face.file_path, (char *) filePath.c_str(), 1023); |
726 | | - font_face_list.push_back(face); |
727 | | - } else { |
728 | | - pango_font_description_free(user_desc); |
729 | | - Napi::Error::New(env, "Could not load font to the system's font host").ThrowAsJavaScriptException(); |
730 | | - |
731 | | - } |
732 | | - } else { |
733 | | - pango_font_description_free(user_desc); |
734 | | - if (!env.IsExceptionPending()) { |
735 | | - Napi::Error::New(env, GENERIC_FACE_ERROR).ThrowAsJavaScriptException(); |
736 | | - } |
737 | | - } |
738 | | - |
739 | | - free(family); |
740 | | - free(weight); |
741 | | - free(style); |
742 | | - fontSerial++; |
743 | | -} |
744 | | - |
745 | | -void |
746 | | -Canvas::DeregisterAllFonts(const Napi::CallbackInfo& info) { |
747 | | - Napi::Env env = info.Env(); |
748 | | - // Unload all fonts from pango to free up memory |
749 | | - bool success = true; |
750 | | - |
751 | | - std::for_each(font_face_list.begin(), font_face_list.end(), [&](FontFace& f) { |
752 | | - if (!deregister_font( (unsigned char *)f.file_path )) success = false; |
753 | | - pango_font_description_free(f.user_desc); |
754 | | - pango_font_description_free(f.sys_desc); |
755 | | - }); |
756 | | - |
757 | | - font_face_list.clear(); |
758 | | - fontSerial++; |
759 | | - if (!success) Napi::Error::New(env, "Could not deregister one or more fonts").ThrowAsJavaScriptException(); |
760 | | -} |
761 | | - |
762 | 667 | /* |
763 | 668 | * Do not use! This is only exported for testing |
764 | 669 | */ |
@@ -793,111 +698,6 @@ Canvas::ParseFont(const Napi::CallbackInfo& info) { |
793 | 698 | return obj; |
794 | 699 | } |
795 | 700 |
|
796 | | -/* |
797 | | - * Get a PangoStyle from a CSS string (like "italic") |
798 | | - */ |
799 | | - |
800 | | -PangoStyle |
801 | | -Canvas::GetStyleFromCSSString(const char *style) { |
802 | | - PangoStyle s = PANGO_STYLE_NORMAL; |
803 | | - |
804 | | - if (strlen(style) > 0) { |
805 | | - if (0 == strcmp("italic", style)) { |
806 | | - s = PANGO_STYLE_ITALIC; |
807 | | - } else if (0 == strcmp("oblique", style)) { |
808 | | - s = PANGO_STYLE_OBLIQUE; |
809 | | - } |
810 | | - } |
811 | | - |
812 | | - return s; |
813 | | -} |
814 | | - |
815 | | -/* |
816 | | - * Get a PangoWeight from a CSS string ("bold", "100", etc) |
817 | | - */ |
818 | | - |
819 | | -PangoWeight |
820 | | -Canvas::GetWeightFromCSSString(const char *weight) { |
821 | | - PangoWeight w = PANGO_WEIGHT_NORMAL; |
822 | | - |
823 | | - if (strlen(weight) > 0) { |
824 | | - if (0 == strcmp("bold", weight)) { |
825 | | - w = PANGO_WEIGHT_BOLD; |
826 | | - } else if (0 == strcmp("100", weight)) { |
827 | | - w = PANGO_WEIGHT_THIN; |
828 | | - } else if (0 == strcmp("200", weight)) { |
829 | | - w = PANGO_WEIGHT_ULTRALIGHT; |
830 | | - } else if (0 == strcmp("300", weight)) { |
831 | | - w = PANGO_WEIGHT_LIGHT; |
832 | | - } else if (0 == strcmp("400", weight)) { |
833 | | - w = PANGO_WEIGHT_NORMAL; |
834 | | - } else if (0 == strcmp("500", weight)) { |
835 | | - w = PANGO_WEIGHT_MEDIUM; |
836 | | - } else if (0 == strcmp("600", weight)) { |
837 | | - w = PANGO_WEIGHT_SEMIBOLD; |
838 | | - } else if (0 == strcmp("700", weight)) { |
839 | | - w = PANGO_WEIGHT_BOLD; |
840 | | - } else if (0 == strcmp("800", weight)) { |
841 | | - w = PANGO_WEIGHT_ULTRABOLD; |
842 | | - } else if (0 == strcmp("900", weight)) { |
843 | | - w = PANGO_WEIGHT_HEAVY; |
844 | | - } |
845 | | - } |
846 | | - |
847 | | - return w; |
848 | | -} |
849 | | - |
850 | | -/* |
851 | | - * Given a user description, return a description that will select the |
852 | | - * font either from the system or @font-face |
853 | | - */ |
854 | | - |
855 | | -PangoFontDescription * |
856 | | -Canvas::ResolveFontDescription(const PangoFontDescription *desc) { |
857 | | - // One of the user-specified families could map to multiple SFNT family names |
858 | | - // if someone registered two different fonts under the same family name. |
859 | | - // https://drafts.csswg.org/css-fonts-3/#font-style-matching |
860 | | - FontFace best; |
861 | | - istringstream families(pango_font_description_get_family(desc)); |
862 | | - unordered_set<string> seen_families; |
863 | | - string resolved_families; |
864 | | - bool first = true; |
865 | | - |
866 | | - for (string family; getline(families, family, ','); ) { |
867 | | - string renamed_families; |
868 | | - for (auto& ff : font_face_list) { |
869 | | - string pangofamily = string(pango_font_description_get_family(ff.user_desc)); |
870 | | - if (streq_casein(family, pangofamily)) { |
871 | | - const char* sys_desc_family_name = pango_font_description_get_family(ff.sys_desc); |
872 | | - bool unseen = seen_families.find(sys_desc_family_name) == seen_families.end(); |
873 | | - bool better = best.user_desc == nullptr || pango_font_description_better_match(desc, best.user_desc, ff.user_desc); |
874 | | - |
875 | | - // Avoid sending duplicate SFNT font names due to a bug in Pango for macOS: |
876 | | - // https://bugzilla.gnome.org/show_bug.cgi?id=762873 |
877 | | - if (unseen) { |
878 | | - seen_families.insert(sys_desc_family_name); |
879 | | - |
880 | | - if (better) { |
881 | | - renamed_families = string(sys_desc_family_name) + (renamed_families.size() ? "," : "") + renamed_families; |
882 | | - } else { |
883 | | - renamed_families = renamed_families + (renamed_families.size() ? "," : "") + sys_desc_family_name; |
884 | | - } |
885 | | - } |
886 | | - |
887 | | - if (first && better) best = ff; |
888 | | - } |
889 | | - } |
890 | | - |
891 | | - if (resolved_families.size()) resolved_families += ','; |
892 | | - resolved_families += renamed_families.size() ? renamed_families : family; |
893 | | - first = false; |
894 | | - } |
895 | | - |
896 | | - PangoFontDescription* ret = pango_font_description_copy(best.sys_desc ? best.sys_desc : desc); |
897 | | - pango_font_description_set_family(ret, resolved_families.c_str()); |
898 | | - |
899 | | - return ret; |
900 | | -} |
901 | 701 |
|
902 | 702 | // This returns an approximate value only, suitable for |
903 | 703 | // Napi::MemoryManagement:: AdjustExternalMemory. |
|
0 commit comments