00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <ft2build.h>
00027 #include FT_OUTLINE_H
00028 #include FT_INTERNAL_OBJECTS_H
00029 #include FT_INTERNAL_DEBUG_H
00030 #include FT_TRIGONOMETRY_H
00031
00032
00033
00034
00035
00036
00037
00038
00039 #undef FT_COMPONENT
00040 #define FT_COMPONENT trace_outline
00041
00042
00043 static
00044 const FT_Outline null_outline = { 0, 0, 0, 0, 0, 0 };
00045
00046
00047
00048
00049 FT_EXPORT_DEF( FT_Error )
00050 FT_Outline_Decompose( FT_Outline* outline,
00051 const FT_Outline_Funcs* func_interface,
00052 void* user )
00053 {
00054 #undef SCALED
00055 #define SCALED( x ) ( ( (x) << shift ) - delta )
00056
00057 FT_Vector v_last;
00058 FT_Vector v_control;
00059 FT_Vector v_start;
00060
00061 FT_Vector* point;
00062 FT_Vector* limit;
00063 char* tags;
00064
00065 FT_Error error;
00066
00067 FT_Int n;
00068 FT_UInt first;
00069 FT_Int tag;
00070
00071 FT_Int shift;
00072 FT_Pos delta;
00073
00074
00075 if ( !outline || !func_interface )
00076 return FT_Err_Invalid_Argument;
00077
00078 shift = func_interface->shift;
00079 delta = func_interface->delta;
00080 first = 0;
00081
00082 for ( n = 0; n < outline->n_contours; n++ )
00083 {
00084 FT_Int last;
00085
00086
00087 FT_TRACE5(( "FT_Outline_Decompose: Outline %d\n", n ));
00088
00089 last = outline->contours[n];
00090 if ( last < 0 )
00091 goto Invalid_Outline;
00092 limit = outline->points + last;
00093
00094 v_start = outline->points[first];
00095 v_start.x = SCALED( v_start.x );
00096 v_start.y = SCALED( v_start.y );
00097
00098 v_last = outline->points[last];
00099 v_last.x = SCALED( v_last.x );
00100 v_last.y = SCALED( v_last.y );
00101
00102 v_control = v_start;
00103
00104 point = outline->points + first;
00105 tags = outline->tags + first;
00106 tag = FT_CURVE_TAG( tags[0] );
00107
00108
00109 if ( tag == FT_CURVE_TAG_CUBIC )
00110 goto Invalid_Outline;
00111
00112
00113 if ( tag == FT_CURVE_TAG_CONIC )
00114 {
00115
00116 if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON )
00117 {
00118
00119 v_start = v_last;
00120 limit--;
00121 }
00122 else
00123 {
00124
00125
00126
00127 v_start.x = ( v_start.x + v_last.x ) / 2;
00128 v_start.y = ( v_start.y + v_last.y ) / 2;
00129
00130 v_last = v_start;
00131 }
00132 point--;
00133 tags--;
00134 }
00135
00136 FT_TRACE5(( " move to (%.2f, %.2f)\n",
00137 v_start.x / 64.0, v_start.y / 64.0 ));
00138 error = func_interface->move_to( &v_start, user );
00139 if ( error )
00140 goto Exit;
00141
00142 while ( point < limit )
00143 {
00144 point++;
00145 tags++;
00146
00147 tag = FT_CURVE_TAG( tags[0] );
00148 switch ( tag )
00149 {
00150 case FT_CURVE_TAG_ON:
00151 {
00152 FT_Vector vec;
00153
00154
00155 vec.x = SCALED( point->x );
00156 vec.y = SCALED( point->y );
00157
00158 FT_TRACE5(( " line to (%.2f, %.2f)\n",
00159 vec.x / 64.0, vec.y / 64.0 ));
00160 error = func_interface->line_to( &vec, user );
00161 if ( error )
00162 goto Exit;
00163 continue;
00164 }
00165
00166 case FT_CURVE_TAG_CONIC:
00167 v_control.x = SCALED( point->x );
00168 v_control.y = SCALED( point->y );
00169
00170 Do_Conic:
00171 if ( point < limit )
00172 {
00173 FT_Vector vec;
00174 FT_Vector v_middle;
00175
00176
00177 point++;
00178 tags++;
00179 tag = FT_CURVE_TAG( tags[0] );
00180
00181 vec.x = SCALED( point->x );
00182 vec.y = SCALED( point->y );
00183
00184 if ( tag == FT_CURVE_TAG_ON )
00185 {
00186 FT_TRACE5(( " conic to (%.2f, %.2f)"
00187 " with control (%.2f, %.2f)\n",
00188 vec.x / 64.0, vec.y / 64.0,
00189 v_control.x / 64.0, v_control.y / 64.0 ));
00190 error = func_interface->conic_to( &v_control, &vec, user );
00191 if ( error )
00192 goto Exit;
00193 continue;
00194 }
00195
00196 if ( tag != FT_CURVE_TAG_CONIC )
00197 goto Invalid_Outline;
00198
00199 v_middle.x = ( v_control.x + vec.x ) / 2;
00200 v_middle.y = ( v_control.y + vec.y ) / 2;
00201
00202 FT_TRACE5(( " conic to (%.2f, %.2f)"
00203 " with control (%.2f, %.2f)\n",
00204 v_middle.x / 64.0, v_middle.y / 64.0,
00205 v_control.x / 64.0, v_control.y / 64.0 ));
00206 error = func_interface->conic_to( &v_control, &v_middle, user );
00207 if ( error )
00208 goto Exit;
00209
00210 v_control = vec;
00211 goto Do_Conic;
00212 }
00213
00214 FT_TRACE5(( " conic to (%.2f, %.2f)"
00215 " with control (%.2f, %.2f)\n",
00216 v_start.x / 64.0, v_start.y / 64.0,
00217 v_control.x / 64.0, v_control.y / 64.0 ));
00218 error = func_interface->conic_to( &v_control, &v_start, user );
00219 goto Close;
00220
00221 default:
00222 {
00223 FT_Vector vec1, vec2;
00224
00225
00226 if ( point + 1 > limit ||
00227 FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )
00228 goto Invalid_Outline;
00229
00230 point += 2;
00231 tags += 2;
00232
00233 vec1.x = SCALED( point[-2].x );
00234 vec1.y = SCALED( point[-2].y );
00235
00236 vec2.x = SCALED( point[-1].x );
00237 vec2.y = SCALED( point[-1].y );
00238
00239 if ( point <= limit )
00240 {
00241 FT_Vector vec;
00242
00243
00244 vec.x = SCALED( point->x );
00245 vec.y = SCALED( point->y );
00246
00247 FT_TRACE5(( " cubic to (%.2f, %.2f)"
00248 " with controls (%.2f, %.2f) and (%.2f, %.2f)\n",
00249 vec.x / 64.0, vec.y / 64.0,
00250 vec1.x / 64.0, vec1.y / 64.0,
00251 vec2.x / 64.0, vec2.y / 64.0 ));
00252 error = func_interface->cubic_to( &vec1, &vec2, &vec, user );
00253 if ( error )
00254 goto Exit;
00255 continue;
00256 }
00257
00258 FT_TRACE5(( " cubic to (%.2f, %.2f)"
00259 " with controls (%.2f, %.2f) and (%.2f, %.2f)\n",
00260 v_start.x / 64.0, v_start.y / 64.0,
00261 vec1.x / 64.0, vec1.y / 64.0,
00262 vec2.x / 64.0, vec2.y / 64.0 ));
00263 error = func_interface->cubic_to( &vec1, &vec2, &v_start, user );
00264 goto Close;
00265 }
00266 }
00267 }
00268
00269
00270 FT_TRACE5(( " line to (%.2f, %.2f)\n",
00271 v_start.x / 64.0, v_start.y / 64.0 ));
00272 error = func_interface->line_to( &v_start, user );
00273
00274 Close:
00275 if ( error )
00276 goto Exit;
00277
00278 first = last + 1;
00279 }
00280
00281 FT_TRACE5(( "FT_Outline_Decompose: Done\n", n ));
00282 return FT_Err_Ok;
00283
00284 Exit:
00285 FT_TRACE5(( "FT_Outline_Decompose: Error %d\n", error ));
00286 return error;
00287
00288 Invalid_Outline:
00289 return FT_Err_Invalid_Outline;
00290 }
00291
00292
00293 FT_EXPORT_DEF( FT_Error )
00294 FT_Outline_New_Internal( FT_Memory memory,
00295 FT_UInt numPoints,
00296 FT_Int numContours,
00297 FT_Outline *anoutline )
00298 {
00299 FT_Error error;
00300
00301
00302 if ( !anoutline || !memory )
00303 return FT_Err_Invalid_Argument;
00304
00305 *anoutline = null_outline;
00306
00307 if ( FT_NEW_ARRAY( anoutline->points, numPoints ) ||
00308 FT_NEW_ARRAY( anoutline->tags, numPoints ) ||
00309 FT_NEW_ARRAY( anoutline->contours, numContours ) )
00310 goto Fail;
00311
00312 anoutline->n_points = (FT_UShort)numPoints;
00313 anoutline->n_contours = (FT_Short)numContours;
00314 anoutline->flags |= FT_OUTLINE_OWNER;
00315
00316 return FT_Err_Ok;
00317
00318 Fail:
00319 anoutline->flags |= FT_OUTLINE_OWNER;
00320 FT_Outline_Done_Internal( memory, anoutline );
00321
00322 return error;
00323 }
00324
00325
00326
00327
00328 FT_EXPORT_DEF( FT_Error )
00329 FT_Outline_New( FT_Library library,
00330 FT_UInt numPoints,
00331 FT_Int numContours,
00332 FT_Outline *anoutline )
00333 {
00334 if ( !library )
00335 return FT_Err_Invalid_Library_Handle;
00336
00337 return FT_Outline_New_Internal( library->memory, numPoints,
00338 numContours, anoutline );
00339 }
00340
00341
00342
00343
00344 FT_EXPORT_DEF( FT_Error )
00345 FT_Outline_Check( FT_Outline* outline )
00346 {
00347 if ( outline )
00348 {
00349 FT_Int n_points = outline->n_points;
00350 FT_Int n_contours = outline->n_contours;
00351 FT_Int end0, end;
00352 FT_Int n;
00353
00354
00355
00356 if ( n_points == 0 && n_contours == 0 )
00357 return 0;
00358
00359
00360 if ( n_points <= 0 || n_contours <= 0 )
00361 goto Bad;
00362
00363 end0 = end = -1;
00364 for ( n = 0; n < n_contours; n++ )
00365 {
00366 end = outline->contours[n];
00367
00368
00369 if ( end <= end0 || end >= n_points )
00370 goto Bad;
00371
00372 end0 = end;
00373 }
00374
00375 if ( end != n_points - 1 )
00376 goto Bad;
00377
00378
00379 return 0;
00380 }
00381
00382 Bad:
00383 return FT_Err_Invalid_Argument;
00384 }
00385
00386
00387
00388
00389 FT_EXPORT_DEF( FT_Error )
00390 FT_Outline_Copy( const FT_Outline* source,
00391 FT_Outline *target )
00392 {
00393 FT_Int is_owner;
00394
00395
00396 if ( !source || !target ||
00397 source->n_points != target->n_points ||
00398 source->n_contours != target->n_contours )
00399 return FT_Err_Invalid_Argument;
00400
00401 if ( source == target )
00402 return FT_Err_Ok;
00403
00404 FT_ARRAY_COPY( target->points, source->points, source->n_points );
00405
00406 FT_ARRAY_COPY( target->tags, source->tags, source->n_points );
00407
00408 FT_ARRAY_COPY( target->contours, source->contours, source->n_contours );
00409
00410
00411 is_owner = target->flags & FT_OUTLINE_OWNER;
00412 target->flags = source->flags;
00413
00414 target->flags &= ~FT_OUTLINE_OWNER;
00415 target->flags |= is_owner;
00416
00417 return FT_Err_Ok;
00418 }
00419
00420
00421 FT_EXPORT_DEF( FT_Error )
00422 FT_Outline_Done_Internal( FT_Memory memory,
00423 FT_Outline* outline )
00424 {
00425 if ( memory && outline )
00426 {
00427 if ( outline->flags & FT_OUTLINE_OWNER )
00428 {
00429 FT_FREE( outline->points );
00430 FT_FREE( outline->tags );
00431 FT_FREE( outline->contours );
00432 }
00433 *outline = null_outline;
00434
00435 return FT_Err_Ok;
00436 }
00437 else
00438 return FT_Err_Invalid_Argument;
00439 }
00440
00441
00442
00443
00444 FT_EXPORT_DEF( FT_Error )
00445 FT_Outline_Done( FT_Library library,
00446 FT_Outline* outline )
00447 {
00448
00449
00450 if ( !library )
00451 return FT_Err_Invalid_Library_Handle;
00452
00453 return FT_Outline_Done_Internal( library->memory, outline );
00454 }
00455
00456
00457
00458
00459 FT_EXPORT_DEF( void )
00460 FT_Outline_Get_CBox( const FT_Outline* outline,
00461 FT_BBox *acbox )
00462 {
00463 FT_Pos xMin, yMin, xMax, yMax;
00464
00465
00466 if ( outline && acbox )
00467 {
00468 if ( outline->n_points == 0 )
00469 {
00470 xMin = 0;
00471 yMin = 0;
00472 xMax = 0;
00473 yMax = 0;
00474 }
00475 else
00476 {
00477 FT_Vector* vec = outline->points;
00478 FT_Vector* limit = vec + outline->n_points;
00479
00480
00481 xMin = xMax = vec->x;
00482 yMin = yMax = vec->y;
00483 vec++;
00484
00485 for ( ; vec < limit; vec++ )
00486 {
00487 FT_Pos x, y;
00488
00489
00490 x = vec->x;
00491 if ( x < xMin ) xMin = x;
00492 if ( x > xMax ) xMax = x;
00493
00494 y = vec->y;
00495 if ( y < yMin ) yMin = y;
00496 if ( y > yMax ) yMax = y;
00497 }
00498 }
00499 acbox->xMin = xMin;
00500 acbox->xMax = xMax;
00501 acbox->yMin = yMin;
00502 acbox->yMax = yMax;
00503 }
00504 }
00505
00506
00507
00508
00509 FT_EXPORT_DEF( void )
00510 FT_Outline_Translate( const FT_Outline* outline,
00511 FT_Pos xOffset,
00512 FT_Pos yOffset )
00513 {
00514 FT_UShort n;
00515 FT_Vector* vec;
00516
00517
00518 if ( !outline )
00519 return;
00520
00521 vec = outline->points;
00522
00523 for ( n = 0; n < outline->n_points; n++ )
00524 {
00525 vec->x += xOffset;
00526 vec->y += yOffset;
00527 vec++;
00528 }
00529 }
00530
00531
00532
00533
00534 FT_EXPORT_DEF( void )
00535 FT_Outline_Reverse( FT_Outline* outline )
00536 {
00537 FT_UShort n;
00538 FT_Int first, last;
00539
00540
00541 if ( !outline )
00542 return;
00543
00544 first = 0;
00545
00546 for ( n = 0; n < outline->n_contours; n++ )
00547 {
00548 last = outline->contours[n];
00549
00550
00551 {
00552 FT_Vector* p = outline->points + first;
00553 FT_Vector* q = outline->points + last;
00554 FT_Vector swap;
00555
00556
00557 while ( p < q )
00558 {
00559 swap = *p;
00560 *p = *q;
00561 *q = swap;
00562 p++;
00563 q--;
00564 }
00565 }
00566
00567
00568 {
00569 char* p = outline->tags + first;
00570 char* q = outline->tags + last;
00571 char swap;
00572
00573
00574 while ( p < q )
00575 {
00576 swap = *p;
00577 *p = *q;
00578 *q = swap;
00579 p++;
00580 q--;
00581 }
00582 }
00583
00584 first = last + 1;
00585 }
00586
00587 outline->flags ^= FT_OUTLINE_REVERSE_FILL;
00588 }
00589
00590
00591
00592
00593 FT_EXPORT_DEF( FT_Error )
00594 FT_Outline_Render( FT_Library library,
00595 FT_Outline* outline,
00596 FT_Raster_Params* params )
00597 {
00598 FT_Error error;
00599 FT_Bool update = FALSE;
00600 FT_Renderer renderer;
00601 FT_ListNode node;
00602
00603
00604 if ( !library )
00605 return FT_Err_Invalid_Library_Handle;
00606
00607 if ( !outline || !params )
00608 return FT_Err_Invalid_Argument;
00609
00610 renderer = library->cur_renderer;
00611 node = library->renderers.head;
00612
00613 params->source = (void*)outline;
00614
00615 error = FT_Err_Cannot_Render_Glyph;
00616 while ( renderer )
00617 {
00618 error = renderer->raster_render( renderer->raster, params );
00619 if ( !error || FT_ERROR_BASE( error ) != FT_Err_Cannot_Render_Glyph )
00620 break;
00621
00622
00623
00624
00625
00626
00627
00628 renderer = FT_Lookup_Renderer( library, FT_GLYPH_FORMAT_OUTLINE,
00629 &node );
00630 update = TRUE;
00631 }
00632
00633
00634
00635 if ( !error && update && renderer )
00636 FT_Set_Renderer( library, renderer, 0, 0 );
00637
00638 return error;
00639 }
00640
00641
00642
00643
00644 FT_EXPORT_DEF( FT_Error )
00645 FT_Outline_Get_Bitmap( FT_Library library,
00646 FT_Outline* outline,
00647 const FT_Bitmap *abitmap )
00648 {
00649 FT_Raster_Params params;
00650
00651
00652 if ( !abitmap )
00653 return FT_Err_Invalid_Argument;
00654
00655
00656
00657 params.target = abitmap;
00658 params.flags = 0;
00659
00660 if ( abitmap->pixel_mode == FT_PIXEL_MODE_GRAY ||
00661 abitmap->pixel_mode == FT_PIXEL_MODE_LCD ||
00662 abitmap->pixel_mode == FT_PIXEL_MODE_LCD_V )
00663 params.flags |= FT_RASTER_FLAG_AA;
00664
00665 return FT_Outline_Render( library, outline, ¶ms );
00666 }
00667
00668
00669
00670
00671 FT_EXPORT_DEF( void )
00672 FT_Vector_Transform( FT_Vector* vector,
00673 const FT_Matrix* matrix )
00674 {
00675 FT_Pos xz, yz;
00676
00677
00678 if ( !vector || !matrix )
00679 return;
00680
00681 xz = FT_MulFix( vector->x, matrix->xx ) +
00682 FT_MulFix( vector->y, matrix->xy );
00683
00684 yz = FT_MulFix( vector->x, matrix->yx ) +
00685 FT_MulFix( vector->y, matrix->yy );
00686
00687 vector->x = xz;
00688 vector->y = yz;
00689 }
00690
00691
00692
00693
00694 FT_EXPORT_DEF( void )
00695 FT_Outline_Transform( const FT_Outline* outline,
00696 const FT_Matrix* matrix )
00697 {
00698 FT_Vector* vec;
00699 FT_Vector* limit;
00700
00701
00702 if ( !outline || !matrix )
00703 return;
00704
00705 vec = outline->points;
00706 limit = vec + outline->n_points;
00707
00708 for ( ; vec < limit; vec++ )
00709 FT_Vector_Transform( vec, matrix );
00710 }
00711
00712
00713 #if 0
00714
00715 #define FT_OUTLINE_GET_CONTOUR( outline, c, first, last ) \
00716 do { \
00717 (first) = ( c > 0 ) ? (outline)->points + \
00718 (outline)->contours[c - 1] + 1 \
00719 : (outline)->points; \
00720 (last) = (outline)->points + (outline)->contours[c]; \
00721 } while ( 0 )
00722
00723
00724
00725
00726
00727
00728
00729 static FT_Bool
00730 ft_contour_has( FT_Outline* outline,
00731 FT_Short c,
00732 FT_Vector* point )
00733 {
00734 FT_Vector* first;
00735 FT_Vector* last;
00736 FT_Vector* a;
00737 FT_Vector* b;
00738 FT_UInt n = 0;
00739
00740
00741 FT_OUTLINE_GET_CONTOUR( outline, c, first, last );
00742
00743 for ( a = first; a <= last; a++ )
00744 {
00745 FT_Pos x;
00746 FT_Int intersect;
00747
00748
00749 b = ( a == last ) ? first : a + 1;
00750
00751 intersect = ( a->y - point->y ) ^ ( b->y - point->y );
00752
00753
00754 if ( intersect >= 0 )
00755 {
00756 if ( intersect == 0 && a->y == point->y )
00757 {
00758 if ( ( a->x <= point->x && b->x >= point->x ) ||
00759 ( a->x >= point->x && b->x <= point->x ) )
00760 return 1;
00761 }
00762
00763 continue;
00764 }
00765
00766 x = a->x + ( b->x - a->x ) * (point->y - a->y ) / ( b->y - a->y );
00767
00768 if ( x < point->x )
00769 n++;
00770 else if ( x == point->x )
00771 return 1;
00772 }
00773
00774 return ( n % 2 );
00775 }
00776
00777
00778 static FT_Bool
00779 ft_contour_enclosed( FT_Outline* outline,
00780 FT_UShort c )
00781 {
00782 FT_Vector* first;
00783 FT_Vector* last;
00784 FT_Short i;
00785
00786
00787 FT_OUTLINE_GET_CONTOUR( outline, c, first, last );
00788
00789 for ( i = 0; i < outline->n_contours; i++ )
00790 {
00791 if ( i != c && ft_contour_has( outline, i, first ) )
00792 {
00793 FT_Vector* pt;
00794
00795
00796 for ( pt = first + 1; pt <= last; pt++ )
00797 if ( !ft_contour_has( outline, i, pt ) )
00798 return 0;
00799
00800 return 1;
00801 }
00802 }
00803
00804 return 0;
00805 }
00806
00807
00808
00809
00810
00811
00812 static FT_Orientation
00813 ft_outline_get_orientation( FT_Outline* outline )
00814 {
00815 FT_Short i;
00816 FT_Vector* first;
00817 FT_Vector* last;
00818 FT_Orientation orient = FT_ORIENTATION_NONE;
00819
00820
00821 first = outline->points;
00822 for ( i = 0; i < outline->n_contours; i++, first = last + 1 )
00823 {
00824 FT_Vector* point;
00825 FT_Vector* xmin_point;
00826 FT_Pos xmin;
00827
00828
00829 last = outline->points + outline->contours[i];
00830
00831
00832 if ( last < first + 2 )
00833 continue;
00834
00835 if ( ft_contour_enclosed( outline, i ) )
00836 continue;
00837
00838 xmin = first->x;
00839 xmin_point = first;
00840
00841 for ( point = first + 1; point <= last; point++ )
00842 {
00843 if ( point->x < xmin )
00844 {
00845 xmin = point->x;
00846 xmin_point = point;
00847 }
00848 }
00849
00850
00851 {
00852 FT_Vector* prev;
00853 FT_Vector* next;
00854 FT_Orientation o;
00855
00856
00857 prev = ( xmin_point == first ) ? last : xmin_point - 1;
00858 next = ( xmin_point == last ) ? first : xmin_point + 1;
00859
00860 if ( FT_Atan2( prev->x - xmin_point->x, prev->y - xmin_point->y ) >
00861 FT_Atan2( next->x - xmin_point->x, next->y - xmin_point->y ) )
00862 o = FT_ORIENTATION_POSTSCRIPT;
00863 else
00864 o = FT_ORIENTATION_TRUETYPE;
00865
00866 if ( orient == FT_ORIENTATION_NONE )
00867 orient = o;
00868 else if ( orient != o )
00869 return FT_ORIENTATION_NONE;
00870 }
00871 }
00872
00873 return orient;
00874 }
00875
00876 #endif
00877
00878
00879
00880
00881 FT_EXPORT_DEF( FT_Error )
00882 FT_Outline_Embolden( FT_Outline* outline,
00883 FT_Pos strength )
00884 {
00885 FT_Vector* points;
00886 FT_Vector v_prev, v_first, v_next, v_cur;
00887 FT_Angle rotate, angle_in, angle_out;
00888 FT_Int c, n, first;
00889 FT_Int orientation;
00890
00891
00892 if ( !outline )
00893 return FT_Err_Invalid_Argument;
00894
00895 strength /= 2;
00896 if ( strength == 0 )
00897 return FT_Err_Ok;
00898
00899 orientation = FT_Outline_Get_Orientation( outline );
00900 if ( orientation == FT_ORIENTATION_NONE )
00901 {
00902 if ( outline->n_contours )
00903 return FT_Err_Invalid_Argument;
00904 else
00905 return FT_Err_Ok;
00906 }
00907
00908 if ( orientation == FT_ORIENTATION_TRUETYPE )
00909 rotate = -FT_ANGLE_PI2;
00910 else
00911 rotate = FT_ANGLE_PI2;
00912
00913 points = outline->points;
00914
00915 first = 0;
00916 for ( c = 0; c < outline->n_contours; c++ )
00917 {
00918 int last = outline->contours[c];
00919
00920
00921 v_first = points[first];
00922 v_prev = points[last];
00923 v_cur = v_first;
00924
00925 for ( n = first; n <= last; n++ )
00926 {
00927 FT_Vector in, out;
00928 FT_Angle angle_diff;
00929 FT_Pos d;
00930 FT_Fixed scale;
00931
00932
00933 if ( n < last )
00934 v_next = points[n + 1];
00935 else
00936 v_next = v_first;
00937
00938
00939 in.x = v_cur.x - v_prev.x;
00940 in.y = v_cur.y - v_prev.y;
00941
00942 out.x = v_next.x - v_cur.x;
00943 out.y = v_next.y - v_cur.y;
00944
00945 angle_in = FT_Atan2( in.x, in.y );
00946 angle_out = FT_Atan2( out.x, out.y );
00947 angle_diff = FT_Angle_Diff( angle_in, angle_out );
00948 scale = FT_Cos( angle_diff / 2 );
00949
00950 if ( scale < 0x4000L && scale > -0x4000L )
00951 in.x = in.y = 0;
00952 else
00953 {
00954 d = FT_DivFix( strength, scale );
00955
00956 FT_Vector_From_Polar( &in, d, angle_in + angle_diff / 2 - rotate );
00957 }
00958
00959 outline->points[n].x = v_cur.x + strength + in.x;
00960 outline->points[n].y = v_cur.y + strength + in.y;
00961
00962 v_prev = v_cur;
00963 v_cur = v_next;
00964 }
00965
00966 first = last + 1;
00967 }
00968
00969 return FT_Err_Ok;
00970 }
00971
00972
00973
00974
00975 FT_EXPORT_DEF( FT_Orientation )
00976 FT_Outline_Get_Orientation( FT_Outline* outline )
00977 {
00978 FT_Pos xmin = 32768L;
00979 FT_Pos xmin_ymin = 32768L;
00980 FT_Pos xmin_ymax = -32768L;
00981 FT_Vector* xmin_first = NULL;
00982 FT_Vector* xmin_last = NULL;
00983
00984 short* contour;
00985
00986 FT_Vector* first;
00987 FT_Vector* last;
00988 FT_Vector* prev;
00989 FT_Vector* point;
00990
00991 int i;
00992 FT_Pos ray_y[3];
00993 FT_Orientation result[3];
00994
00995
00996 if ( !outline || outline->n_points <= 0 )
00997 return FT_ORIENTATION_TRUETYPE;
00998
00999
01000
01001
01002
01003
01004 first = outline->points;
01005 for ( contour = outline->contours;
01006 contour < outline->contours + outline->n_contours;
01007 contour++, first = last + 1 )
01008 {
01009 FT_Pos contour_xmin = 32768L;
01010 FT_Pos contour_xmax = -32768L;
01011 FT_Pos contour_ymin = 32768L;
01012 FT_Pos contour_ymax = -32768L;
01013
01014
01015 last = outline->points + *contour;
01016
01017
01018 if ( last < first + 2 )
01019 continue;
01020
01021 for ( point = first; point <= last; ++point )
01022 {
01023 if ( point->x < contour_xmin )
01024 contour_xmin = point->x;
01025
01026 if ( point->x > contour_xmax )
01027 contour_xmax = point->x;
01028
01029 if ( point->y < contour_ymin )
01030 contour_ymin = point->y;
01031
01032 if ( point->y > contour_ymax )
01033 contour_ymax = point->y;
01034 }
01035
01036 if ( contour_xmin < xmin &&
01037 contour_xmin != contour_xmax &&
01038 contour_ymin != contour_ymax )
01039 {
01040 xmin = contour_xmin;
01041 xmin_ymin = contour_ymin;
01042 xmin_ymax = contour_ymax;
01043 xmin_first = first;
01044 xmin_last = last;
01045 }
01046 }
01047
01048 if ( xmin == 32768L )
01049 return FT_ORIENTATION_TRUETYPE;
01050
01051 ray_y[0] = ( xmin_ymin * 3 + xmin_ymax ) >> 2;
01052 ray_y[1] = ( xmin_ymin + xmin_ymax ) >> 1;
01053 ray_y[2] = ( xmin_ymin + xmin_ymax * 3 ) >> 2;
01054
01055 for ( i = 0; i < 3; i++ )
01056 {
01057 FT_Pos left_x;
01058 FT_Pos right_x;
01059 FT_Vector* left1;
01060 FT_Vector* left2;
01061 FT_Vector* right1;
01062 FT_Vector* right2;
01063
01064
01065 RedoRay:
01066 left_x = 32768L;
01067 right_x = -32768L;
01068
01069 left1 = left2 = right1 = right2 = NULL;
01070
01071 prev = xmin_last;
01072 for ( point = xmin_first; point <= xmin_last; prev = point, ++point )
01073 {
01074 FT_Pos tmp_x;
01075
01076
01077 if ( point->y == ray_y[i] || prev->y == ray_y[i] )
01078 {
01079 ray_y[i]++;
01080 goto RedoRay;
01081 }
01082
01083 if ( ( point->y < ray_y[i] && prev->y < ray_y[i] ) ||
01084 ( point->y > ray_y[i] && prev->y > ray_y[i] ) )
01085 continue;
01086
01087 tmp_x = FT_MulDiv( point->x - prev->x,
01088 ray_y[i] - prev->y,
01089 point->y - prev->y ) + prev->x;
01090
01091 if ( tmp_x < left_x )
01092 {
01093 left_x = tmp_x;
01094 left1 = prev;
01095 left2 = point;
01096 }
01097
01098 if ( tmp_x > right_x )
01099 {
01100 right_x = tmp_x;
01101 right1 = prev;
01102 right2 = point;
01103 }
01104 }
01105
01106 if ( left1 && right1 )
01107 {
01108 if ( left1->y < left2->y && right1->y > right2->y )
01109 result[i] = FT_ORIENTATION_TRUETYPE;
01110 else if ( left1->y > left2->y && right1->y < right2->y )
01111 result[i] = FT_ORIENTATION_POSTSCRIPT;
01112 else
01113 result[i] = FT_ORIENTATION_NONE;
01114 }
01115 }
01116
01117 if ( result[0] != FT_ORIENTATION_NONE &&
01118 ( result[0] == result[1] || result[0] == result[2] ) )
01119 return result[0];
01120
01121 if ( result[1] != FT_ORIENTATION_NONE && result[1] == result[2] )
01122 return result[1];
01123
01124 return FT_ORIENTATION_TRUETYPE;
01125 }
01126
01127
01128