static void BBox_Cubic_Check( FT_Pos p1, FT_Pos p2, FT_Pos p3, FT_Pos p4, FT_Pos* min, FT_Pos* max ) { FT_Pos nmin, nmax; FT_Int shift; /* This function is only called when a control off-point is outside */ /* the bbox that contains all on-points. It finds a local extremum */ /* within the segment using iterative bisection of the segment. */ /* The fixed-point arithmetic of bisection is inherently stable */ /* but may loose accuracy in the two lowest bits. To compensate, */ /* we upscale the segment if there is room. Large values may need */ /* to be downscaled to avoid overflows during bisection. */ /* The control off-point outside the bbox is likely to have the top */ /* absolute value among arguments. */ shift = 27 - FT_MSB( FT_ABS( p2 ) | FT_ABS( p3 ) ); if ( shift > 0 ) { /* upscaling too much just wastes time */ if ( shift > 2 ) shift = 2; p1 <<= shift; p2 <<= shift; p3 <<= shift; p4 <<= shift; nmin = *min << shift; nmax = *max << shift; } else { p1 >>= -shift; p2 >>= -shift; p3 >>= -shift; p4 >>= -shift; nmin = *min >> -shift; nmax = *max >> -shift; } nmax = update_cubic_max( p1, p2, p3, p4, nmax ); /* now flip the signs to update the minimum */ nmin = -update_cubic_max( -p1, -p2, -p3, -p4, -nmin ); if ( shift > 0 ) { nmin >>= shift; nmax >>= shift; }
pfr_face_get_kerning( FT_Face pfrface, /* PFR_Face */ FT_UInt glyph1, FT_UInt glyph2, FT_Vector* kerning ) { PFR_Face face = (PFR_Face)pfrface; FT_Error error = FT_Err_Ok; PFR_PhyFont phy_font = &face->phy_font; FT_UInt32 code1, code2, pair; kerning->x = 0; kerning->y = 0; if ( glyph1 > 0 ) glyph1--; if ( glyph2 > 0 ) glyph2--; /* convert glyph indices to character codes */ if ( glyph1 > phy_font->num_chars || glyph2 > phy_font->num_chars ) goto Exit; code1 = phy_font->chars[glyph1].char_code; code2 = phy_font->chars[glyph2].char_code; pair = PFR_KERN_INDEX( code1, code2 ); /* now search the list of kerning items */ { PFR_KernItem item = phy_font->kern_items; FT_Stream stream = pfrface->stream; for ( ; item; item = item->next ) { if ( pair >= item->pair1 && pair <= item->pair2 ) goto FoundPair; } goto Exit; FoundPair: /* we found an item, now parse it and find the value if any */ if ( FT_STREAM_SEEK( item->offset ) || FT_FRAME_ENTER( item->pair_count * item->pair_size ) ) goto Exit; { FT_UInt count = item->pair_count; FT_UInt size = item->pair_size; FT_UInt power = 1 << FT_MSB( count ); FT_UInt probe = power * size; FT_UInt extra = count - power; FT_Byte* base = stream->cursor; FT_Bool twobytes = FT_BOOL( item->flags & 1 ); FT_Bool twobyte_adj = FT_BOOL( item->flags & 2 ); FT_Byte* p; FT_UInt32 cpair; if ( extra > 0 ) { p = base + extra * size; if ( twobytes ) cpair = FT_NEXT_ULONG( p ); else cpair = PFR_NEXT_KPAIR( p ); if ( cpair == pair ) goto Found; if ( cpair < pair ) { if ( twobyte_adj ) p += 2; else p++; base = p; } } while ( probe > size ) { probe >>= 1; p = base + probe; if ( twobytes ) cpair = FT_NEXT_ULONG( p ); else cpair = PFR_NEXT_KPAIR( p ); if ( cpair == pair ) goto Found; if ( cpair < pair ) base += probe; } p = base; if ( twobytes ) cpair = FT_NEXT_ULONG( p ); else cpair = PFR_NEXT_KPAIR( p ); if ( cpair == pair ) { FT_Int value; Found: if ( twobyte_adj ) value = FT_PEEK_SHORT( p ); else value = p[0]; kerning->x = item->base_adj + value; } } FT_FRAME_EXIT(); } Exit: return error; }
static void BBox_Cubic_Check( FT_Pos y1, FT_Pos y2, FT_Pos y3, FT_Pos y4, FT_Pos* min, FT_Pos* max ) { /* always compare first and last points */ if ( y1 < *min ) *min = y1; else if ( y1 > *max ) *max = y1; if ( y4 < *min ) *min = y4; else if ( y4 > *max ) *max = y4; /* now, try to see if there are split points here */ if ( y1 <= y4 ) { /* flat or ascending arc test */ if ( y1 <= y2 && y2 <= y4 && y1 <= y3 && y3 <= y4 ) return; } else /* y1 > y4 */ { /* descending arc test */ if ( y1 >= y2 && y2 >= y4 && y1 >= y3 && y3 >= y4 ) return; } /* There are some split points. Find them. */ /* We already made sure that a, b, and c below cannot be all zero. */ { FT_Pos a = y4 - 3*y3 + 3*y2 - y1; FT_Pos b = y3 - 2*y2 + y1; FT_Pos c = y2 - y1; FT_Pos d; FT_Fixed t; FT_Int shift; /* We need to solve `ax^2+2bx+c' here, without floating points! */ /* The trick is to normalize to a different representation in order */ /* to use our 16.16 fixed-point routines. */ /* */ /* We compute FT_MulFix(b,b) and FT_MulFix(a,c) after normalization. */ /* These values must fit into a single 16.16 value. */ /* */ /* We normalize a, b, and c to `8.16' fixed-point values to ensure */ /* that their product is held in a `16.16' value including the sign. */ /* Necessarily, we need to shift `a', `b', and `c' so that the most */ /* significant bit of their absolute values is at position 22. */ /* */ /* This also means that we are using 23 bits of precision to compute */ /* the zeros, independently of the range of the original polynomial */ /* coefficients. */ /* */ /* This algorithm should ensure reasonably accurate values for the */ /* zeros. Note that they are only expressed with 16 bits when */ /* computing the extrema (the zeros need to be in 0..1 exclusive */ /* to be considered part of the arc). */ shift = FT_MSB( FT_ABS( a ) | FT_ABS( b ) | FT_ABS( c ) ); if ( shift > 22 ) { shift -= 22; /* this loses some bits of precision, but we use 23 of them */ /* for the computation anyway */ a >>= shift; b >>= shift; c >>= shift; } else {
af_loader_compute_darkening( AF_Loader loader, FT_Face face, FT_Pos standard_width ) { AF_Module module = loader->globals->module; FT_UShort units_per_EM; FT_Fixed ppem, em_ratio; FT_Fixed stem_width, stem_width_per_1000, scaled_stem, darken_amount; FT_Int log_base_2; FT_Int x1, y1, x2, y2, x3, y3, x4, y4; ppem = FT_MAX( af_intToFixed( 4 ), af_intToFixed( face->size->metrics.x_ppem ) ); units_per_EM = face->units_per_EM; em_ratio = FT_DivFix( af_intToFixed( 1000 ), af_intToFixed ( units_per_EM ) ); if ( em_ratio < af_floatToFixed( .01 ) ) { /* If something goes wrong, don't embolden. */ return 0; } x1 = module->darken_params[0]; y1 = module->darken_params[1]; x2 = module->darken_params[2]; y2 = module->darken_params[3]; x3 = module->darken_params[4]; y3 = module->darken_params[5]; x4 = module->darken_params[6]; y4 = module->darken_params[7]; if ( standard_width <= 0 ) { stem_width = af_intToFixed( 75 ); /* taken from cf2font.c */ stem_width_per_1000 = stem_width; } else { stem_width = af_intToFixed( standard_width ); stem_width_per_1000 = FT_MulFix( stem_width, em_ratio ); } log_base_2 = FT_MSB( (FT_UInt32)stem_width_per_1000 ) + FT_MSB( (FT_UInt32)ppem ); if ( log_base_2 >= 46 ) { /* possible overflow */ scaled_stem = af_intToFixed( x4 ); } else scaled_stem = FT_MulFix( stem_width_per_1000, ppem ); /* now apply the darkening parameters */ if ( scaled_stem < af_intToFixed( x1 ) ) darken_amount = FT_DivFix( af_intToFixed( y1 ), ppem ); else if ( scaled_stem < af_intToFixed( x2 ) ) { FT_Int xdelta = x2 - x1; FT_Int ydelta = y2 - y1; FT_Int x = stem_width_per_1000 - FT_DivFix( af_intToFixed( x1 ), ppem ); if ( !xdelta ) goto Try_x3; darken_amount = FT_MulDiv( x, ydelta, xdelta ) + FT_DivFix( af_intToFixed( y1 ), ppem ); } else if ( scaled_stem < af_intToFixed( x3 ) ) { Try_x3: { FT_Int xdelta = x3 - x2; FT_Int ydelta = y3 - y2; FT_Int x = stem_width_per_1000 - FT_DivFix( af_intToFixed( x2 ), ppem ); if ( !xdelta ) goto Try_x4; darken_amount = FT_MulDiv( x, ydelta, xdelta ) + FT_DivFix( af_intToFixed( y2 ), ppem ); } } else if ( scaled_stem < af_intToFixed( x4 ) ) { Try_x4: { FT_Int xdelta = x4 - x3; FT_Int ydelta = y4 - y3; FT_Int x = stem_width_per_1000 - FT_DivFix( af_intToFixed( x3 ), ppem ); if ( !xdelta ) goto Use_y4; darken_amount = FT_MulDiv( x, ydelta, xdelta ) + FT_DivFix( af_intToFixed( y3 ), ppem ); } } else { Use_y4: darken_amount = FT_DivFix( af_intToFixed( y4 ), ppem ); } /* Convert darken_amount from per 1000 em to true character space. */ return af_fixedToInt( FT_DivFix( darken_amount, em_ratio ) ); }
FT_Outline_Get_Orientation( FT_Outline* outline ) { FT_BBox cbox; FT_Int xshift, yshift; FT_Vector* points; FT_Vector v_prev, v_cur; FT_Int c, n, first; FT_Pos area = 0; if ( !outline || outline->n_points <= 0 ) return FT_ORIENTATION_TRUETYPE; /* We use the nonzero winding rule to find the orientation. */ /* Since glyph outlines behave much more `regular' than arbitrary */ /* cubic or quadratic curves, this test deals with the polygon */ /* only that is spanned up by the control points. */ FT_Outline_Get_CBox( outline, &cbox ); /* Handle collapsed outlines to avoid undefined FT_MSB. */ if ( cbox.xMin == cbox.xMax || cbox.yMin == cbox.yMax ) return FT_ORIENTATION_NONE; xshift = FT_MSB( (FT_UInt32)( FT_ABS( cbox.xMax ) | FT_ABS( cbox.xMin ) ) ) - 14; xshift = FT_MAX( xshift, 0 ); yshift = FT_MSB( (FT_UInt32)( cbox.yMax - cbox.yMin ) ) - 14; yshift = FT_MAX( yshift, 0 ); points = outline->points; first = 0; for ( c = 0; c < outline->n_contours; c++ ) { FT_Int last = outline->contours[c]; v_prev.x = points[last].x >> xshift; v_prev.y = points[last].y >> yshift; for ( n = first; n <= last; n++ ) { v_cur.x = points[n].x >> xshift; v_cur.y = points[n].y >> yshift; area = ADD_LONG( area, ( v_cur.y - v_prev.y ) * ( v_cur.x + v_prev.x ) ); v_prev = v_cur; } first = last + 1; } if ( area > 0 ) return FT_ORIENTATION_POSTSCRIPT; else if ( area < 0 ) return FT_ORIENTATION_TRUETYPE; else return FT_ORIENTATION_NONE; }
/* Compute a stem darkening amount in character space. */ static void cf2_computeDarkening( CF2_Fixed emRatio, CF2_Fixed ppem, CF2_Fixed stemWidth, CF2_Fixed* darkenAmount, CF2_Fixed boldenAmount, FT_Bool stemDarkened, FT_Int* darkenParams ) { /* * Total darkening amount is computed in 1000 unit character space * using the modified 5 part curve as Adobe's Avalon rasterizer. * The darkening amount is smaller for thicker stems. * It becomes zero when the stem is thicker than 2.333 pixels. * * By default, we use * * darkenAmount = 0.4 pixels if scaledStem <= 0.5 pixels, * darkenAmount = 0.275 pixels if 1 <= scaledStem <= 1.667 pixels, * darkenAmount = 0 pixel if scaledStem >= 2.333 pixels, * * and piecewise linear in-between: * * * darkening * ^ * | * | (x1,y1) * |--------+ * | \ * | \ * | \ (x3,y3) * | +----------+ * | (x2,y2) \ * | \ * | \ * | +----------------- * | (x4,y4) * +---------------------------------------------> stem * thickness * * * This corresponds to the following values for the * `darkening-parameters' property: * * (x1, y1) = (500, 400) * (x2, y2) = (1000, 275) * (x3, y3) = (1667, 275) * (x4, y4) = (2333, 0) * */ /* Internal calculations are done in units per thousand for */ /* convenience. The x axis is scaled stem width in */ /* thousandths of a pixel. That is, 1000 is 1 pixel. */ /* The y axis is darkening amount in thousandths of a pixel.*/ /* In the code, below, dividing by ppem and */ /* adjusting for emRatio converts darkenAmount to character */ /* space (font units). */ CF2_Fixed stemWidthPer1000, scaledStem; FT_Int logBase2; *darkenAmount = 0; if ( boldenAmount == 0 && !stemDarkened ) return; /* protect against range problems and divide by zero */ if ( emRatio < cf2_floatToFixed( .01 ) ) return; if ( stemDarkened ) { FT_Int x1 = darkenParams[0]; FT_Int y1 = darkenParams[1]; FT_Int x2 = darkenParams[2]; FT_Int y2 = darkenParams[3]; FT_Int x3 = darkenParams[4]; FT_Int y3 = darkenParams[5]; FT_Int x4 = darkenParams[6]; FT_Int y4 = darkenParams[7]; /* convert from true character space to 1000 unit character space; */ /* add synthetic emboldening effect */ /* `stemWidthPer1000' will not overflow for a legitimate font */ stemWidthPer1000 = FT_MulFix( stemWidth + boldenAmount, emRatio ); /* `scaledStem' can easily overflow, so we must clamp its maximum */ /* value; the test doesn't need to be precise, but must be */ /* conservative. The clamp value (default 2333) where */ /* `darkenAmount' is zero is well below the overflow value of */ /* 32767. */ /* */ /* FT_MSB computes the integer part of the base 2 logarithm. The */ /* number of bits for the product is 1 or 2 more than the sum of */ /* logarithms; remembering that the 16 lowest bits of the fraction */ /* are dropped this is correct to within a factor of almost 4. */ /* For example, 0x80.0000 * 0x80.0000 = 0x4000.0000 is 23+23 and */ /* is flagged as possible overflow because 0xFF.FFFF * 0xFF.FFFF = */ /* 0xFFFF.FE00 is also 23+23. */ logBase2 = FT_MSB( (FT_UInt32)stemWidthPer1000 ) + FT_MSB( (FT_UInt32)ppem ); if ( logBase2 >= 46 ) /* possible overflow */ scaledStem = cf2_intToFixed( x4 ); else scaledStem = FT_MulFix( stemWidthPer1000, ppem ); /* now apply the darkening parameters */ if ( scaledStem < cf2_intToFixed( x1 ) ) *darkenAmount = FT_DivFix( cf2_intToFixed( y1 ), ppem ); else if ( scaledStem < cf2_intToFixed( x2 ) ) { FT_Int xdelta = x2 - x1; FT_Int ydelta = y2 - y1; FT_Int x = stemWidthPer1000 - FT_DivFix( cf2_intToFixed( x1 ), ppem ); if ( !xdelta ) goto Try_x3; *darkenAmount = FT_MulDiv( x, ydelta, xdelta ) + FT_DivFix( cf2_intToFixed( y1 ), ppem ); } else if ( scaledStem < cf2_intToFixed( x3 ) ) { Try_x3: { FT_Int xdelta = x3 - x2; FT_Int ydelta = y3 - y2; FT_Int x = stemWidthPer1000 - FT_DivFix( cf2_intToFixed( x2 ), ppem ); if ( !xdelta ) goto Try_x4; *darkenAmount = FT_MulDiv( x, ydelta, xdelta ) + FT_DivFix( cf2_intToFixed( y2 ), ppem ); } } else if ( scaledStem < cf2_intToFixed( x4 ) ) { Try_x4: { FT_Int xdelta = x4 - x3; FT_Int ydelta = y4 - y3; FT_Int x = stemWidthPer1000 - FT_DivFix( cf2_intToFixed( x3 ), ppem ); if ( !xdelta ) goto Use_y4; *darkenAmount = FT_MulDiv( x, ydelta, xdelta ) + FT_DivFix( cf2_intToFixed( y3 ), ppem ); } } else { Use_y4: *darkenAmount = FT_DivFix( cf2_intToFixed( y4 ), ppem ); } /* use half the amount on each side and convert back to true */ /* character space */ *darkenAmount = FT_DivFix( *darkenAmount, 2 * emRatio ); } /* add synthetic emboldening effect in character space */ *darkenAmount += boldenAmount / 2; }