static FT_Byte* TA_sfnt_emit_hints_records(SFNT* sfnt, Hints_Record* hints_records, FT_UInt num_hints_records, FT_Byte* bufp) { FT_UInt i; Hints_Record* hints_record; hints_record = hints_records; for (i = 0; i < num_hints_records - 1; i++) { BCI(MPPEM); if (hints_record->size > 0xFF) { BCI(PUSHW_1); BCI(HIGH((hints_record + 1)->size)); BCI(LOW((hints_record + 1)->size)); } else { BCI(PUSHB_1); BCI((hints_record + 1)->size); } BCI(LT); BCI(IF); bufp = TA_sfnt_emit_hints_record(sfnt, hints_record, bufp); BCI(ELSE); hints_record++; } bufp = TA_sfnt_emit_hints_record(sfnt, hints_record, bufp); for (i = 0; i < num_hints_records - 1; i++) BCI(EIF); BCI(PUSHB_1); BCI(bci_hint_glyph); BCI(CALL); return bufp; }
static FT_Byte* TA_sfnt_build_glyph_segments(SFNT* sfnt, Recorder* recorder, FT_Byte* bufp) { FONT* font = recorder->font; TA_GlyphHints hints = &font->loader->hints; TA_AxisHints axis = &hints->axis[TA_DIMENSION_VERT]; TA_Point points = hints->points; TA_Segment segments = axis->segments; TA_Segment seg; TA_Segment seg_limit; FT_Outline outline = font->loader->gloader->base.outline; FT_UInt* args; FT_UInt* arg; FT_UInt num_args; FT_UInt nargs; FT_UInt num_segments; FT_UInt* wrap_around_segment; FT_UInt num_wrap_around_segments; FT_Bool need_words = 0; FT_Int n; FT_UInt i, j; FT_UInt base; FT_UInt num_packed_segments; FT_UInt num_storage; FT_UInt num_stack_elements; FT_UInt num_twilight_points; seg_limit = segments + axis->num_segments; num_segments = axis->num_segments; /* to pack the data in the bytecode more tightly, */ /* we store up to the first nine segments in nibbles if possible, */ /* using delta values */ base = 0; num_packed_segments = 0; for (seg = segments; seg < seg_limit; seg++) { FT_UInt first = seg->first - points; FT_UInt last = seg->last - points; first = TA_adjust_point_index(recorder, first); last = TA_adjust_point_index(recorder, last); if (first - base >= 16) break; if (first > last || last - first >= 16) break; if (num_packed_segments == 9) break; num_packed_segments++; base = last; } /* some segments can `wrap around' */ /* a contour's start point like 24-25-26-0-1-2 */ /* (there can be at most one such segment per contour); */ /* we thus append additional records to split them into 24-26 and 0-2 */ wrap_around_segment = recorder->wrap_around_segments; /* `num_packed_segments' segments */ /* have already been checked in previous loop */ for (seg = segments + num_packed_segments; seg < seg_limit; seg++) if (seg->first > seg->last) { /* the stored data is used later for edge linking */ *(wrap_around_segment++) = seg - segments; } num_wrap_around_segments = wrap_around_segment - recorder->wrap_around_segments; num_segments += num_wrap_around_segments; /* wrap-around segments are pushed with four arguments; */ /* a segment stored in nibbles needs only one byte instead of two */ num_args = num_packed_segments + 2 * (num_segments - num_packed_segments) + 2 * num_wrap_around_segments + 2; /* collect all arguments temporarily in an array (in reverse order) */ /* so that we can easily split into chunks of 255 args */ /* as needed by NPUSHB and NPUSHW, respectively */ args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt)); if (!args) return NULL; arg = args + num_args - 1; if (num_segments > 0xFF) need_words = 1; /* the number of packed segments is indicated by the function number */ if (recorder->glyph->num_components) *(arg--) = bci_create_segments_composite_0 + num_packed_segments; else *(arg--) = bci_create_segments_0 + num_packed_segments; *(arg--) = num_segments; base = 0; for (seg = segments; seg < segments + num_packed_segments; seg++) { FT_UInt first = seg->first - points; FT_UInt last = seg->last - points; FT_UInt low_nibble; FT_UInt high_nibble; first = TA_adjust_point_index(recorder, first); last = TA_adjust_point_index(recorder, last); low_nibble = first - base; high_nibble = last - first; *(arg--) = 16 * high_nibble + low_nibble; base = last; if (last > 0xFF) need_words = 1; } for (seg = segments + num_packed_segments; seg < seg_limit; seg++) { FT_UInt first = seg->first - points; FT_UInt last = seg->last - points; *(arg--) = TA_adjust_point_index(recorder, first); *(arg--) = TA_adjust_point_index(recorder, last); /* we push the last and first contour point */ /* as a third and fourth argument in wrap-around segments */ if (first > last) { for (n = 0; n < outline.n_contours; n++) { FT_UInt end = (FT_UInt)outline.contours[n]; if (first <= end) { *(arg--) = TA_adjust_point_index(recorder, end); if (end > 0xFF) need_words = 1; if (n == 0) *(arg--) = TA_adjust_point_index(recorder, 0); else *(arg--) = TA_adjust_point_index(recorder, (FT_UInt)outline.contours[n - 1] + 1); break; } } } if (last > 0xFF) need_words = 1; } /* emit the second part of wrap-around segments as separate segments */ /* so that edges can easily link to them */ for (seg = segments; seg < seg_limit; seg++) { FT_UInt first = seg->first - points; FT_UInt last = seg->last - points; if (first > last) { for (n = 0; n < outline.n_contours; n++) { if (first <= (FT_UInt)outline.contours[n]) { if (n == 0) *(arg--) = TA_adjust_point_index(recorder, 0); else *(arg--) = TA_adjust_point_index(recorder, (FT_UInt)outline.contours[n - 1] + 1); break; } } *(arg--) = TA_adjust_point_index(recorder, last); } } /* with most fonts it is very rare */ /* that any of the pushed arguments is larger than 0xFF, */ /* thus we refrain from further optimizing this case */ arg = args; if (need_words) { for (i = 0; i < num_args; i += 255) { nargs = (num_args - i > 255) ? 255 : num_args - i; BCI(NPUSHW); BCI(nargs); for (j = 0; j < nargs; j++) { BCI(HIGH(*arg)); BCI(LOW(*arg)); arg++; } } } else { for (i = 0; i < num_args; i += 255) { nargs = (num_args - i > 255) ? 255 : num_args - i; BCI(NPUSHB); BCI(nargs); for (j = 0; j < nargs; j++) { BCI(*arg); arg++; } } } BCI(CALL); num_storage = sal_segment_offset + num_segments * 2; if (num_storage > sfnt->max_storage) sfnt->max_storage = num_storage; num_twilight_points = num_segments * 2; if (num_twilight_points > sfnt->max_twilight_points) sfnt->max_twilight_points = num_twilight_points; num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_args; if (num_stack_elements > sfnt->max_stack_elements) sfnt->max_stack_elements = num_stack_elements; free(args); return bufp; }
static FT_Byte* TA_sfnt_emit_hints_record(SFNT* sfnt, Hints_Record* hints_record, FT_Byte* bufp) { FT_Byte* p; FT_Byte* endp; FT_Bool need_words = 0; FT_UInt i, j; FT_UInt num_arguments; FT_UInt num_args; FT_UInt num_stack_elements; /* check whether any argument is larger than 0xFF */ endp = hints_record->buf + hints_record->buf_len; for (p = hints_record->buf; p < endp; p += 2) if (*p) need_words = 1; /* with most fonts it is very rare */ /* that any of the pushed arguments is larger than 0xFF, */ /* thus we refrain from further optimizing this case */ num_arguments = hints_record->buf_len / 2; p = endp - 2; if (need_words) { for (i = 0; i < num_arguments; i += 255) { num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i); BCI(NPUSHW); BCI(num_args); for (j = 0; j < num_args; j++) { BCI(*p); BCI(*(p + 1)); p -= 2; } } } else { /* we only need the lower bytes */ p++; for (i = 0; i < num_arguments; i += 255) { num_args = (num_arguments - i > 255) ? 255 : (num_arguments - i); BCI(NPUSHB); BCI(num_args); for (j = 0; j < num_args; j++) { BCI(*p); p -= 2; } } } num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_arguments; if (num_stack_elements > sfnt->max_stack_elements) sfnt->max_stack_elements = num_stack_elements; return bufp; }
static FT_Byte* TA_font_build_subglyph_shifter(FONT* font, FT_Byte* bufp) { FT_Face face = font->loader->face; FT_GlyphSlot glyph = face->glyph; TA_GlyphLoader gloader = font->loader->gloader; TA_SubGlyph subglyphs = gloader->base.subglyphs; TA_SubGlyph subglyph_limit = subglyphs + gloader->base.num_subglyphs; TA_SubGlyph subglyph; FT_Int curr_contour = 0; for (subglyph = subglyphs; subglyph < subglyph_limit; subglyph++) { FT_Error error; FT_UShort flags = subglyph->flags; FT_Pos y_offset = subglyph->arg2; FT_Int num_contours; /* load subglyph to get the number of contours */ error = FT_Load_Glyph(face, subglyph->index, FT_LOAD_NO_SCALE); if (error) return NULL; num_contours = glyph->outline.n_contours; /* nothing to do if there is a point-to-point alignment */ if (!(flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES)) goto End; /* nothing to do if y offset is zero */ if (!y_offset) goto End; /* nothing to do if there are no contours */ if (!num_contours) goto End; /* note that calling `FT_Load_Glyph' without FT_LOAD_NO_RECURSE */ /* ensures that composite subglyphs are represented as simple glyphs */ if (num_contours > 0xFF || curr_contour > 0xFF) { BCI(PUSHW_2); BCI(HIGH(curr_contour)); BCI(LOW(curr_contour)); BCI(HIGH(num_contours)); BCI(LOW(num_contours)); } else { BCI(PUSHB_2); BCI(curr_contour); BCI(num_contours); } /* there are high chances that this value needs PUSHW, */ /* thus we handle it separately */ if (y_offset > 0xFF || y_offset < 0) { BCI(PUSHW_1); BCI(HIGH(y_offset)); BCI(LOW(y_offset)); } else { BCI(PUSHB_1); BCI(y_offset); } BCI(PUSHB_1); BCI(bci_shift_subglyph); BCI(CALL); End: curr_contour += num_contours; } return bufp; }
static FT_Byte* TA_sfnt_build_glyph_scaler(SFNT* sfnt, Recorder* recorder, FT_Byte* bufp) { FT_GlyphSlot glyph = sfnt->face->glyph; FT_Vector* points = glyph->outline.points; FT_Int num_contours = glyph->outline.n_contours; FT_UInt* args; FT_UInt* arg; FT_UInt num_args; FT_UInt nargs; FT_Bool need_words = 0; FT_Int p, q; FT_UInt i, j; FT_Int start, end; FT_UInt num_stack_elements; num_args = 2 * num_contours + 2; /* collect all arguments temporarily in an array (in reverse order) */ /* so that we can easily split into chunks of 255 args */ /* as needed by NPUSHB and NPUSHW, respectively */ args = (FT_UInt*)malloc(num_args * sizeof (FT_UInt)); if (!args) return NULL; arg = args + num_args - 1; if (num_args > 0xFF) need_words = 1; if (recorder->glyph->num_components) *(arg--) = bci_scale_composite_glyph; else *(arg--) = bci_scale_glyph; *(arg--) = num_contours; start = 0; end = 0; for (p = 0; p < num_contours; p++) { FT_Int max = start; FT_Int min = start; end = glyph->outline.contours[p]; for (q = start; q <= end; q++) { if (points[q].y < points[min].y) min = q; if (points[q].y > points[max].y) max = q; } if (min > max) { *(arg--) = TA_adjust_point_index(recorder, max); *(arg--) = TA_adjust_point_index(recorder, min); } else { *(arg--) = TA_adjust_point_index(recorder, min); *(arg--) = TA_adjust_point_index(recorder, max); } start = end + 1; } if (end > 0xFF) need_words = 1; /* with most fonts it is very rare */ /* that any of the pushed arguments is larger than 0xFF, */ /* thus we refrain from further optimizing this case */ arg = args; if (need_words) { for (i = 0; i < num_args; i += 255) { nargs = (num_args - i > 255) ? 255 : num_args - i; BCI(NPUSHW); BCI(nargs); for (j = 0; j < nargs; j++) { BCI(HIGH(*arg)); BCI(LOW(*arg)); arg++; } } } else { for (i = 0; i < num_args; i += 255) { nargs = (num_args - i > 255) ? 255 : num_args - i; BCI(NPUSHB); BCI(nargs); for (j = 0; j < nargs; j++) { BCI(*arg); arg++; } } } BCI(CALL); num_stack_elements = ADDITIONAL_STACK_ELEMENTS + num_args; if (num_stack_elements > sfnt->max_stack_elements) sfnt->max_stack_elements = num_stack_elements; free(args); return bufp; }
static FT_Error TA_table_build_prep(FT_Byte** prep, FT_ULong* prep_len, SFNT* sfnt, FONT* font) { SFNT_Table* glyf_table = &font->tables[sfnt->glyf_idx]; glyf_Data* data = (glyf_Data*)glyf_table->data; /* XXX: make this work for more than 256 styles */ FT_Byte num_used_styles = (FT_Byte)data->num_used_styles; FT_Int i; FT_Byte* buf = NULL; FT_Byte* buf_new; FT_UInt buf_len; FT_UInt buf_new_len; FT_UInt len; FT_Byte* bufp = NULL; if (font->x_height_snapping_exceptions) { bufp = TA_sfnt_build_number_set(sfnt, &buf, font->x_height_snapping_exceptions); if (!bufp) return FT_Err_Out_Of_Memory; } buf_len = (FT_UInt)(bufp - buf); buf_new_len = buf_len; if (font->hinting_limit) buf_new_len += sizeof (PREP(hinting_limit_a)) + 2 + sizeof (PREP(hinting_limit_b)); buf_new_len += sizeof (PREP(store_funits_to_pixels)); if (font->x_height_snapping_exceptions) buf_new_len += sizeof (PREP(test_exception_a)); buf_new_len += sizeof (PREP(align_top_a)) + (num_used_styles > 6 ? num_used_styles + 3 : num_used_styles + 2) + sizeof (PREP(align_top_b)); buf_new_len += sizeof (PREP(loop_cvt_a)) + (num_used_styles > 3 ? 2 * num_used_styles + 3 : 2 * num_used_styles + 2) + sizeof (PREP(loop_cvt_b)) + (num_used_styles > 3 ? 2 * num_used_styles + 3 : 2 * num_used_styles + 2) + sizeof (PREP(loop_cvt_c)); if (font->x_height_snapping_exceptions) buf_new_len += sizeof (PREP(test_exception_b)); buf_new_len += sizeof (PREP(store_vwidth_data_a)) + 1 + sizeof (PREP(store_vwidth_data_b)) + (num_used_styles > 6 ? 2 * (num_used_styles + 1) + 2 : 2 * (num_used_styles + 1) + 1) + sizeof (PREP(store_vwidth_data_c)) + 1 + sizeof (PREP(store_vwidth_data_d)) + (num_used_styles > 6 ? 2 * (num_used_styles + 1) + 2 : 2 * (num_used_styles + 1) + 1) + sizeof (PREP(store_vwidth_data_e)); buf_new_len += sizeof (PREP(set_smooth_or_strong_a)) + 1 + sizeof (PREP(set_smooth_or_strong_b)) + 1 + sizeof (PREP(set_smooth_or_strong_c)) + 1 + sizeof (PREP(set_smooth_or_strong_d)); buf_new_len += (num_used_styles > 3 ? 2 * num_used_styles + 3 : 2 * num_used_styles + 2) + sizeof (PREP(round_blues)); buf_new_len += sizeof (PREP(set_dropout_mode)); buf_new_len += sizeof (PREP(reset_component_counter)); if (font->control_data_head) buf_new_len += sizeof (PREP(adjust_delta_exceptions)); buf_new_len += sizeof (PREP(set_default_cvs_values)); /* buffer length must be a multiple of four */ len = (buf_new_len + 3) & ~3U; buf_new = (FT_Byte*)realloc(buf, len); if (!buf_new) { free(buf); return FT_Err_Out_Of_Memory; } buf = buf_new; /* pad end of buffer with zeros */ buf[len - 1] = 0x00; buf[len - 2] = 0x00; buf[len - 3] = 0x00; /* copy remaining cvt program into buffer */ /* and fill in the missing variables */ bufp = buf + buf_len; if (font->hinting_limit) { COPY_PREP(hinting_limit_a); *(bufp++) = HIGH(font->hinting_limit); *(bufp++) = LOW(font->hinting_limit); COPY_PREP(hinting_limit_b); } COPY_PREP(store_funits_to_pixels); if (font->x_height_snapping_exceptions) COPY_PREP(test_exception_a); COPY_PREP(align_top_a); if (num_used_styles > 6) { BCI(NPUSHB); BCI(num_used_styles + 2); } else BCI(PUSHB_1 - 1 + num_used_styles + 2); /* XXX: make this work for offsets > 255 */ for (i = TA_STYLE_MAX - 1; i >= 0; i--) { if (data->style_ids[i] == 0xFFFFU) continue; *(bufp++) = CVT_X_HEIGHT_BLUE_OFFSET(i) >= 0xFFFFU ? 0 : (unsigned char)CVT_X_HEIGHT_BLUE_OFFSET(i); } *(bufp++) = num_used_styles; COPY_PREP(align_top_b); COPY_PREP(loop_cvt_a); if (num_used_styles > 3) { BCI(NPUSHB); BCI(2 * num_used_styles + 2); } else BCI(PUSHB_1 - 1 + 2 * num_used_styles + 2); /* XXX: make this work for offsets > 255 */ for (i = TA_STYLE_MAX - 1; i >= 0; i--) { if (data->style_ids[i] == 0xFFFFU) continue; /* don't loop over artificial blue zones */ *(bufp++) = (unsigned char)CVT_VERT_STANDARD_WIDTH_OFFSET(i); *(bufp++) = (unsigned char)( 1 + CVT_VERT_WIDTHS_SIZE(i) + (CVT_BLUES_SIZE(i) > 1 ? CVT_BLUES_SIZE(i) - 2 : 0)); } *(bufp++) = num_used_styles; COPY_PREP(loop_cvt_b); if (num_used_styles > 3) { BCI(NPUSHB); BCI(2 * num_used_styles + 2); } else BCI(PUSHB_1 - 1 + 2 * num_used_styles + 2); /* XXX: make this work for offsets > 255 */ for (i = TA_STYLE_MAX - 1; i >= 0; i--) { if (data->style_ids[i] == 0xFFFFU) continue; /* don't loop over artificial blue zones */ *(bufp++) = (unsigned char)CVT_BLUE_SHOOTS_OFFSET(i); *(bufp++) = (unsigned char)( CVT_BLUES_SIZE(i) > 1 ? CVT_BLUES_SIZE(i) - 2 : 0); } *(bufp++) = num_used_styles; COPY_PREP(loop_cvt_c); if (font->x_height_snapping_exceptions) COPY_PREP(test_exception_b); COPY_PREP(store_vwidth_data_a); *(bufp++) = (unsigned char)CVT_VWIDTH_OFFSET_DATA(0); COPY_PREP(store_vwidth_data_b); if (num_used_styles > 6) { BCI(NPUSHW); BCI(num_used_styles + 2); } else BCI(PUSHW_1 - 1 + num_used_styles + 2); for (i = TA_STYLE_MAX - 1; i >= 0; i--) { if (data->style_ids[i] == 0xFFFFU) continue; *(bufp++) = HIGH(CVT_VERT_WIDTHS_OFFSET(i) * 64); *(bufp++) = LOW(CVT_VERT_WIDTHS_OFFSET(i) * 64); } *(bufp++) = HIGH(num_used_styles); *(bufp++) = LOW(num_used_styles); COPY_PREP(store_vwidth_data_c); *(bufp++) = (unsigned char)CVT_VWIDTH_SIZE_DATA(0); COPY_PREP(store_vwidth_data_d); if (num_used_styles > 6) { BCI(NPUSHW); BCI(num_used_styles + 2); } else BCI(PUSHW_1 - 1 + num_used_styles + 2); for (i = TA_STYLE_MAX - 1; i >= 0; i--) { if (data->style_ids[i] == 0xFFFFU) continue; *(bufp++) = HIGH(CVT_VERT_WIDTHS_SIZE(i) * 64); *(bufp++) = LOW(CVT_VERT_WIDTHS_SIZE(i) * 64); } *(bufp++) = HIGH(num_used_styles); *(bufp++) = LOW(num_used_styles); COPY_PREP(store_vwidth_data_e); COPY_PREP(set_smooth_or_strong_a); *(bufp++) = font->gray_strong_stem_width ? 100 : 0; COPY_PREP(set_smooth_or_strong_b); *(bufp++) = font->gdi_cleartype_strong_stem_width ? 100 : 0; COPY_PREP(set_smooth_or_strong_c); *(bufp++) = font->dw_cleartype_strong_stem_width ? 100 : 0; COPY_PREP(set_smooth_or_strong_d); if (num_used_styles > 3) { BCI(NPUSHB); BCI(2 * num_used_styles + 2); } else BCI(PUSHB_1 - 1 + 2 * num_used_styles + 2); /* XXX: make this work for offsets > 255 */ for (i = TA_STYLE_MAX - 1; i >= 0; i--) { if (data->style_ids[i] == 0xFFFFU) continue; *(bufp++) = (unsigned char)CVT_BLUE_REFS_OFFSET(i); *(bufp++) = (unsigned char)CVT_BLUES_SIZE(i); } *(bufp++) = num_used_styles; COPY_PREP(round_blues); COPY_PREP(set_dropout_mode); COPY_PREP(reset_component_counter); if (font->control_data_head) COPY_PREP(adjust_delta_exceptions); COPY_PREP(set_default_cvs_values); *prep = buf; *prep_len = buf_new_len; return FT_Err_Ok; }
static FT_Byte* TA_sfnt_build_number_set(SFNT* sfnt, FT_Byte** buf, number_range* number_set) { FT_Byte* bufp = NULL; number_range* nr; FT_UInt num_singles2 = 0; FT_UInt* single2_args; FT_UInt* single2_arg; FT_UInt num_singles = 0; FT_UInt* single_args; FT_UInt* single_arg; FT_UInt num_ranges2 = 0; FT_UInt* range2_args; FT_UInt* range2_arg; FT_UInt num_ranges = 0; FT_UInt* range_args; FT_UInt* range_arg; FT_UInt have_single = 0; FT_UInt have_range = 0; FT_UShort num_stack_elements; /* build up four stacks to stay as compact as possible */ nr = number_set; while (nr) { if (nr->start == nr->end) { if (nr->start < 256) num_singles++; else num_singles2++; } else { if (nr->start < 256 && nr->end < 256) num_ranges++; else num_ranges2++; } nr = nr->next; } /* collect all arguments temporarily in arrays (in reverse order) */ /* so that we can easily split into chunks of 255 args */ /* as needed by NPUSHB and friends; */ /* for simplicity, always allocate an extra slot */ single2_args = (FT_UInt*)malloc((num_singles2 + 1) * sizeof (FT_UInt)); single_args = (FT_UInt*)malloc((num_singles + 1) * sizeof (FT_UInt)); range2_args = (FT_UInt*)malloc((2 * num_ranges2 + 1) * sizeof (FT_UInt)); range_args = (FT_UInt*)malloc((2 * num_ranges + 1) * sizeof (FT_UInt)); if (!single2_args || !single_args || !range2_args || !range_args) goto Fail; /* check whether we need the extra slot for the argument to CALL */ if (num_singles || num_singles2) have_single = 1; if (num_ranges || num_ranges2) have_range = 1; /* set function indices outside of argument loop (using the extra slot) */ if (have_single) single_args[num_singles] = bci_number_set_is_element; if (have_range) range_args[2 * num_ranges] = bci_number_set_is_element2; single2_arg = single2_args + num_singles2 - 1; single_arg = single_args + num_singles - 1; range2_arg = range2_args + 2 * num_ranges2 - 1; range_arg = range_args + 2 * num_ranges - 1; nr = number_set; while (nr) { FT_UInt start = (FT_UInt)nr->start; FT_UInt end = (FT_UInt)nr->end; if (start == end) { if (start < 256) *(single_arg--) = start; else *(single2_arg--) = start; } else { if (start < 256 && end < 256) { *(range_arg--) = start; *(range_arg--) = end; } else { *(range2_arg--) = start; *(range2_arg--) = end; } } nr = nr->next; } /* this rough estimate of the buffer size gets adjusted later on */ *buf = (FT_Byte*)malloc((2 + 1) * num_singles2 + (1 + 1) * num_singles + (4 + 1) * num_ranges2 + (2 + 1) * num_ranges + 10); if (!*buf) goto Fail; bufp = *buf; BCI(PUSHB_2); BCI(cvtl_is_element); BCI(0); BCI(WCVTP); bufp = TA_build_push(bufp, single2_args, num_singles2, 1, 1); bufp = TA_build_push(bufp, single_args, num_singles + have_single, 0, 1); if (have_single) BCI(CALL); bufp = TA_build_push(bufp, range2_args, 2 * num_ranges2, 1, 1); bufp = TA_build_push(bufp, range_args, 2 * num_ranges + have_range, 0, 1); if (have_range) BCI(CALL); num_stack_elements = (FT_UShort)(num_singles + num_singles2); if (num_stack_elements > num_ranges + num_ranges2) num_stack_elements = (FT_UShort)(num_ranges + num_ranges2); num_stack_elements += ADDITIONAL_STACK_ELEMENTS; if (num_stack_elements > sfnt->max_stack_elements) sfnt->max_stack_elements = num_stack_elements; Fail: free(single2_args); free(single_args); free(range2_args); free(range_args); return bufp; }