FT_Outline_GetOutsideBorder( FT_Outline* outline ) { FT_Orientation o = FT_Outline_Get_Orientation( outline ); return o == FT_ORIENTATION_TRUETYPE ? FT_STROKER_BORDER_LEFT : FT_STROKER_BORDER_RIGHT ; }
static PyObject* Py_Outline_get_orientation(Py_Outline* self, PyObject* args, PyObject* kwds) { int orientation; orientation = FT_Outline_Get_Orientation(&self->x); return Py_Constant_cnew(&Py_FT_ORIENTATION_ConstantType, orientation); }
unsigned int get_contour_type(FT_Outline& outline, unsigned int c) { FT_Orientation orientation = FT_Outline_Get_Orientation(&outline); unsigned int order = get_contour_order(outline, c); if (orientation==FT_ORIENTATION_TRUETYPE && order==kOrderCounterClockwise) return kContourTypeInner; else if (orientation==FT_ORIENTATION_TRUETYPE && order==kOrderClockwise) return kContourTypeOuter; else if (orientation==FT_ORIENTATION_POSTSCRIPT && order==kOrderCounterClockwise) return kContourTypeOuter; else if (orientation==FT_ORIENTATION_POSTSCRIPT && order==kOrderClockwise) return kContourTypeInner; else return -1; }
// 新的加粗函数 FT_Error New_FT_Outline_Embolden( FT_Outline* outline, FT_Pos str_h, FT_Pos str_v ) { int orientation; if ( !outline ) return FT_Err_Invalid_Argument; orientation = FT_Outline_Get_Orientation( outline ); if ( orientation == FT_ORIENTATION_NONE ) if ( outline->n_contours ) return FT_Err_Invalid_Argument; Vert_FT_Outline_Embolden( outline, str_v ); Old_FT_Outline_Embolden( outline, str_h ); return FT_Err_Ok; }
FT_Outline_Embolden( FT_Outline* outline, FT_Pos strength ) { FT_Vector* points; FT_Vector v_prev, v_first, v_next, v_cur; FT_Angle rotate, angle_in, angle_out; FT_Int c, n, first; FT_Int orientation; if ( !outline ) return FT_Err_Invalid_Argument; strength /= 2; if ( strength == 0 ) return FT_Err_Ok; orientation = FT_Outline_Get_Orientation( outline ); if ( orientation == FT_ORIENTATION_NONE ) { if ( outline->n_contours ) return FT_Err_Invalid_Argument; else return FT_Err_Ok; } if ( orientation == FT_ORIENTATION_TRUETYPE ) rotate = -FT_ANGLE_PI2; else rotate = FT_ANGLE_PI2; points = outline->points; first = 0; for ( c = 0; c < outline->n_contours; c++ ) { int last = outline->contours[c]; v_first = points[first]; v_prev = points[last]; v_cur = v_first; for ( n = first; n <= last; n++ ) { FT_Vector in, out; FT_Angle angle_diff; FT_Pos d; FT_Fixed scale; if ( n < last ) v_next = points[n + 1]; else v_next = v_first; /* compute the in and out vectors */ in.x = v_cur.x - v_prev.x; in.y = v_cur.y - v_prev.y; out.x = v_next.x - v_cur.x; out.y = v_next.y - v_cur.y; angle_in = FT_Atan2( in.x, in.y ); angle_out = FT_Atan2( out.x, out.y ); angle_diff = FT_Angle_Diff( angle_in, angle_out ); scale = FT_Cos( angle_diff / 2 ); if ( scale < 0x4000L && scale > -0x4000L ) in.x = in.y = 0; else { d = FT_DivFix( strength, scale ); FT_Vector_From_Polar( &in, d, angle_in + angle_diff / 2 - rotate ); } outline->points[n].x = v_cur.x + strength + in.x; outline->points[n].y = v_cur.y + strength + in.y; v_prev = v_cur; v_cur = v_next; } first = last + 1; } return FT_Err_Ok; }
FT_Outline_EmboldenXY( FT_Outline* outline, FT_Pos xstrength, FT_Pos ystrength ) { FT_Vector* points; FT_Vector v_prev, v_first, v_next, v_cur; FT_Int c, n, first; FT_Int orientation; if ( !outline ) return FT_Err_Invalid_Argument; xstrength /= 2; ystrength /= 2; if ( xstrength == 0 && ystrength == 0 ) return FT_Err_Ok; orientation = FT_Outline_Get_Orientation( outline ); if ( orientation == FT_ORIENTATION_NONE ) { if ( outline->n_contours ) return FT_Err_Invalid_Argument; else return FT_Err_Ok; } points = outline->points; first = 0; for ( c = 0; c < outline->n_contours; c++ ) { FT_Vector in, out, shift; FT_Fixed l_in, l_out, l, q, d; int last = outline->contours[c]; v_first = points[first]; v_prev = points[last]; v_cur = v_first; /* compute the incoming vector and its length */ in.x = v_cur.x - v_prev.x; in.y = v_cur.y - v_prev.y; l_in = FT_Vector_Length( &in ); for ( n = first; n <= last; n++ ) { if ( n < last ) v_next = points[n + 1]; else v_next = v_first; /* compute the outgoing vector and its length */ out.x = v_next.x - v_cur.x; out.y = v_next.y - v_cur.y; l_out = FT_Vector_Length( &out ); d = l_in * l_out + in.x * out.x + in.y * out.y; /* shift only if turn is less then ~160 degrees */ if ( 16 * d > l_in * l_out ) { /* shift components are aligned along bisector */ /* and directed according to the outline orientation. */ shift.x = l_out * in.y + l_in * out.y; shift.y = l_out * in.x + l_in * out.x; if ( orientation == FT_ORIENTATION_TRUETYPE ) shift.x = -shift.x; else shift.y = -shift.y; /* threshold strength to better handle collapsing segments */ l = FT_MIN( l_in, l_out ); q = out.x * in.y - out.y * in.x; if ( orientation == FT_ORIENTATION_TRUETYPE ) q = -q; if ( FT_MulDiv( xstrength, q, l ) < d ) shift.x = FT_MulDiv( shift.x, xstrength, d ); else shift.x = FT_MulDiv( shift.x, l, q ); if ( FT_MulDiv( ystrength, q, l ) < d ) shift.y = FT_MulDiv( shift.y, ystrength, d ); else shift.y = FT_MulDiv( shift.y, l, q ); } else shift.x = shift.y = 0; outline->points[n].x = v_cur.x + xstrength + shift.x; outline->points[n].y = v_cur.y + ystrength + shift.y; in = out; l_in = l_out; v_cur = v_next; } first = last + 1; } return FT_Err_Ok; }
static void GK_Outline_Embolden(FT_Outline* outline,FT_Pos strength,int* x_left,int* x_right,int* y_bottom,int* y_top) { FT_Vector* points; FT_Vector v_prev, v_first, v_next, v_cur; FT_Angle rotate, angle_in, angle_out; FT_Int c, n, first = 0; FT_Int orientation; FT_Int min_x = 35565, max_x = -35565, min_y = 35565, max_y = -35565; FT_Int new_min_x = 35565, new_max_x = -35565, new_min_y = 35565, new_max_y = -35565; if (!outline) return; strength /= 2; if ( strength == 0 ) return; orientation = FT_Outline_Get_Orientation(outline); if (orientation == FT_ORIENTATION_NONE) return; #ifdef GLYPH_LOG if (glyph_log) { fprintf(glyph_log," Emboldening the outline by %ld:\n",strength); } #endif if (orientation == FT_ORIENTATION_TRUETYPE) rotate = -FT_ANGLE_PI2; else rotate = FT_ANGLE_PI2; points = outline->points; for ( c = 0; c < outline->n_contours; c++ ) { int last = outline->contours[c]; v_first = points[first]; v_prev = points[last]; v_cur = v_first; for ( n = first; n <= last; n++ ) { FT_Vector in, out; FT_Angle angle_diff; FT_Pos d; FT_Fixed scale; if ( n < last ) v_next = points[n + 1]; else v_next = v_first; /* compute the in and out vectors */ in.x = v_cur.x - v_prev.x; in.y = v_cur.y - v_prev.y; out.x = v_next.x - v_cur.x; out.y = v_next.y - v_cur.y; angle_in = FT_Atan2( in.x, in.y ); angle_out = FT_Atan2( out.x, out.y ); angle_diff = FT_Angle_Diff( angle_in, angle_out ); scale = FT_Cos( angle_diff / 2 ); if ( scale < 0x4000L && scale > -0x4000L ) in.x = in.y = 0; else { d = FT_DivFix( strength, scale ); FT_Vector_From_Polar( &in, d, angle_in + angle_diff / 2 - rotate ); } outline->points[n].x = v_cur.x + strength + in.x; outline->points[n].y = v_cur.y + strength + in.y; if (v_cur.x < min_x) min_x = v_cur.x; if (v_cur.x > max_x) max_x = v_cur.x; if (v_cur.y < min_y) min_y = v_cur.y; if (v_cur.y > max_y) max_y = v_cur.y; if (outline->points[n].x < new_min_x) new_min_x = outline->points[n].x; if (outline->points[n].x > new_max_x) new_max_x = outline->points[n].x; if (outline->points[n].y < new_min_y) new_min_y = outline->points[n].y; if (outline->points[n].y > new_max_y) new_max_y = outline->points[n].y; v_prev = v_cur; v_cur = v_next; } first = last + 1; } *x_left = min_x - new_min_x; *x_right = new_max_x - max_x; *y_top = new_max_y - max_y; *y_bottom = min_y - new_min_y; #ifdef GLYPH_LOG if (glyph_log) { fprintf(glyph_log," (%d..%d x %d..%d) -> (%d..%d x %d..%d)\n", min_x,max_x,min_y,max_y,new_min_x,new_max_x,new_min_y,new_max_y); } #endif }
af_glyph_hints_reload( AF_GlyphHints hints, FT_Outline* outline ) { FT_Error error = FT_Err_Ok; AF_Point points; FT_UInt old_max, new_max; AF_Scaler scaler = &hints->metrics->scaler; FT_Fixed x_scale = hints->x_scale; FT_Fixed y_scale = hints->y_scale; FT_Pos x_delta = hints->x_delta; FT_Pos y_delta = hints->y_delta; FT_Memory memory = hints->memory; hints->scaler_flags = scaler->flags; hints->num_points = 0; hints->num_contours = 0; hints->axis[0].num_segments = 0; hints->axis[0].num_edges = 0; hints->axis[1].num_segments = 0; hints->axis[1].num_edges = 0; /* first of all, reallocate the contours array when necessary */ new_max = (FT_UInt) outline->n_contours; old_max = hints->max_contours; if ( new_max > old_max ) { new_max = (new_max + 3) & ~3; if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) ) goto Exit; hints->max_contours = new_max; } /* then, reallocate the points, segments & edges arrays if needed -- * note that we reserved two additional point positions, used to * hint metrics appropriately */ new_max = (FT_UInt)( outline->n_points + 2 ); old_max = hints->max_points; if ( new_max > old_max ) { FT_Byte* items; FT_ULong off1, off2, off3; /* we store in a single buffer the following arrays: * * - an array of N AF_PointRec items * - an array of 2*N AF_SegmentRec items * - an array of 2*N AF_EdgeRec items * */ new_max = ( new_max + 2 + 7 ) & ~7; #define OFF_PAD2(x,y) (((x)+(y)-1) & ~((y)-1)) #define OFF_PADX(x,y) ((((x)+(y)-1)/(y))*(y)) #define OFF_PAD(x,y) ( ((y) & ((y)-1)) ? OFF_PADX(x,y) : OFF_PAD2(x,y) ) #undef OFF_INCREMENT #define OFF_INCREMENT( _off, _type, _count ) \ ( OFF_PAD( _off, sizeof(_type) ) + (_count)*sizeof(_type)) off1 = OFF_INCREMENT( 0, AF_PointRec, new_max ); off2 = OFF_INCREMENT( off1, AF_SegmentRec, new_max*2 ); off3 = OFF_INCREMENT( off2, AF_EdgeRec, new_max*2 ); FT_FREE( hints->points ); if ( FT_ALLOC( items, off3 ) ) { hints->max_points = 0; hints->axis[0].segments = NULL; hints->axis[0].edges = NULL; hints->axis[1].segments = NULL; hints->axis[1].edges = NULL; goto Exit; } /* readjust some pointers */ hints->max_points = new_max; hints->points = (AF_Point) items; hints->axis[0].segments = (AF_Segment)( items + off1 ); hints->axis[1].segments = hints->axis[0].segments + new_max; hints->axis[0].edges = (AF_Edge) ( items + off2 ); hints->axis[1].edges = hints->axis[0].edges + new_max; } hints->num_points = outline->n_points; hints->num_contours = outline->n_contours; /* We can't rely on the value of `FT_Outline.flags' to know the fill */ /* direction used for a glyph, given that some fonts are broken (e.g. */ /* the Arphic ones). We thus recompute it each time we need to. */ /* */ hints->axis[ AF_DIMENSION_HORZ ].major_dir = AF_DIR_UP; hints->axis[ AF_DIMENSION_VERT ].major_dir = AF_DIR_LEFT; if ( FT_Outline_Get_Orientation( outline ) == FT_ORIENTATION_POSTSCRIPT ) { hints->axis[ AF_DIMENSION_HORZ ].major_dir = AF_DIR_DOWN; hints->axis[ AF_DIMENSION_VERT ].major_dir = AF_DIR_RIGHT; } hints->x_scale = x_scale; hints->y_scale = y_scale; hints->x_delta = x_delta; hints->y_delta = y_delta; points = hints->points; if ( hints->num_points == 0 ) goto Exit; { AF_Point point; AF_Point point_limit = points + hints->num_points; /* compute coordinates & bezier flags */ { FT_Vector* vec = outline->points; char* tag = outline->tags; for ( point = points; point < point_limit; point++, vec++, tag++ ) { point->fx = vec->x; point->fy = vec->y; point->ox = point->x = FT_MulFix( vec->x, x_scale ) + x_delta; point->oy = point->y = FT_MulFix( vec->y, y_scale ) + y_delta; switch ( FT_CURVE_TAG( *tag ) ) { case FT_CURVE_TAG_CONIC: point->flags = AF_FLAG_CONIC; break; case FT_CURVE_TAG_CUBIC: point->flags = AF_FLAG_CUBIC; break; default: point->flags = 0; ; } } } /* compute `next' and `prev' */ { FT_Int contour_index; AF_Point prev; AF_Point first; AF_Point end; contour_index = 0; first = points; end = points + outline->contours[0]; prev = end; for ( point = points; point < point_limit; point++ ) { point->prev = prev; if ( point < end ) { point->next = point + 1; prev = point; } else { point->next = first; contour_index++; if ( point + 1 < point_limit ) { end = points + outline->contours[contour_index]; first = point + 1; prev = end; } } } } /* set-up the contours array */ { AF_Point* contour = hints->contours; AF_Point* contour_limit = contour + hints->num_contours; short* end = outline->contours; short idx = 0; for ( ; contour < contour_limit; contour++, end++ ) { contour[0] = points + idx; idx = (short)( end[0] + 1 ); } } /* compute directions of in & out vectors */ { for ( point = points; point < point_limit; point++ ) { AF_Point prev; AF_Point next; FT_Pos in_x, in_y, out_x, out_y; prev = point->prev; in_x = point->fx - prev->fx; in_y = point->fy - prev->fy; point->in_dir = af_direction_compute( in_x, in_y ); next = point->next; out_x = next->fx - point->fx; out_y = next->fy - point->fy; point->out_dir = af_direction_compute( out_x, out_y ); if ( point->flags & ( AF_FLAG_CONIC | AF_FLAG_CUBIC ) ) { Is_Weak_Point: point->flags |= AF_FLAG_WEAK_INTERPOLATION; } else if ( point->out_dir == point->in_dir ) { AF_Angle angle_in, angle_out, delta; if ( point->out_dir != AF_DIR_NONE ) goto Is_Weak_Point; angle_in = af_angle_atan( in_x, in_y ); angle_out = af_angle_atan( out_x, out_y ); delta = af_angle_diff( angle_in, angle_out ); if ( delta < 2 && delta > -2 ) goto Is_Weak_Point; } else if ( point->in_dir == -point->out_dir ) goto Is_Weak_Point; } } } /* compute inflection points */ af_glyph_hints_compute_inflections( hints ); Exit: return error; }
FT_Outline_EmboldenXY( FT_Outline* outline, FT_Pos xstrength, FT_Pos ystrength ) { FT_Vector* points; FT_Int c, first, last; FT_Int orientation; if ( !outline ) return FT_THROW( Invalid_Outline ); xstrength /= 2; ystrength /= 2; if ( xstrength == 0 && ystrength == 0 ) return FT_Err_Ok; orientation = FT_Outline_Get_Orientation( outline ); if ( orientation == FT_ORIENTATION_NONE ) { if ( outline->n_contours ) return FT_THROW( Invalid_Argument ); else return FT_Err_Ok; } points = outline->points; first = 0; for ( c = 0; c < outline->n_contours; c++ ) { FT_Vector in, out, anchor, shift; FT_Fixed l_in, l_out, l_anchor = 0, l, q, d; FT_Int i, j, k; l_in = 0; last = outline->contours[c]; /* pacify compiler */ in.x = in.y = anchor.x = anchor.y = 0; /* Counter j cycles though the points; counter i advances only */ /* when points are moved; anchor k marks the first moved point. */ for ( i = last, j = first, k = -1; j != i && i != k; j = j < last ? j + 1 : first ) { if ( j != k ) { out.x = points[j].x - points[i].x; out.y = points[j].y - points[i].y; l_out = (FT_Fixed)FT_Vector_NormLen( &out ); if ( l_out == 0 ) continue; } else { out = anchor; l_out = l_anchor; } if ( l_in != 0 ) { if ( k < 0 ) { k = i; anchor = in; l_anchor = l_in; } d = FT_MulFix( in.x, out.x ) + FT_MulFix( in.y, out.y ); /* shift only if turn is less than ~160 degrees */ if ( d > -0xF000L ) { d = d + 0x10000L; /* shift components along lateral bisector in proper orientation */ shift.x = in.y + out.y; shift.y = in.x + out.x; if ( orientation == FT_ORIENTATION_TRUETYPE ) shift.x = -shift.x; else shift.y = -shift.y; /* restrict shift magnitude to better handle collapsing segments */ q = FT_MulFix( out.x, in.y ) - FT_MulFix( out.y, in.x ); if ( orientation == FT_ORIENTATION_TRUETYPE ) q = -q; l = FT_MIN( l_in, l_out ); /* non-strict inequalities avoid divide-by-zero when q == l == 0 */ if ( FT_MulFix( xstrength, q ) <= FT_MulFix( l, d ) ) shift.x = FT_MulDiv( shift.x, xstrength, d ); else shift.x = FT_MulDiv( shift.x, l, q ); if ( FT_MulFix( ystrength, q ) <= FT_MulFix( l, d ) ) shift.y = FT_MulDiv( shift.y, ystrength, d ); else shift.y = FT_MulDiv( shift.y, l, q ); } else shift.x = shift.y = 0; for ( ; i != j; i = i < last ? i + 1 : first ) { points[i].x += xstrength + shift.x; points[i].y += ystrength + shift.y; } } else i = j; in = out; l_in = l_out; } first = last + 1; } return FT_Err_Ok; }
osgText::Glyph3D * FreeTypeFont::getGlyph3D(const osgText::FontResolution& fontRes, unsigned int charcode) { OpenThreads::ScopedLock<OpenThreads::Mutex> lock(FreeTypeLibrary::instance()->getMutex()); setFontResolution(fontRes); // // GT: fix for symbol fonts (i.e. the Webdings font) as the wrong character are being // returned, for symbol fonts in windows (FT_ENCONDING_MS_SYMBOL in freetype) the correct // values are from 0xF000 to 0xF0FF not from 0x000 to 0x00FF (0 to 255) as you would expect. // Microsoft uses a private field for its symbol fonts // unsigned int charindex = charcode; if (_face->charmap != NULL) { if (_face->charmap->encoding == FT_ENCODING_MS_SYMBOL) { charindex |= 0xF000; } } FT_Error error = FT_Load_Char( _face, charindex, FT_LOAD_DEFAULT|_flags ); if (error) { OSG_WARN << "FT_Load_Char(...) error 0x"<<std::hex<<error<<std::dec<<std::endl; return 0; } if (_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE) { OSG_WARN << "FreeTypeFont3D::getGlyph : not a vector font" << std::endl; return 0; } float coord_scale = getCoordScale(); // ** init FreeType to describe the glyph FreeType::Char3DInfo char3d(_facade->getNumberCurveSamples()); char3d._coord_scale = coord_scale; FT_Outline outline = _face->glyph->outline; FT_Outline_Funcs funcs; funcs.conic_to = (FT_Outline_ConicToFunc)&FreeType::conicTo; funcs.line_to = (FT_Outline_LineToFunc)&FreeType::lineTo; funcs.cubic_to = (FT_Outline_CubicToFunc)&FreeType::cubicTo; funcs.move_to = (FT_Outline_MoveToFunc)&FreeType::moveTo; funcs.shift = 0; funcs.delta = 0; FT_Orientation orientation = FT_Outline_Get_Orientation(&outline); char3d._reverseFill = (orientation == FT_ORIENTATION_POSTSCRIPT); // ** record description FT_Error _error = FT_Outline_Decompose(&outline, &funcs, &char3d); if (_error) { OSG_WARN << "FreeTypeFont3D::getGlyph : - outline decompose failed ..." << std::endl; return 0; } // ** create geometry for each part of the glyph osg::ref_ptr<osg::Geometry> frontGeo(new osg::Geometry); osg::ref_ptr<osg::Vec3Array> rawVertices = new osg::Vec3Array(*(char3d._verts)); osg::Geometry::PrimitiveSetList rawPrimitives; for(osg::Geometry::PrimitiveSetList::iterator itr = char3d.get()->getPrimitiveSetList().begin(); itr != char3d.get()->getPrimitiveSetList().end(); ++itr) { rawPrimitives.push_back(dynamic_cast<osg::PrimitiveSet*>((*itr)->clone(osg::CopyOp::DEEP_COPY_ALL))); } // ** save vertices and PrimitiveSetList of each face in the Glyph3D PrimitiveSet face list osg::ref_ptr<osgText::Glyph3D> glyph = new osgText::Glyph3D(_facade, charcode); // copy the raw primitive set list before we tessellate it. glyph->getRawFacePrimitiveSetList() = rawPrimitives; glyph->setRawVertexArray(rawVertices.get()); FT_Glyph_Metrics* metrics = &(_face->glyph->metrics); glyph->setWidth((float)metrics->width * coord_scale); glyph->setHeight((float)metrics->height * coord_scale); glyph->setHorizontalBearing(osg::Vec2((float)metrics->horiBearingX * coord_scale,(float)(metrics->horiBearingY-metrics->height) * coord_scale)); // bottom left. glyph->setHorizontalAdvance((float)metrics->horiAdvance * coord_scale); glyph->setVerticalBearing(osg::Vec2((float)metrics->vertBearingX * coord_scale,(float)(metrics->vertBearingY-metrics->height) * coord_scale)); // top middle. glyph->setVerticalAdvance((float)metrics->vertAdvance * coord_scale); #if 0 OSG_NOTICE<<"getGlyph3D("<<charcode<<", "<<char(charcode)<<")"<<std::endl; OSG_NOTICE<<" height="<<glyph->getHeight()<<std::endl; OSG_NOTICE<<" width="<<glyph->getWidth()<<std::endl; OSG_NOTICE<<" horizontalBearing="<<glyph->getHorizontalBearing()<<std::endl; OSG_NOTICE<<" horizontalAdvance="<<glyph->getHorizontalAdvance()<<std::endl; OSG_NOTICE<<" verticalBearing="<<glyph->getHorizontalBearing()<<std::endl; OSG_NOTICE<<" verticalAdvance="<<glyph->getVerticalAdvance()<<std::endl; #endif FT_BBox ftbb; FT_Outline_Get_BBox(&outline, &ftbb); osg::BoundingBox bb(float(ftbb.xMin) * coord_scale, float(ftbb.yMin) * coord_scale, 0.0f, float(ftbb.xMax) * coord_scale, float(ftbb.yMax) * coord_scale, 0.0f); glyph->setBoundingBox(bb); return glyph.release(); }
FT_Outline_EmboldenXY( FT_Outline* outline, FT_Pos xstrength, FT_Pos ystrength ) { FT_Vector* points; FT_Vector v_prev, v_first, v_next, v_cur; FT_Int c, n, first; FT_Int orientation; if ( !outline ) return FT_Err_Invalid_Argument; xstrength /= 2; ystrength /= 2; if ( xstrength == 0 && ystrength == 0 ) return FT_Err_Ok; orientation = FT_Outline_Get_Orientation( outline ); if ( orientation == FT_ORIENTATION_NONE ) { if ( outline->n_contours ) return FT_Err_Invalid_Argument; else return FT_Err_Ok; } points = outline->points; first = 0; for ( c = 0; c < outline->n_contours; c++ ) { FT_Vector in, out, shift; FT_Fixed l_in, l_out, d; int last = outline->contours[c]; v_first = points[first]; v_prev = points[last]; v_cur = v_first; /* compute the incoming vector and its length */ in.x = v_cur.x - v_prev.x; in.y = v_cur.y - v_prev.y; l_in = FT_Vector_Length( &in ); for ( n = first; n <= last; n++ ) { if ( n < last ) v_next = points[n + 1]; else v_next = v_first; /* compute the outgoing vector and its length */ out.x = v_next.x - v_cur.x; out.y = v_next.y - v_cur.y; l_out = FT_Vector_Length( &out ); d = l_in * l_out + in.x * out.x + in.y * out.y; /* shift only if turn is less then ~160 degrees */ if ( 16 * d > l_in * l_out ) { /* shift components are rotated */ shift.x = FT_DivFix( l_out * in.y + l_in * out.y, d ); shift.y = FT_DivFix( l_out * in.x + l_in * out.x, d ); if ( orientation == FT_ORIENTATION_TRUETYPE ) shift.x = -shift.x; else shift.y = -shift.y; shift.x = FT_MulFix( xstrength, shift.x ); shift.y = FT_MulFix( ystrength, shift.y ); } else shift.x = shift.y = 0; outline->points[n].x = v_cur.x + xstrength + shift.x; outline->points[n].y = v_cur.y + ystrength + shift.y; in = out; l_in = l_out; v_cur = v_next; } first = last + 1; } return FT_Err_Ok; }