1
+ #include " cpp11/protect.hpp"
1
2
#define R_NO_REMAP
2
3
3
4
#include " string_metrics.h"
@@ -110,6 +111,10 @@ std::vector< std::vector<FontFeature> > create_font_features(list_of<list> featu
110
111
std::vector<FontSettings> create_font_settings (strings path, integers index, std::vector< std::vector<FontFeature> >& features) {
111
112
std::vector<FontSettings> res;
112
113
114
+ if (path.size () != index.size () || path.size () != features.size ()) {
115
+ cpp11::stop (" `path`, `index`, and `features` must all be of the same length" );
116
+ }
117
+
113
118
for (R_xlen_t i = 0 ; i < path.size (); ++i) {
114
119
res.emplace_back ();
115
120
strncpy (res.back ().file , Rf_translateCharUTF8 (path[i]), PATH_MAX);
@@ -129,77 +134,99 @@ list get_string_shape_c(strings string, integers id, strings path, integers inde
129
134
doubles indent, doubles hanging, doubles space_before,
130
135
doubles space_after) {
131
136
int n_strings = string.size ();
132
- auto all_features = create_font_features (features);
133
- auto fonts = create_font_settings (path, index, all_features);
134
137
135
138
// Return Columns
136
139
writable::integers glyph, glyph_id, metric_id, string_id, fontindex;
137
140
writable::doubles x_offset, y_offset, widths, heights, left_bearings, right_bearings,
138
141
top_bearings, bottom_bearings, left_border, top_border, pen_x, pen_y, fontsize,
139
142
advance, ascender, descender;
140
- writable::strings fontpath;
141
-
142
- // Shape the text
143
- int cur_id = id[0 ] - 1 ; // make sure it differs from first
144
- bool success = false ;
145
-
146
- HarfBuzzShaper& shaper = get_hb_shaper ();
147
- for (int i = 0 ; i < n_strings; ++i) {
148
- const char * this_string = Rf_translateCharUTF8 (string[i]);
149
- int this_id = id[i];
150
- if (cur_id == this_id) {
151
- success = shaper.add_string (this_string, fonts[i], size[i], tracking[i], cpp11::is_na (string[i]));
152
-
153
- if (!success) {
154
- Rf_error (" Failed to shape string (%s) with font file (%s) with freetype error %i" , this_string, Rf_translateCharUTF8 (path[i]), shaper.error_code );
155
- }
156
- } else {
157
- cur_id = this_id;
158
- success = shaper.shape_string (this_string, fonts[i], size[i], res[i],
159
- lineheight[i], align[i], hjust[i], vjust[i],
160
- width[i] * 64.0 , tracking[i], indent[i] * 64.0 ,
161
- hanging[i] * 64.0 , space_before[i] * 64.0 ,
162
- space_after[i] * 64.0 , cpp11::is_na (string[i]));
163
-
164
- if (!success) {
165
- Rf_error (" Failed to shape string (%s) with font file (%s) with freetype error %i" , this_string, Rf_translateCharUTF8 (STRING_ELT (path, i)), shaper.error_code );
166
- }
143
+ writable::strings fontpath, str;
144
+
145
+ if (n_strings != 0 ) {
146
+ if (n_strings != id.size () ||
147
+ n_strings != path.size () ||
148
+ n_strings != index.size () ||
149
+ n_strings != features.size () ||
150
+ n_strings != size.size () ||
151
+ n_strings != res.size () ||
152
+ n_strings != lineheight.size () ||
153
+ n_strings != align.size () ||
154
+ n_strings != hjust.size () ||
155
+ n_strings != vjust.size () ||
156
+ n_strings != width.size () ||
157
+ n_strings != tracking.size () ||
158
+ n_strings != indent.size () ||
159
+ n_strings != hanging.size () ||
160
+ n_strings != space_before.size () ||
161
+ n_strings != space_after.size ()
162
+ ) {
163
+ cpp11::stop (" All input must be the same size" );
167
164
}
168
- bool store_string = i == n_strings - 1 || cur_id != INTEGER (id)[i + 1 ];
169
- if (store_string) {
170
- success = shaper.finish_string ();
171
- if (!success) {
172
- Rf_error (" Failed to finalise string shaping" );
165
+ auto all_features = create_font_features (features);
166
+ auto fonts = create_font_settings (path, index, all_features);
167
+
168
+ // Shape the text
169
+ int cur_id = id[0 ] - 1 ; // make sure it differs from first
170
+ bool success = false ;
171
+
172
+ HarfBuzzShaper& shaper = get_hb_shaper ();
173
+ for (int i = 0 ; i < n_strings; ++i) {
174
+ const char * this_string = Rf_translateCharUTF8 (string[i]);
175
+ int this_id = id[i];
176
+ if (cur_id == this_id) {
177
+ success = shaper.add_string (this_string, fonts[i], size[i], tracking[i], cpp11::is_na (string[i]));
178
+
179
+ if (!success) {
180
+ cpp11::stop (" Failed to shape string (%s) with font file (%s) with freetype error %i" , this_string, Rf_translateCharUTF8 (path[i]), shaper.error_code );
181
+ }
182
+ } else {
183
+ cur_id = this_id;
184
+ success = shaper.shape_string (this_string, fonts[i], size[i], res[i],
185
+ lineheight[i], align[i], hjust[i], vjust[i],
186
+ width[i] * 64.0 , tracking[i], indent[i] * 64.0 ,
187
+ hanging[i] * 64.0 , space_before[i] * 64.0 ,
188
+ space_after[i] * 64.0 , cpp11::is_na (string[i]));
189
+
190
+ if (!success) {
191
+ cpp11::stop (" Failed to shape string (%s) with font file (%s) with freetype error %i" , this_string, Rf_translateCharUTF8 (STRING_ELT (path, i)), shaper.error_code );
192
+ }
173
193
}
174
- int n_glyphs = shaper.glyph_id .size ();
175
- for (int j = 0 ; j < n_glyphs; j++) {
176
- if (shaper.must_break [j]) continue ; // Don't add any linebreak chars as they often map to null glyph
177
- glyph.push_back ((int ) shaper.glyph_cluster [j] + 1 );
178
- glyph_id.push_back ((int ) shaper.glyph_id [j]);
179
- metric_id.push_back (pen_x.size () + 1 );
180
- string_id.push_back (shaper.string_id [j] + 1 );
181
- x_offset.push_back (double (shaper.x_pos [j]) / 64.0 );
182
- y_offset.push_back (double (shaper.y_pos [j]) / 64.0 );
183
- fontpath.push_back (shaper.fontfile [j]);
184
- fontindex.push_back ((int ) shaper.fontindex [j]);
185
- fontsize.push_back (shaper.fontsize [j]);
186
- advance.push_back (double (shaper.advance [j]) / 64.0 );
187
- ascender.push_back (double (shaper.ascender [j]) / 64.0 );
188
- descender.push_back (double (shaper.descender [j]) / 64.0 );
194
+ bool store_string = i == n_strings - 1 || cur_id != INTEGER (id)[i + 1 ];
195
+ if (store_string) {
196
+ success = shaper.finish_string ();
197
+ if (!success) {
198
+ cpp11::stop (" Failed to finalise string shaping" );
199
+ }
200
+ int n_glyphs = shaper.glyph_id .size ();
201
+ for (int j = 0 ; j < n_glyphs; j++) {
202
+ if (shaper.must_break [j]) continue ; // Don't add any linebreak chars as they often map to null glyph
203
+ glyph.push_back ((int ) shaper.glyph_cluster [j] + 1 );
204
+ glyph_id.push_back ((int ) shaper.glyph_id [j]);
205
+ metric_id.push_back (pen_x.size () + 1 );
206
+ string_id.push_back (shaper.string_id [j] + 1 );
207
+ x_offset.push_back (double (shaper.x_pos [j]) / 64.0 );
208
+ y_offset.push_back (double (shaper.y_pos [j]) / 64.0 );
209
+ fontpath.push_back (shaper.fontfile [j]);
210
+ fontindex.push_back ((int ) shaper.fontindex [j]);
211
+ fontsize.push_back (shaper.fontsize [j]);
212
+ advance.push_back (double (shaper.advance [j]) / 64.0 );
213
+ ascender.push_back (double (shaper.ascender [j]) / 64.0 );
214
+ descender.push_back (double (shaper.descender [j]) / 64.0 );
215
+ }
216
+ widths.push_back (double (shaper.width ) / 64.0 );
217
+ heights.push_back (double (shaper.height ) / 64.0 );
218
+ left_bearings.push_back (double (shaper.left_bearing ) / 64.0 );
219
+ right_bearings.push_back (double (shaper.right_bearing ) / 64.0 );
220
+ top_bearings.push_back (double (shaper.top_bearing ) / 64.0 );
221
+ bottom_bearings.push_back (double (shaper.bottom_bearing ) / 64.0 );
222
+ left_border.push_back (double (shaper.left_border ) / 64.0 );
223
+ top_border.push_back (double (shaper.top_border ) / 64.0 );
224
+ pen_x.push_back (double (shaper.pen_x ) / 64.0 );
225
+ pen_y.push_back (double (shaper.pen_y ) / 64.0 );
189
226
}
190
- widths.push_back (double (shaper.width ) / 64.0 );
191
- heights.push_back (double (shaper.height ) / 64.0 );
192
- left_bearings.push_back (double (shaper.left_bearing ) / 64.0 );
193
- right_bearings.push_back (double (shaper.right_bearing ) / 64.0 );
194
- top_bearings.push_back (double (shaper.top_bearing ) / 64.0 );
195
- bottom_bearings.push_back (double (shaper.bottom_bearing ) / 64.0 );
196
- left_border.push_back (double (shaper.left_border ) / 64.0 );
197
- top_border.push_back (double (shaper.top_border ) / 64.0 );
198
- pen_x.push_back (double (shaper.pen_x ) / 64.0 );
199
- pen_y.push_back (double (shaper.pen_y ) / 64.0 );
200
227
}
228
+ str = writable::strings (pen_x.size ());
201
229
}
202
- writable::strings str (pen_x.size ());
203
230
204
231
writable::data_frame string_df ({
205
232
" string" _nm = str,
@@ -241,34 +268,37 @@ list get_string_shape_c(strings string, integers id, strings path, integers inde
241
268
doubles get_line_width_c (strings string, strings path, integers index, doubles size,
242
269
doubles res, logicals include_bearing) {
243
270
int n_strings = string.size ();
244
- bool one_path = path.size () == 1 ;
245
- const char * first_path = Rf_translateCharUTF8 (path[0 ]);
246
- int first_index = index[0 ];
247
- bool one_size = size.size () == 1 ;
248
- double first_size = size[0 ];
249
- bool one_res = res.size () == 1 ;
250
- double first_res = res[0 ];
251
- bool one_bear = include_bearing.size () == 1 ;
252
- int first_bear = include_bearing[0 ];
253
-
254
271
writable::doubles widths;
255
- int error = 1 ;
256
- double width = 0 ;
257
-
258
- for (int i = 0 ; i < n_strings; ++i) {
259
- error = string_width (
260
- Rf_translateCharUTF8 (string[i]),
261
- one_path ? first_path : Rf_translateCharUTF8 (path[i]),
262
- one_path ? first_index : index[i],
263
- one_size ? first_size : size[i],
264
- one_res ? first_res : res[i],
265
- one_bear ? first_bear : static_cast <int >(include_bearing[0 ]),
266
- &width
267
- );
268
- if (error) {
269
- Rf_error (" Failed to calculate width of string (%s) with font file (%s) with freetype error %i" , Rf_translateCharUTF8 (string[i]), Rf_translateCharUTF8 (path[i]), error);
272
+ if (n_strings != 0 ) {
273
+ bool one_path = path.size () == 1 ;
274
+ const char * first_path = Rf_translateCharUTF8 (path[0 ]);
275
+ int first_index = index[0 ];
276
+ bool one_size = size.size () == 1 ;
277
+ double first_size = size[0 ];
278
+ bool one_res = res.size () == 1 ;
279
+ double first_res = res[0 ];
280
+ bool one_bear = include_bearing.size () == 1 ;
281
+ int first_bear = include_bearing[0 ];
282
+
283
+
284
+ int error = 1 ;
285
+ double width = 0 ;
286
+
287
+ for (int i = 0 ; i < n_strings; ++i) {
288
+ error = string_width (
289
+ Rf_translateCharUTF8 (string[i]),
290
+ one_path ? first_path : Rf_translateCharUTF8 (path[i]),
291
+ one_path ? first_index : index[i],
292
+ one_size ? first_size : size[i],
293
+ one_res ? first_res : res[i],
294
+ one_bear ? first_bear : static_cast <int >(include_bearing[0 ]),
295
+ &width
296
+ );
297
+ if (error) {
298
+ cpp11::stop (" Failed to calculate width of string (%s) with font file (%s) with freetype error %i" , Rf_translateCharUTF8 (string[i]), Rf_translateCharUTF8 (path[i]), error);
299
+ }
300
+ widths.push_back (width);
270
301
}
271
- widths.push_back (width);
272
302
}
273
303
274
304
return widths;
0 commit comments