Subtitle library
[jpcrr.git] / lua / textrender.lua
blob1941cfa6826d538b46ed12e711c9ba252f3b9df8
1 local cached_fonts = {};
2 local font_file = {};
4 local xD800 = 55296;
5 local xDC00 = 56320;
6 local xDFFF = 57343;
8 set_font_file = function(file)
9 font_file = file;
10 cached_fonts = {}; -- Flush cache.
11 end
13 local check_codepoint = function(codepoint)
14 if type(codepoint) == "string" then
15 if codepoint == "nonexistent" then
16 return true;
17 elseif codepoint == "invalid" then
18 return true;
19 else
20 return false;
21 end
22 elseif type(codepoint) == "number" then
23 local planechar = codepoint % 65536;
24 local plane = (codepoint - planechar) / 65536;
26 -- Negative codepoints are not valid, planes have 65534 characters
27 -- and there are 17 planes.
28 if codepoint < 0 or planechar > 65533 or plane > 16 then
29 return false;
30 end
31 -- Surrogate range not valid.
32 if codepoint >= xD800 and codepoint <= xDFFF then
33 return false;
34 end
35 return true; -- Ok.
36 else
37 return false;
38 end
39 end
41 local load_codepoint = function(codepoint)
42 local bitmap = "";
43 local metric_w = 0;
44 local metric_h = 0;
46 if not font_file or not font_file.member then
47 cached_fonts[codepoint] = false;
48 return;
49 end
51 local file, err;
52 file, err = font_file:member(tostring(codepoint));
53 if not file then
54 cached_fonts[codepoint] = false;
55 return;
56 end
57 local file2 = file:four_to_five();
58 bitmap = "";
59 local line;
60 local raw = file2:read();
61 if #raw < 2 then
62 metric_h = 0;
63 metric_w = 0;
64 bitmap = "";
65 else
66 local w1 = string.byte(raw, 1);
67 local w2 = string.byte(raw, 2);
68 local w, h, l;
69 if w1 > 127 then
70 metric_w = (w1 - 128) + 128 * w2;
71 l = #raw - 2;
72 else
73 metric_w = w1;
74 l = #raw - 1;
75 end
76 metric_h = ((8 * l) - (8 * l) % metric_w) / metric_w;
77 bitmap = raw;
78 end
79 file2:close();
81 cached_fonts[codepoint] = {bitmap = bitmap, metric_w = metric_w, metric_h = metric_h};
82 end
84 local get_character = function(codepoint)
85 if not check_codepoint(codepoint) then
86 codepoint = "invalid";
87 end
88 if cached_fonts[codepoint] == nil then
89 load_codepoint(codepoint);
90 end
91 if not cached_fonts[codepoint] then
92 -- No such codepoint in font. Fall back.
93 codepoint = "nonexistent";
94 end
95 if cached_fonts[codepoint] == nil then
96 load_codepoint(codepoint);
97 end
98 if not cached_fonts[codepoint] then
99 -- Fine, doesn't exist and no fallback.
100 return {bitmap = "", metric_w = 0, metric_h = 0};
102 return cached_fonts[codepoint];
105 local next_character = function(str, index)
106 local c1 = string.byte(str, index);
107 local c2 = nil;
108 if index < #str then
109 c2 = string.byte(str, index);
111 local codelen = 0;
112 local point = 0;
114 if c1 < xD800 or c1 > xDFFF then
115 point = c1;
116 codelen = 1;
117 elseif c1 >= xDC00 then
118 point = "invalid";
119 codelen = 1;
120 elseif not c2 then
121 point = "invalid";
122 codelen = 1;
123 elseif c2 < xDC00 or c2 > xDFFF then
124 point = "invalid";
125 codelen = 2;
126 else
127 c1 = c1 - xD800;
128 c2 = c2 - xDC00;
129 point = 65536 + c1 * 1024 + c2;
130 codelen = 2;
132 if index + codelen <= #str then
133 return point, index + codelen;
134 else
135 return point, nil;
139 text_metrics = function(str, singleline)
140 local metric_w = 0;
141 local metric_h = 0;
142 local metric_w_curline = 0;
143 local metric_h_curline = 0;
144 local index = 1;
146 while index do
147 local codepoint;
148 local fontdata;
149 codepoint, index = next_character(str, index);
150 if singleline or (codepoint ~= 10 and codepoint ~= 13) then
151 fontdata = get_character(codepoint);
152 if fontdata.metric_h > metric_h_curline then
153 metric_h_curline = fontdata.metric_h;
155 metric_w_curline = metric_w_curline + fontdata.metric_w;
156 else
157 if metric_w_curline > metric_w then
158 metric_w = metric_w_curline;
160 metric_h = metric_h + metric_h_curline;
161 metric_w_curline = 0;
162 metric_h_curline = 0;
165 if metric_w_curline > metric_w then
166 metric_w = metric_w_curline;
168 metric_h = metric_h + metric_h_curline;
169 metric_w_curline = 0;
170 metric_h_curline = 0;
172 return metric_w, metric_h;
175 render_text = function(flags, x, y, str, singleline, fgr, fgg, fgb, fga, bgr, bgg, bgb, bga)
176 local metric_w = 0;
177 local metric_h = 0;
178 local metric_w_curline = 0;
179 local metric_h_curline = 0;
180 local index = 1;
182 fga = fga or 255;
183 bgr = bgr or 0;
184 bgg = bgg or 0;
185 bgb = bgb or 0;
186 bga = bga or 0;
188 while index do
189 local codepoint;
190 local fontdata;
191 codepoint, index = next_character(str, index);
192 if singleline or (codepoint ~= 10 and codepoint ~= 13) then
193 fontdata = get_character(codepoint);
194 jpcrr.hud.bitmap_binary(flags, x + metric_w_curline, y + metric_h, fontdata.bitmap, fgr, fgg,
195 fgb, fga, bgr, bgg, bgb, bga);
196 if fontdata.metric_h > metric_h_curline then
197 metric_h_curline = fontdata.metric_h;
199 metric_w_curline = metric_w_curline + fontdata.metric_w;
200 else
201 if metric_w_curline > metric_w then
202 metric_w = metric_w_curline;
204 metric_h = metric_h + metric_h_curline;
205 metric_w_curline = 0;
206 metric_h_curline = 0;