11
11
San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
14
/* $Id: gdevpdtt.c 8022 2007-06-05 22:23:38Z giles $ */
14
/* $Id: gdevpdtt.c 8360 2007-11-13 10:01:55Z ken $ */
15
15
/* Text processing for pdfwrite. */
17
17
#include "string_.h"
53
54
static gs_glyph standard_glyph_code_for_notdef = GS_NO_GLYPH;
55
56
/* Define the auxiliary procedures for text processing. */
57
58
pdf_text_resync(gs_text_enum_t *pte, const gs_text_enum_t *pfrom)
59
60
pdf_text_enum_t *const penum = (pdf_text_enum_t *)pte;
88
89
return gs_text_current_width(penum->pte_default, pwidth);
89
90
return_error(gs_error_rangecheck); /* can't happen */
92
93
pdf_text_set_cache(gs_text_enum_t *pte, const double *pw,
93
94
gs_text_cache_control_t control)
225
226
return gs_text_retry(penum->pte_default);
226
227
return_error(gs_error_rangecheck); /* can't happen */
229
230
pdf_text_release(gs_text_enum_t *pte, client_name_t cname)
231
232
pdf_text_enum_t *const penum = (pdf_text_enum_t *)pte;
249
250
/* Begin processing text. */
250
private text_enum_proc_process(pdf_text_process);
251
private const gs_text_enum_procs_t pdf_text_procs = {
251
static text_enum_proc_process(pdf_text_process);
252
static const gs_text_enum_procs_t pdf_text_procs = {
252
253
pdf_text_resync, pdf_text_process,
253
254
pdf_text_is_width_only, pdf_text_current_width,
254
255
pdf_text_set_cache, pdf_text_retry,
259
260
pdf_prepare_text_drawing(gx_device_pdf *const pdev, gs_text_enum_t *pte)
261
262
gs_imager_state * pis = pte->pis;
336
337
pdf_current_page(pdev)->text_rotation.counts[i] += text->size;
340
pdev->last_charpath_op = 0;
341
if ((text->operation & TEXT_DO_ANY_CHARPATH) && !path0->first_subpath) {
342
if(pdf_compare_text_state_for_charpath(pdev->text->text_state, pdev, pis, font, text))
343
pdev->last_charpath_op = text->operation & TEXT_DO_ANY_CHARPATH;
339
346
if (font->FontType == ft_user_defined &&
340
347
(text->operation & TEXT_DO_NONE) && (text->operation & TEXT_RETURN_WIDTH)) {
341
348
/* This is stringwidth, see gx_default_text_begin.
762
757
* Check font resource for encoding compatibility.
765
760
pdf_is_compatible_encoding(gx_device_pdf *pdev, pdf_font_resource_t *pdfont,
766
761
gs_font *font, const pdf_char_glyph_pair_t *pairs, int num_chars)
818
813
* Check whethet the font resource has glyphs.
821
816
pdf_font_has_glyphs(gx_device_pdf *pdev, pdf_font_resource_t *pdfont,
822
817
gs_font *font, const pdf_char_glyph_pair_t *pairs, int num_chars)
848
843
* Find a font resource compatible with a given font.
851
846
pdf_find_font_resource(gx_device_pdf *pdev, gs_font *font,
852
847
pdf_resource_type_t type,
853
848
pdf_font_resource_t **ppdfont,
901
896
* Find a type0 font resource for a gived descendent name and CMap name.
904
899
pdf_find_type0_font_resource(gx_device_pdf *pdev, const pdf_font_resource_t *pdsubf,
905
const gs_const_string *CMapName, pdf_font_resource_t **ppdfont)
900
const gs_const_string *CMapName, uint font_index, pdf_font_resource_t **ppdfont)
907
902
pdf_resource_t **pchain = pdev->resources[resourceFont].chains;
908
903
pdf_resource_t *pres;
917
912
if (pdfont->u.type0.DescendantFont != pdsubf)
914
if (pdfont->u.type0.font_index != font_index)
919
916
if (pdfont->BaseFont.size != pdsubf->BaseFont.size + CMapName->size + 1)
921
918
if (memcmp(pdfont->BaseFont.data + pdsubf->BaseFont.size + 1,
932
private int pdf_make_font_resource(gx_device_pdf *pdev, gs_font *font,
929
static int pdf_make_font_resource(gx_device_pdf *pdev, gs_font *font,
933
930
pdf_font_resource_t **ppdfont,
934
931
pdf_char_glyph_pairs_t *cgp);
1032
1029
bfont->nearest_encoding_index, true);
1033
1030
pdfont->u.simple.s.type3.char_procs = NULL;
1034
1031
pdfont->u.simple.s.type3.cached = cached;
1035
pdfont->u.simple.s.type3.FontBBox.p.x = (int)floor(bfont->FontBBox.p.x);
1036
pdfont->u.simple.s.type3.FontBBox.p.y = (int)floor(bfont->FontBBox.p.y);
1037
pdfont->u.simple.s.type3.FontBBox.q.x = (int)ceil(bfont->FontBBox.q.x);
1038
pdfont->u.simple.s.type3.FontBBox.q.y = (int)ceil(bfont->FontBBox.q.y);
1032
pdfont->u.simple.s.type3.FontBBox.p.x = bfont->FontBBox.p.x;
1033
pdfont->u.simple.s.type3.FontBBox.p.y = bfont->FontBBox.p.y;
1034
pdfont->u.simple.s.type3.FontBBox.q.x = bfont->FontBBox.q.x;
1035
pdfont->u.simple.s.type3.FontBBox.q.y = bfont->FontBBox.q.y;
1039
1036
pdfont->u.simple.s.type3.FontMatrix = bfont->FontMatrix;
1040
1037
pdfont->u.simple.s.type3.Resources = cos_dict_alloc(pdev, "pdf_make_font3_resource");
1041
1038
if (pdfont->u.simple.s.type3.Resources == NULL)
1060
1057
* This procedure is only intended to be called
1061
1058
* from a few places in the text code.
1064
1061
pdf_make_font_resource(gx_device_pdf *pdev, gs_font *font,
1065
1062
pdf_font_resource_t **ppdfont,
1066
1063
pdf_char_glyph_pairs_t *cgp)
1234
/* Get a synthesized Type 3 font scale. */
1236
pdf_font3_scale(gx_device_pdf *pdev, gs_font *font, double *scale)
1238
pdf_font_resource_t *pdfont;
1240
pdf_attached_font_resource(pdev, font, &pdfont, NULL, NULL, NULL, NULL);
1241
*scale = pdfont->u.simple.s.type3.FontMatrix.xx;
1245
1232
* Check for simple font.
1267
1254
* Enumerate glyphs for a text.
1270
1257
pdf_next_char_glyph(gs_text_enum_t *penum, const gs_string *pstr,
1271
1258
/* const */ gs_font *font, bool font_is_simple,
1272
1259
gs_char *char_code, gs_char *cid, gs_glyph *glyph)
1294
1281
store_glyphs(pdf_char_glyph_pairs_t *cgp,
1295
1282
byte *glyph_usage, int char_cache_size,
1296
1283
gs_char char_code, gs_char cid, gs_glyph glyph)
1368
1355
if (standard_glyph_code_for_notdef == GS_NO_GLYPH)
1369
1356
standard_glyph_code_for_notdef =
1370
1357
gs_c_name_glyph((const byte *)".notdef", 7) - gs_c_min_std_encoding_glyph;
1371
for (ch = 0; ch < 256; ch++) {
1358
for (ch = *last_reserved_char + 1; ch < 256; ch++) {
1372
1359
pdf_encoding_element_t *pet = &pdfont->u.simple.Encoding[ch];
1374
1361
if (pet->glyph == GS_NO_GLYPH && enc[ch] == standard_glyph_code_for_notdef) {
1362
*last_reserved_char = ch;
1400
1388
/* Allocate storage for the glyph set of the text. */
1402
1390
pdf_alloc_text_glyphs_table(gx_device_pdf *pdev, pdf_text_enum_t *penum, const gs_string *pstr)
1404
1392
const int go = (pstr != NULL ? pstr->size : penum->text.size);
1418
1406
/* Build the glyph set of the text. */
1420
1408
pdf_make_text_glyphs_table(pdf_text_enum_t *penum, const gs_string *pstr,
1421
1409
byte *glyph_usage, int char_cache_size)
1460
1448
/* Build the glyph set of the glyphshow text, and re_encode the text. */
1462
1450
pdf_make_text_glyphs_table_unencoded(gx_device_pdf *pdev, pdf_char_glyph_pairs_t *cgp,
1463
1451
gs_font *font, const gs_string *pstr, const gs_glyph *gdata,
1464
1452
int *ps_encoding_index)
1515
1504
/* Try to add glyphs to the current font resource. . */
1516
1505
cgp->num_unused_chars = 0;
1517
1506
cgp->num_all_chars = 0;
1509
last_reserved_char = pdfont->u.simple.last_reserved_char;
1518
1511
for (i = 0; i < pstr->size; i++) {
1519
1513
if (pdfont == NULL)
1520
1514
ch = 256; /* Force new encoding. */
1522
ch = pdf_reserve_char_code_in_pdfont(pdfont, cgp, gdata[i], &pdfont->u.simple.last_reserved_char);
1516
ch = pdf_reserve_char_code_in_pdfont(pdfont, cgp, gdata[i], &last_reserved_char);
1523
1517
if (ch > 255) {
1519
last_reserved_char = pdfont->u.simple.last_reserved_char;
1524
1520
/* Start a new font/encoding. */
1525
int last_reserved_char = -1;
1521
last_reserved_char = -1;
1527
1523
cgp->num_unused_chars = 0;
1528
1524
cgp->num_all_chars = 0;
1535
1531
return_error(gs_error_unregistered);
1539
pdfont->u.simple.last_reserved_char = last_reserved_char;
1537
pdfont->u.simple.last_reserved_char = last_reserved_char;
1542
1538
/* Change glyphs to char codes in the text : */
1543
1539
for (i = 0; i < pstr->size; i++) {
1544
1540
/* A trick : pdf_reserve_char_code_in_pdfont here simply encodes with cgp. */
1591
1587
/* Get/make font resource for the font with a known encoding. */
1593
1589
pdf_obtain_font_resource_encoded(gx_device_pdf *pdev, gs_font *font,
1594
1590
pdf_font_resource_t **ppdfont, pdf_char_glyph_pairs_t *cgp)
1669
1665
/* Mark glyphs used in the text with the font resource. */
1671
1667
pdf_mark_text_glyphs(const gs_text_enum_t *penum, const gs_string *pstr,
1672
1668
byte *glyph_usage, int char_cache_size)
1706
1702
/* Mark glyphs used in the glyphshow text with the font resource. */
1708
1704
pdf_mark_text_glyphs_unencoded(const gs_text_enum_t *penum, const gs_string *pstr,
1709
1705
byte *glyph_usage, int char_cache_size)
1807
1803
pstr, glyph_usage, char_cache_size);
1811
1807
strings_equal(const gs_const_string *s1, const gs_const_string *s2)
1813
1809
return s1->size == s2->size &&
1821
1817
pdf_obtain_parent_type0_font_resource(gx_device_pdf *pdev, pdf_font_resource_t *pdsubf,
1822
const gs_const_string *CMapName, pdf_font_resource_t **pdfont)
1818
uint font_index, const gs_const_string *CMapName, pdf_font_resource_t **pdfont)
1824
if (pdsubf->u.cidfont.parent != 0 &&
1820
if (pdsubf->u.cidfont.parent != 0 &&
1821
font_index == pdsubf->u.cidfont.parent->u.type0.font_index &&
1825
1822
strings_equal(CMapName, &pdsubf->u.cidfont.parent->u.type0.CMapName))
1826
1823
*pdfont = pdsubf->u.cidfont.parent;
1838
1835
if (pdsubf->u.cidfont.parent == NULL ||
1839
pdf_find_type0_font_resource(pdev, pdsubf, CMapName, pdfont) <= 0) {
1836
pdf_find_type0_font_resource(pdev, pdsubf, CMapName, font_index, pdfont) <= 0) {
1840
1837
int code = pdf_font_type0_alloc(pdev, pdfont, gs_no_id, pdsubf, CMapName);
1841
(*pdfont)->u.type0.font_index = font_index;
1845
1843
pdsubf->u.cidfont.parent = *pdfont;
1880
1878
* TEXT_ADD_TO_SPACE_WIDTH. Note that this procedure fills in all the
1881
1879
* values in ppts->values, not just the ones that need to be set now.
1884
1882
transform_delta_inverse(const gs_point *pdelta, const gs_matrix *pmat,
1905
pdf_update_text_state(pdf_text_process_state_t *ppts,
1906
const pdf_text_enum_t *penum,
1907
pdf_font_resource_t *pdfont, const gs_matrix *pfmat)
1903
float pdf_calculate_text_size(gs_imager_state *pis, pdf_font_resource_t *pdfont,
1904
const gs_matrix *pfmat, gs_matrix *smat, gs_matrix *tmat,
1905
gs_font *font, gx_device_pdf *pdev)
1909
gx_device_pdf *const pdev = (gx_device_pdf *)penum->dev;
1910
gs_font *font = penum->current_font;
1912
gs_matrix orig_matrix, smat, tmat;
1907
gs_matrix orig_matrix;
1914
1909
sx = pdev->HWResolution[0] / 72.0,
1915
1910
sy = pdev->HWResolution[1] / 72.0;
1917
float c_s = 0, w_s = 0;
1919
int code = gx_path_current_point(penum->path, &cpt);
1924
1914
/* Get the original matrix of the base font. */
1947
1937
/* Compute the scaling matrix and combined matrix. */
1949
gs_matrix_invert(&orig_matrix, &smat);
1950
gs_matrix_multiply(&smat, pfmat, &smat);
1951
tmat = ctm_only(penum->pis);
1952
tmat.tx = tmat.ty = 0;
1953
gs_matrix_multiply(&smat, &tmat, &tmat);
1939
gs_matrix_invert(&orig_matrix, smat);
1940
gs_matrix_multiply(smat, pfmat, smat);
1941
*tmat = ctm_only(pis);
1942
tmat->tx = tmat->ty = 0;
1943
gs_matrix_multiply(smat, tmat, tmat);
1955
1945
/* Try to find a reasonable size value. This isn't necessary, */
1956
1946
/* but it's worth a little effort. */
1958
size = hypot(tmat.yx, tmat.yy) / sy;
1948
size = hypot(tmat->yx, tmat->yy) / sy;
1959
1949
if (size < 0.01)
1960
size = hypot(tmat.xx, tmat.xy) / sx;
1950
size = hypot(tmat->xx, tmat->xy) / sx;
1961
1951
if (size < 0.01)
1958
pdf_update_text_state(pdf_text_process_state_t *ppts,
1959
const pdf_text_enum_t *penum,
1960
pdf_font_resource_t *pdfont, const gs_matrix *pfmat)
1962
gx_device_pdf *const pdev = (gx_device_pdf *)penum->dev;
1963
gs_font *font = penum->current_font;
1965
gs_matrix smat, tmat;
1967
float c_s = 0, w_s = 0;
1969
int code = gx_path_current_point(penum->path, &cpt);
1975
size = pdf_calculate_text_size(penum->pis, pdfont, pfmat, &smat, &tmat, penum->current_font, pdev);
1964
1976
/* Check for spacing parameters we can handle, and transform them. */
1966
1978
if (penum->text.operation & TEXT_ADD_TO_ALL_WIDTHS) {
2068
2080
return pdf_set_text_state_values(pdev, &ppts->values);
2072
store_glyph_width(pdf_glyph_width_t *pwidth, int wmode, double scale,
2084
store_glyph_width(pdf_glyph_width_t *pwidth, int wmode, const gs_matrix *scale,
2073
2085
const gs_glyph_info_t *pinfo)
2077
pwidth->xy.x = pinfo->width[wmode].x * scale;
2078
pwidth->xy.y = pinfo->width[wmode].y * scale;
2089
gs_distance_transform(pinfo->width[wmode].x, pinfo->width[wmode].y, scale, &pwidth->xy);
2080
2091
w = pwidth->xy.y, v = pwidth->xy.x;
2086
pwidth->v.x = pinfo->v.x * scale;
2087
pwidth->v.y = pinfo->v.y * scale;
2097
gs_distance_transform(pinfo->v.x, pinfo->v.y, scale, &pwidth->v);
2092
get_missing_width(gs_font_base *cfont, int wmode, double scale_c,
2102
get_missing_width(gs_font_base *cfont, int wmode, const gs_matrix *scale_c,
2093
2103
pdf_glyph_widths_t *pwidths)
2095
2105
gs_font_info_t finfo;
2103
pwidths->Width.xy.x = pwidths->real_width.xy.x = 0;
2104
pwidths->Width.xy.y = pwidths->real_width.xy.y =
2105
- finfo.MissingWidth * scale_c;
2113
gs_distance_transform(0.0, -finfo.MissingWidth, scale_c, &pwidths->real_width.xy);
2114
pwidths->Width.xy.x = 0;
2115
pwidths->Width.xy.y = pwidths->real_width.xy.y;
2106
2116
pwidths->Width.w = pwidths->real_width.w =
2107
2117
pwidths->Width.xy.y;
2108
2118
pwidths->Width.v.x = - pwidths->Width.xy.y / 2;
2109
2119
pwidths->Width.v.y = - pwidths->Width.xy.y;
2111
pwidths->Width.xy.x = pwidths->real_width.xy.x =
2112
finfo.MissingWidth * scale_c;
2121
gs_distance_transform(finfo.MissingWidth, 0.0, scale_c, &pwidths->real_width.xy);
2122
pwidths->Width.xy.x = pwidths->real_width.xy.x;
2123
pwidths->Width.xy.y = 0;
2113
2124
pwidths->Width.w = pwidths->real_width.w =
2114
2125
pwidths->Width.xy.x;
2115
pwidths->Width.xy.y = pwidths->real_width.xy.y = 0;
2116
2126
pwidths->Width.v.x = pwidths->Width.v.y = 0;
2138
2148
gs_font_base *cfont = pdf_font_resource_font(pdfont, false);
2139
2149
gs_font *ofont = orig_font;
2140
2150
gs_glyph_info_t info;
2142
* orig_scale is 1.0 for TrueType, 0.001 or 1.0/2048 for Type 1.
2145
double scale_c, scale_o;
2151
gs_matrix scale_c, scale_o;
2146
2152
int code, rcode = 0;
2148
2154
int allow_cdevproc_callout = (orig_font->FontType == ft_CID_TrueType
2152
2158
if (ofont->FontType == ft_composite)
2153
2159
return_error(gs_error_unregistered); /* Must not happen. */
2154
code = font_orig_scale((const gs_font *)cfont, &sxc);
2157
code = font_orig_scale(ofont, &sxo);
2160
scale_c = sxc * 1000.0;
2161
scale_o = sxo * 1000.0;
2160
code = pdf_font_orig_matrix((const gs_font *)cfont, &scale_c);
2163
code = pdf_font_orig_matrix(ofont, &scale_o);
2166
gs_matrix_scale(&scale_c, 1000.0, 1000.0, &scale_c);
2167
gs_matrix_scale(&scale_o, 1000.0, 1000.0, &scale_o);
2162
2168
pwidths->Width.v.x = pwidths->Width.v.y = 0;
2163
2169
pwidths->real_width.v.x = pwidths->real_width.v.y = 0;
2164
2170
pwidths->replaced_v = false;
2165
2171
if (glyph == GS_NO_GLYPH)
2166
return get_missing_width(cfont, wmode, scale_c, pwidths);
2172
return get_missing_width(cfont, wmode, &scale_c, pwidths);
2167
2173
code = cfont->procs.glyph_info((gs_font *)cfont, glyph, NULL,
2168
2174
GLYPH_INFO_WIDTH0 |
2169
2175
(GLYPH_INFO_WIDTH0 << wmode) |
2175
2181
So make a compatibe data here.
2177
2183
if (code == gs_error_undefined || !(info.members & (GLYPH_INFO_WIDTH0 << wmode))) {
2178
code = get_missing_width(cfont, wmode, scale_c, pwidths);
2184
code = get_missing_width(cfont, wmode, &scale_c, pwidths);
2183
2189
if (wmode && pdf_is_CID_font(ofont)) {
2184
2190
pdf_glyph_widths_t widths1;
2186
if (get_missing_width(cfont, 0, scale_c, &widths1) < 0)
2192
if (get_missing_width(cfont, 0, &scale_c, &widths1) < 0)
2189
2195
v.x = widths1.Width.w / 2;
2192
2198
} else if (code < 0)
2195
code = store_glyph_width(&pwidths->Width, wmode, scale_c, &info);
2201
code = store_glyph_width(&pwidths->Width, wmode, &scale_c, &info);
2199
if (info.members & (GLYPH_INFO_VVECTOR0 << wmode)) {
2200
v.y = info.v.y * scale_c;
2205
if (info.members & (GLYPH_INFO_VVECTOR0 << wmode))
2206
gs_distance_transform(info.v.x, info.v.y, &scale_c, &v);
2203
2209
if (wmode && pdf_is_CID_font(ofont)) {
2204
2210
if (info.members & (GLYPH_INFO_WIDTH0 << wmode)) {
2205
v.x = info.width[0].x * scale_c / 2;
2213
gs_distance_transform(info.width[0].x, info.width[0].y, &scale_c, &xy);
2207
2216
pdf_glyph_widths_t widths1;
2209
if (get_missing_width(cfont, 0, scale_c, &widths1) < 0)
2218
if (get_missing_width(cfont, 0, &scale_c, &widths1) < 0)
2212
2221
v.x = widths1.Width.w / 2;
2215
if (info.members & (GLYPH_INFO_VVECTOR0 << wmode)) {
2216
v.x = info.v.x * scale_c;
2221
2225
pwidths->Width.v = v;
2259
2263
pwidths->replaced_v = true;
2261
2265
info.v.x = info.v.y = 0;
2262
code = store_glyph_width(&pwidths->real_width, wmode, scale_o, &info);
2266
code = store_glyph_width(&pwidths->real_width, wmode, &scale_o, &info);
2266
pwidths->real_width.v.x = info.v.x * scale_o;
2267
pwidths->real_width.v.y = info.v.y * scale_o;
2270
gs_distance_transform(info.v.x, info.v.y, &scale_o, &pwidths->real_width.v);
2273
2276
pdf_choose_output_char_code(gx_device_pdf *pdev, pdf_text_enum_t *penum, gs_char *pch)
2382
2385
gs_glyph glyphs[BUF_SIZE / sizeof(gs_glyph)];
2385
if (!penum->pte_default && !penum->charproc_accum) {
2388
if (!penum->pte_default && !penum->charproc_accum) {
2386
2389
/* Don't need to sync before exiting charproc. */
2387
2390
code = pdf_prepare_text_drawing(pdev, pte);
2388
2391
if (code == gs_error_rangecheck) {
2414
2417
code = pdf_choose_output_glyph_hame(pdev, penum, &gnstr, pte_default->returned.current_glyph);
2421
if ((penum->current_font->FontType == ft_user_defined) && stell(pdev->strm) == 0)
2423
char glyph[256], FontName[gs_font_name_max + 1], KeyName[256];
2426
len = min(gs_font_name_max, gnstr.size);
2427
memcpy(glyph, gnstr.data, len);
2429
len = min(255, penum->current_font->font_name.size);
2430
memcpy(FontName, penum->current_font->font_name.chars, len);
2431
FontName[len] = 0x00;
2432
len = min(255, penum->current_font->key_name.size);
2433
memcpy(KeyName, penum->current_font->key_name.chars, len);
2434
KeyName[len] = 0x00;
2436
eprintf4("ERROR: Page %d used undefined glyph '%s' from type 3 font '%s', key '%s'\n",
2437
pdev->next_page, glyph, FontName, KeyName);
2438
stream_puts(pdev->strm, "0 0 0 0 0 0 d1\n");
2417
2441
code = pdf_end_charproc_accum(pdev, penum->current_font, penum->cgp,
2418
2442
pte_default->returned.current_glyph, penum->output_char_code, &gnstr);
2557
/* Now that we are using the working buffer for text in composite fonts, we must make sure
2558
* it is large enough. Each input character code may be promoted to a gs_glyph, in scan_cmap_text
2559
* when processing a Type 0 font with a type 1 descendant font. This routine uses
2560
* pdf_make_text_glyphs_table_unencoded (called from pdf_obtain_font_resource_unencoded) which
2561
* also may require an identically sized buffer, so we need:
2562
* num__input_characters * sizeof(gs_glyph) * 2.
2564
if (pte->orig_font->FontType == ft_composite) {
2565
if (size < (pte->text.size - pte->index) * sizeof(gs_glyph) * 2)
2566
size = (pte->text.size - pte->index) * sizeof(gs_glyph) * 2;
2533
2569
if (size <= sizeof(buf)) {
2534
2570
code = process(pte, buf.bytes, size);