4 * Copyright (C) 2011-2012 by Werner Lemberg.
6 * This file is part of the ttfautohint library, and may only be used,
7 * modified, and distributed under the terms given in `COPYING'. By
8 * continuing to use, modify, or distribute this file you indicate that you
9 * have read `COPYING' and understand and accept it fully.
11 * The file `COPYING' mentioned in the previous paragraph is distributed
12 * with the ttfautohint library.
20 TA_sfnt_build_glyf_hints(SFNT
* sfnt
,
23 FT_Face face
= sfnt
->face
;
28 /* this loop doesn't include the artificial `.ttfautohint' glyph */
29 for (idx
= 0; idx
< face
->num_glyphs
; idx
++)
31 error
= TA_sfnt_build_glyph_instructions(sfnt
, font
, idx
);
35 font
->progress(idx
, face
->num_glyphs
,
36 sfnt
- font
->sfnts
, font
->num_sfnts
,
45 TA_glyph_get_components(GLYPH
* glyph
,
51 FT_UShort
* components_new
;
63 /* walk over component records */
67 return FT_Err_Invalid_Table
;
72 /* add component to list */
73 component
= *(p
++) << 8;
76 glyph
->num_components
++;
77 components_new
= (FT_UShort
*)realloc(glyph
->components
,
79 * sizeof (FT_UShort
));
82 glyph
->num_components
--;
83 return FT_Err_Out_Of_Memory
;
86 glyph
->components
= components_new
;
88 glyph
->components
[glyph
->num_components
- 1] = component
;
90 /* skip scaling and offset arguments */
91 if (flags
& ARGS_ARE_WORDS
)
96 if (flags
& WE_HAVE_A_SCALE
)
98 else if (flags
& WE_HAVE_AN_XY_SCALE
)
100 else if (flags
& WE_HAVE_A_2X2
)
102 } while (flags
& MORE_COMPONENTS
);
109 TA_glyph_parse_composite(GLYPH
* glyph
,
112 FT_UShort num_glyphs
)
114 FT_ULong flags_offset
; /* after the loop, this is the offset */
115 /* to the last element in the flags array */
122 /* we allocate too large a buffer */
123 /* (including space for the new component */
124 /* and possible argument size changes for shifted point indices) */
125 /* and reallocate it later to its real size */
126 glyph
->buf
= (FT_Byte
*)malloc(len
+ 8 + glyph
->num_components
* 2);
128 return FT_Err_Out_Of_Memory
;
138 /* if the composite glyph contains one or more contours, */
139 /* we prepend a composite glyph component to call some bytecode */
140 /* which eventually becomes the last glyph in the `glyf' table; */
141 /* for convenience, however, it is not added to the `components' array */
142 /* (doing so simplifies the conversion of point indices later on) */
143 if (glyph
->num_composite_contours
)
153 /* the composite glyph's bounding box */
154 x_min
= (FT_Short
)((buf
[2] << 8) + buf
[3]);
155 y_min
= (FT_Short
)((buf
[4] << 8) + buf
[5]);
156 x_max
= (FT_Short
)((buf
[6] << 8) + buf
[7]);
157 y_max
= (FT_Short
)((buf
[8] << 8) + buf
[9]);
159 /* use ARGS_ARE_WORDS only if necessary; */
160 /* note that the offset value of the component doesn't matter */
161 /* as long as it stays within the bounding box */
162 if (x_min
<= 0 && x_max
>= 0)
169 if (y_min
<= 0 && y_max
>= 0)
176 if (x_offset
>= -128 && x_offset
<= 127
177 && y_offset
>= -128 && y_offset
<= 127)
180 *(q
++) = ARGS_ARE_XY_VALUES
| MORE_COMPONENTS
;
181 *(q
++) = HIGH(num_glyphs
- 1);
182 *(q
++) = LOW(num_glyphs
- 1);
189 *(q
++) = ARGS_ARE_WORDS
| ARGS_ARE_XY_VALUES
| MORE_COMPONENTS
;
190 *(q
++) = HIGH(num_glyphs
- 1);
191 *(q
++) = LOW(num_glyphs
- 1);
192 *(q
++) = HIGH(x_offset
);
193 *(q
++) = LOW(x_offset
);
194 *(q
++) = HIGH(y_offset
);
195 *(q
++) = LOW(y_offset
);
199 /* walk over component records */
202 flags_offset
= q
- glyph
->buf
;
213 if (flags
& ARGS_ARE_XY_VALUES
)
219 if (flags
& ARGS_ARE_WORDS
)
227 /* handle point numbers */
233 if (flags
& ARGS_ARE_WORDS
)
246 /* adjust point numbers */
247 /* (see `TA_adjust_point_index' in `tabytecode.c' for more) */
248 for (i
= 0; i
< glyph
->num_pointsums
; i
++)
249 if (arg1
< glyph
->pointsums
[i
])
253 for (i
= 0; i
< glyph
->num_pointsums
; i
++)
254 if (arg2
< glyph
->pointsums
[i
])
258 if (arg1
<= 0xFF && arg2
<= 0xFF)
260 glyph
->buf
[flags_offset
+ 1] &= ~ARGS_ARE_WORDS
;
267 glyph
->buf
[flags_offset
+ 1] |= ARGS_ARE_WORDS
;
276 /* copy scaling arguments */
277 if (flags
& (WE_HAVE_A_SCALE
| WE_HAVE_AN_XY_SCALE
| WE_HAVE_A_2X2
))
282 if (flags
& (WE_HAVE_AN_XY_SCALE
| WE_HAVE_A_2X2
))
287 if (flags
& WE_HAVE_A_2X2
)
294 } while (flags
& MORE_COMPONENTS
);
296 glyph
->len1
= q
- glyph
->buf
;
297 /* glyph->len2 = 0; */
298 glyph
->flags_offset
= flags_offset
;
299 glyph
->buf
= (FT_Byte
*)realloc(glyph
->buf
, glyph
->len1
);
301 /* we discard instructions (if any) */
302 glyph
->buf
[glyph
->flags_offset
] &= ~(WE_HAVE_INSTR
>> 8);
309 TA_glyph_parse_simple(GLYPH
* glyph
,
314 FT_Byte
* flags_start
;
318 FT_ULong flags_size
; /* size of the flags array */
319 FT_ULong xy_size
; /* size of x and y coordinate arrays together */
330 ins_offset
= 10 + glyph
->num_contours
* 2;
335 return FT_Err_Invalid_Table
;
337 /* get number of instructions */
338 num_ins
= *(p
++) << 8;
344 return FT_Err_Invalid_Table
;
350 while (i
< glyph
->num_points
)
361 return FT_Err_Invalid_Table
;
365 x_short
= (flags
& X_SHORT_VECTOR
) ? 1 : 2;
366 y_short
= (flags
& Y_SHORT_VECTOR
) ? 1 : 2;
368 have_x
= ((flags
& SAME_X
) && !(flags
& X_SHORT_VECTOR
)) ? 0 : 1;
369 have_y
= ((flags
& SAME_Y
) && !(flags
& Y_SHORT_VECTOR
)) ? 0 : 1;
376 return FT_Err_Invalid_Table
;
380 if (i
+ count
> glyph
->num_points
)
381 return FT_Err_Invalid_Table
;
384 xy_size
+= count
* x_short
* have_x
;
385 xy_size
+= count
* y_short
* have_y
;
390 if (p
+ xy_size
> endp
)
391 return FT_Err_Invalid_Table
;
393 flags_size
= p
- flags_start
;
395 /* store the data before and after the bytecode instructions */
396 /* in the same array */
397 glyph
->len1
= ins_offset
;
398 glyph
->len2
= flags_size
+ xy_size
;
399 glyph
->buf
= (FT_Byte
*)malloc(glyph
->len1
+ glyph
->len2
);
401 return FT_Err_Out_Of_Memory
;
403 /* now copy everything but the instructions */
404 memcpy(glyph
->buf
, buf
, glyph
->len1
);
405 memcpy(glyph
->buf
+ glyph
->len1
, flags_start
, glyph
->len2
);
412 TA_iterate_composite_glyph(glyf_Data
* data
,
413 FT_UShort
* components
,
414 FT_UShort num_components
,
415 FT_UShort
** pointsums
,
416 FT_UShort
* num_pointsums
,
417 FT_UShort
* num_composite_contours
,
418 FT_UShort
* num_composite_points
)
420 FT_UShort
* pointsums_new
;
424 /* save current state */
426 if (*num_pointsums
== 0xFFFF)
427 return FT_Err_Invalid_Table
;
430 pointsums_new
= (FT_UShort
*)realloc(*pointsums
,
432 * sizeof (FT_UShort
));
436 return FT_Err_Out_Of_Memory
;
439 *pointsums
= pointsums_new
;
441 (*pointsums
)[*num_pointsums
- 1] = *num_composite_points
;
443 for (i
= 0; i
< num_components
; i
++)
446 FT_UShort component
= components
[i
];
450 if (component
>= data
->num_glyphs
)
451 return FT_Err_Invalid_Table
;
453 glyph
= &data
->glyphs
[component
];
455 if (glyph
->num_components
)
457 error
= TA_iterate_composite_glyph(data
,
459 glyph
->num_components
,
462 num_composite_contours
,
463 num_composite_points
);
469 /* no need for checking overflow of the number of contours */
470 /* since the number of points is always larger or equal */
471 if (*num_composite_points
> 0xFFFF - glyph
->num_points
)
472 return FT_Err_Invalid_Table
;
474 *num_composite_contours
+= glyph
->num_contours
;
475 *num_composite_points
+= glyph
->num_points
;
484 TA_sfnt_compute_composite_pointsums(SFNT
* sfnt
,
487 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
488 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
493 for (i
= 0; i
< data
->num_glyphs
; i
++)
495 GLYPH
* glyph
= &data
->glyphs
[i
];
498 if (glyph
->num_components
)
501 FT_UShort num_composite_contours
= 0;
502 FT_UShort num_composite_points
= 0;
505 error
= TA_iterate_composite_glyph(data
,
507 glyph
->num_components
,
509 &glyph
->num_pointsums
,
510 &num_composite_contours
,
511 &num_composite_points
);
515 glyph
->num_composite_contours
= num_composite_contours
;
517 /* update maximum values, */
518 /* including the subglyphs not in `components' array */
519 /* (each of them has a single point in a single contour) */
520 if (num_composite_points
+ glyph
->num_pointsums
521 > sfnt
->max_composite_points
)
522 sfnt
->max_composite_points
= num_composite_points
523 + glyph
->num_pointsums
;
524 if (num_composite_contours
+ glyph
->num_pointsums
525 > sfnt
->max_composite_contours
)
526 sfnt
->max_composite_contours
= num_composite_contours
527 + glyph
->num_pointsums
;
536 TA_sfnt_split_glyf_table(SFNT
* sfnt
,
539 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
540 SFNT_Table
* loca_table
= &font
->tables
[sfnt
->loca_idx
];
541 SFNT_Table
* head_table
= &font
->tables
[sfnt
->head_idx
];
547 FT_ULong offset_next
;
551 FT_UShort loop_count
;
556 /* in case of success, all allocated arrays are */
557 /* linked and eventually freed in `TA_font_unload' */
559 /* nothing to do if table has already been split */
560 if (glyf_table
->data
)
563 data
= (glyf_Data
*)calloc(1, sizeof (glyf_Data
));
565 return FT_Err_Out_Of_Memory
;
567 glyf_table
->data
= data
;
569 loca_format
= head_table
->buf
[LOCA_FORMAT_OFFSET
];
571 data
->num_glyphs
= loca_format
? loca_table
->len
/ 4
572 : loca_table
->len
/ 2;
573 loop_count
= data
->num_glyphs
- 1;
575 /* allocate one more glyph slot if we have composite glyphs */
576 if (!sfnt
->max_components
)
577 data
->num_glyphs
-= 1;
578 data
->glyphs
= (GLYPH
*)calloc(1, data
->num_glyphs
* sizeof (GLYPH
));
580 return FT_Err_Out_Of_Memory
;
582 /* first loop over `loca' and `glyf' data */
588 offset_next
= *(p
++) << 24;
589 offset_next
+= *(p
++) << 16;
590 offset_next
+= *(p
++) << 8;
591 offset_next
+= *(p
++);
595 offset_next
= *(p
++) << 8;
596 offset_next
+= *(p
++);
600 for (i
= 0; i
< loop_count
; i
++)
602 GLYPH
* glyph
= &data
->glyphs
[i
];
606 offset
= offset_next
;
610 offset_next
= *(p
++) << 24;
611 offset_next
+= *(p
++) << 16;
612 offset_next
+= *(p
++) << 8;
613 offset_next
+= *(p
++);
617 offset_next
= *(p
++) << 8;
618 offset_next
+= *(p
++);
622 if (offset_next
< offset
623 || offset_next
> glyf_table
->len
)
624 return FT_Err_Invalid_Table
;
626 len
= offset_next
- offset
;
628 continue; /* empty glyph */
634 /* check header size */
636 return FT_Err_Invalid_Table
;
638 /* we need the number of contours and points for */
639 /* `TA_sfnt_compute_composite_pointsums' */
640 buf
= glyf_table
->buf
+ offset
;
641 glyph
->num_contours
= (FT_Short
)((buf
[0] << 8) + buf
[1]);
643 if (glyph
->num_contours
< 0)
645 error
= TA_glyph_get_components(glyph
, buf
, len
);
654 /* use the last contour's end point to compute number of points */
655 off
= 10 + (glyph
->num_contours
- 1) * 2;
656 glyph
->num_points
= buf
[off
] << 8;
657 glyph
->num_points
+= buf
[off
+ 1] + 1;
662 if (sfnt
->max_components
)
664 error
= TA_sfnt_compute_composite_pointsums(sfnt
, font
);
669 /* second loop over `loca' and `glyf' data */
675 offset_next
= *(p
++) << 24;
676 offset_next
+= *(p
++) << 16;
677 offset_next
+= *(p
++) << 8;
678 offset_next
+= *(p
++);
682 offset_next
= *(p
++) << 8;
683 offset_next
+= *(p
++);
687 for (i
= 0; i
< loop_count
; i
++)
689 GLYPH
* glyph
= &data
->glyphs
[i
];
693 offset
= offset_next
;
697 offset_next
= *(p
++) << 24;
698 offset_next
+= *(p
++) << 16;
699 offset_next
+= *(p
++) << 8;
700 offset_next
+= *(p
++);
704 offset_next
= *(p
++) << 8;
705 offset_next
+= *(p
++);
709 len
= offset_next
- offset
;
711 continue; /* empty glyph */
717 buf
= glyf_table
->buf
+ offset
;
719 /* We must parse the rest of the glyph record to get the exact */
720 /* record length. Since the `loca' table rounds record lengths */
721 /* up to multiples of 4 (or 2 for older fonts), and we must round */
722 /* up again after stripping off the instructions, it would be */
723 /* possible otherwise to have more than 4 bytes of padding which */
724 /* is more or less invalid. */
726 if (glyph
->num_contours
< 0)
727 error
= TA_glyph_parse_composite(glyph
, buf
, len
, data
->num_glyphs
);
729 error
= TA_glyph_parse_simple(glyph
, buf
, len
);
735 if (sfnt
->max_components
)
737 /* construct and append our special glyph used as a composite element */
738 GLYPH
* glyph
= &data
->glyphs
[data
->num_glyphs
- 1];
741 FT_Byte bytecode
[] = {
743 /* increment `cvtl_is_subglyph' counter */
756 glyph
->buf
= (FT_Byte
*)malloc(glyph
->len1
+ glyph
->len2
);
758 return FT_Err_Out_Of_Memory
;
762 buf
[0] = 0x00; /* one contour */
764 buf
[2] = 0x00; /* no dimensions */
772 buf
[10] = 0x00; /* one contour end point */
775 buf
[12] = ON_CURVE
| SAME_X
| SAME_Y
; /* the flags for a point at 0,0 */
777 /* add bytecode also; */
778 /* this works because the loop in `TA_sfnt_build_glyf_hints' */
779 /* doesn't include the newly appended glyph */
780 glyph
->ins_len
= sizeof (bytecode
);
781 glyph
->ins_buf
= (FT_Byte
*)malloc(glyph
->ins_len
);
783 return FT_Err_Out_Of_Memory
;
784 memcpy(glyph
->ins_buf
, bytecode
, glyph
->ins_len
);
786 sfnt
->max_components
+= 1;
794 TA_sfnt_build_glyf_table(SFNT
* sfnt
,
797 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
798 glyf_Data
* data
= (glyf_Data
*)glyf_table
->data
;
808 if (glyf_table
->processed
)
813 glyph
= data
->glyphs
;
814 for (i
= 0; i
< data
->num_glyphs
; i
++, glyph
++)
816 /* glyph records should have offsets which are multiples of 4 */
817 len
= (len
+ 3) & ~3;
818 len
+= glyph
->len1
+ glyph
->len2
+ glyph
->ins_len
;
819 /* add two bytes for the instructionLength field */
820 if (glyph
->len2
|| glyph
->ins_len
)
824 /* to make the short format of the `loca' table always work, */
825 /* assure an even length of the `glyf' table */
826 glyf_table
->len
= (len
+ 1) & ~1;
828 buf_new
= (FT_Byte
*)realloc(glyf_table
->buf
, (len
+ 3) & ~3);
830 return FT_Err_Out_Of_Memory
;
832 glyf_table
->buf
= buf_new
;
835 glyph
= data
->glyphs
;
836 for (i
= 0; i
< data
->num_glyphs
; i
++, glyph
++)
838 len
= glyph
->len1
+ glyph
->len2
+ glyph
->ins_len
;
839 if (glyph
->len2
|| glyph
->ins_len
)
844 /* copy glyph data and insert new instructions */
845 memcpy(p
, glyph
->buf
, glyph
->len1
);
851 *(p
++) = HIGH(glyph
->ins_len
);
852 *(p
++) = LOW(glyph
->ins_len
);
853 memcpy(p
, glyph
->ins_buf
, glyph
->ins_len
);
855 memcpy(p
, glyph
->buf
+ glyph
->len1
, glyph
->len2
);
860 /* composite glyph */
863 *(p
+ glyph
->flags_offset
) |= (WE_HAVE_INSTR
>> 8);
865 *(p
++) = HIGH(glyph
->ins_len
);
866 *(p
++) = LOW(glyph
->ins_len
);
867 memcpy(p
, glyph
->ins_buf
, glyph
->ins_len
);
874 /* pad with zero bytes to have an offset which is a multiple of 4; */
875 /* this works even for the last glyph record since the `glyf' */
876 /* table length is a multiple of 4 also */
891 glyf_table
->checksum
= TA_table_compute_checksum(glyf_table
->buf
,
893 glyf_table
->processed
= 1;
900 TA_create_glyph_data(FT_Outline
* outline
,
903 FT_Error error
= TA_Err_Ok
;
909 FT_Byte
* flags
= NULL
;
923 if (!outline
->n_contours
)
924 return TA_Err_Ok
; /* empty glyph */
926 /* in case of success, all non-local allocated arrays are */
927 /* linked and eventually freed in `TA_font_unload' */
931 /* we use `calloc' since we rely on the array */
932 /* being initialized to zero; */
933 /* additionally, we need one more byte for a test after the loop */
934 flags
= (FT_Byte
*)calloc(1, outline
->n_points
+ 1);
937 error
= FT_Err_Out_Of_Memory
;
941 /* we have either one-byte or two-byte elements */
942 x
= (FT_Byte
*)malloc(2 * outline
->n_points
);
945 error
= FT_Err_Out_Of_Memory
;
949 y
= (FT_Byte
*)malloc(2 * outline
->n_points
);
952 error
= FT_Err_Out_Of_Memory
;
959 xmin
= xmax
= (outline
->points
[0].x
+ 32) >> 6;
960 ymin
= ymax
= (outline
->points
[0].y
+ 32) >> 6;
963 oldf
= 0x80; /* start with an impossible value */
965 /* convert the FreeType representation of the glyph's outline */
966 /* into the representation format of the `glyf' table */
967 for (i
= 0; i
< outline
->n_points
; i
++)
969 FT_Pos xcur
= (outline
->points
[i
].x
+ 32) >> 6;
970 FT_Pos ycur
= (outline
->points
[i
].y
+ 32) >> 6;
972 FT_Pos xdelta
= xcur
- lastx
;
973 FT_Pos ydelta
= ycur
- lasty
;
976 /* we are only interested in bit 0 of the `tags' array */
977 f
= outline
->tags
[i
] & ON_CURVE
;
985 if (xdelta
< 256 && xdelta
> -256)
994 *(xp
++) = (FT_Byte
)xdelta
;
998 *(xp
++) = HIGH(xdelta
);
999 *(xp
++) = LOW(xdelta
);
1009 if (ydelta
< 256 && ydelta
> -256)
1011 f
|= Y_SHORT_VECTOR
;
1018 *(yp
++) = (FT_Byte
)ydelta
;
1022 *(yp
++) = HIGH(ydelta
);
1023 *(yp
++) = LOW(ydelta
);
1029 /* set repeat flag */
1030 *(flagsp
- 1) |= REPEAT
;
1034 /* we can only handle 256 repetitions at once, */
1035 /* so use a new counter */
1040 *flagsp
+= 1; /* increase repetition counter */
1045 flagsp
++; /* skip repetition counter */
1063 /* if the last byte was a repetition counter, */
1064 /* we must increase by one to get the correct array size */
1068 header
[0] = HIGH(outline
->n_contours
);
1069 header
[1] = LOW(outline
->n_contours
);
1070 header
[2] = HIGH(xmin
);
1071 header
[3] = LOW(xmin
);
1072 header
[4] = HIGH(ymin
);
1073 header
[5] = LOW(ymin
);
1074 header
[6] = HIGH(xmax
);
1075 header
[7] = LOW(xmax
);
1076 header
[8] = HIGH(ymax
);
1077 header
[9] = LOW(ymax
);
1079 /* concatenate all arrays and fill needed GLYPH structure elements */
1081 glyph
->len1
= 10 + 2 * outline
->n_contours
;
1082 glyph
->len2
= (flagsp
- flags
) + (xp
- x
) + (yp
- y
);
1084 glyph
->buf
= (FT_Byte
*)malloc(glyph
->len1
+ glyph
->len2
);
1087 error
= FT_Err_Out_Of_Memory
;
1092 memcpy(p
, header
, 10);
1096 glyph
->ins_buf
= NULL
;
1098 for (i
= 0; i
< outline
->n_contours
; i
++)
1100 *(p
++) = HIGH(outline
->contours
[i
]);
1101 *(p
++) = LOW(outline
->contours
[i
]);
1104 memcpy(p
, flags
, flagsp
- flags
);
1105 p
+= flagsp
- flags
;
1106 memcpy(p
, x
, xp
- x
);
1108 memcpy(p
, y
, yp
- y
);
1119 /* We hint each glyph at EM size and construct a new `glyf' table. */
1120 /* Some fonts need this; in particular, */
1121 /* there are CJK fonts which use hints to scale and position subglyphs. */
1122 /* As a consequence, there are no longer composite glyphs. */
1125 TA_sfnt_create_glyf_data(SFNT
* sfnt
,
1128 SFNT_Table
* glyf_table
= &font
->tables
[sfnt
->glyf_idx
];
1129 FT_Face face
= sfnt
->face
;
1137 /* in case of success, all allocated arrays are */
1138 /* linked and eventually freed in `TA_font_unload' */
1140 /* nothing to do if table has already been created */
1141 if (glyf_table
->data
)
1144 data
= (glyf_Data
*)calloc(1, sizeof (glyf_Data
));
1146 return FT_Err_Out_Of_Memory
;
1148 glyf_table
->data
= data
;
1150 data
->num_glyphs
= face
->num_glyphs
;
1151 data
->glyphs
= (GLYPH
*)calloc(1, data
->num_glyphs
* sizeof (GLYPH
));
1153 return FT_Err_Out_Of_Memory
;
1155 /* XXX: Make size configurable */
1156 /* we use the EM size */
1157 /* so that the resulting coordinates can be used without transformation */
1158 error
= FT_Set_Char_Size(face
, face
->units_per_EM
* 64, 0, 72, 0);
1162 /* loop over all glyphs in font face */
1163 for (i
= 0; i
< data
->num_glyphs
; i
++)
1165 GLYPH
* glyph
= &data
->glyphs
[i
];
1168 error
= FT_Load_Glyph(face
, i
, FT_LOAD_NO_BITMAP
| FT_LOAD_NO_AUTOHINT
);
1172 error
= TA_create_glyph_data(&face
->glyph
->outline
, glyph
);
1180 /* end of taglyf.c */