1 // Copyright (c) 2012, Thomas Goyne <plorkyeran@aegisub.org>
2 //
3 // Permission to use, copy, modify, and distribute this software for any
4 // purpose with or without fee is hereby granted, provided that the above
5 // copyright notice and this permission notice appear in all copies.
6 //
7 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10 // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 //
15 // Aegisub Project http://www.aegisub.org/
16 
17 #include <libaegisub/fs_fwd.h>
18 #include <libaegisub/scoped_ptr.h>
19 
20 #include <boost/filesystem/path.hpp>
21 #include <functional>
22 #include <map>
23 #include <string>
24 #include <vector>
25 
26 #include <wx/string.h>
27 
28 class AssDialogue;
29 class AssFile;
30 
31 typedef std::function<void (wxString, int)> FontCollectorStatusCallback;
32 
33 struct CollectionResult {
34 	/// Characters which could not be found in any font files
35 	wxString missing;
36 	/// Paths to the file(s) containing the requested font
37 	std::vector<agi::fs::path> paths;
38 	bool fake_bold = false;
39 	bool fake_italic = false;
40 };
41 
42 typedef struct _FcConfig FcConfig;
43 typedef struct _FcFontSet FcFontSet;
44 
45 /// @class FontConfigFontFileLister
46 /// @brief fontconfig powered font lister
47 class FontConfigFontFileLister {
48 	agi::scoped_holder<FcConfig*> config;
49 
50 	/// @brief Case-insensitive match ASS/SSA font family against full name. (also known as "name for humans")
51 	/// @param family font fullname
52 	/// @param bold weight attribute
53 	/// @param italic italic attribute
54 	/// @return font set
55 	FcFontSet *MatchFullname(const char *family, int weight, int slant);
56 public:
57 	/// Constructor
58 	/// @param cb Callback for status logging
59 	FontConfigFontFileLister(FontCollectorStatusCallback &cb);
60 
61 	/// @brief Get the path to the font with the given styles
62 	/// @param facename Name of font face
63 	/// @param bold ASS font weight
64 	/// @param italic Italic?
65 	/// @param characters Characters in this style
66 	/// @return Path to the matching font file(s), or empty if not found
67 	CollectionResult GetFontPaths(std::string const& facename, int bold, bool italic, std::vector<int> const& characters);
68 };
69 
70 /// @class FontCollector
71 /// @brief Class which collects the paths to all fonts used in a script
72 class FontCollector {
73 	/// All data needed to find the font file used to render text
74 	struct StyleInfo {
75 		std::string facename;
76 		int bold;
77 		bool italic;
78 		bool operator<(StyleInfo const& rgt) const;
79 	};
80 
81 	/// Data about where each style is used
82 	struct UsageData {
83 		std::vector<int> chars;          ///< Characters used in this style which glyphs will be needed for
84 		std::vector<int> lines;          ///< Lines on which this style is used via overrides
85 		std::vector<std::string> styles; ///< ASS styles which use this style
86 	};
87 
88 	/// Message callback provider by caller
89 	FontCollectorStatusCallback status_callback;
90 
91 	FontConfigFontFileLister lister;
92 
93 	/// The set of all glyphs used in the file
94 	std::map<StyleInfo, UsageData> used_styles;
95 	/// Style name -> ASS style definition
96 	std::map<std::string, StyleInfo> styles;
97 	/// Paths to found required font files
98 	std::vector<agi::fs::path> results;
99 	/// Number of fonts which could not be found
100 	int missing = 0;
101 	/// Number of fonts which were found, but did not contain all used glyphs
102 	int missing_glyphs = 0;
103 
104 	/// Gather all of the unique styles with text on a line
105 	void ProcessDialogueLine(const AssDialogue *line, int index);
106 
107 	/// Get the font for a single style
108 	void ProcessChunk(std::pair<StyleInfo, UsageData> const& style);
109 
110 	/// Print the lines and styles on which a missing font is used
111 	void PrintUsage(UsageData const& data);
112 
113 public:
114 	/// Constructor
115 	/// @param status_callback Function to pass status updates to
116 	/// @param lister The actual font file lister
117 	FontCollector(FontCollectorStatusCallback status_callback);
118 
119 	/// @brief Get a list of the locations of all font files used in the file
120 	/// @param file Lines in the subtitle file to check
121 	/// @param status Callback function for messages
122 	/// @return List of paths to fonts
123 	std::vector<agi::fs::path> GetFontPaths(const AssFile *file);
124 };
125