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
00027 #include <ft2build.h>
00028 #include FT_BBOX_H
00029 #include FT_IMAGE_H
00030 #include FT_OUTLINE_H
00031 #include FT_INTERNAL_CALC_H
00032 #include FT_INTERNAL_OBJECTS_H
00033
00034
00035 typedef struct TBBox_Rec_
00036 {
00037 FT_Vector last;
00038 FT_BBox bbox;
00039
00040 } TBBox_Rec;
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063 static int
00064 BBox_Move_To( FT_Vector* to,
00065 TBBox_Rec* user )
00066 {
00067 user->last = *to;
00068
00069 return 0;
00070 }
00071
00072
00073 #define CHECK_X( p, bbox ) \
00074 ( p->x < bbox.xMin || p->x > bbox.xMax )
00075
00076 #define CHECK_Y( p, bbox ) \
00077 ( p->y < bbox.yMin || p->y > bbox.yMax )
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102 static void
00103 BBox_Conic_Check( FT_Pos y1,
00104 FT_Pos y2,
00105 FT_Pos y3,
00106 FT_Pos* min,
00107 FT_Pos* max )
00108 {
00109 if ( y1 <= y3 && y2 == y1 )
00110 goto Suite;
00111
00112 if ( y1 < y3 )
00113 {
00114 if ( y2 >= y1 && y2 <= y3 )
00115 goto Suite;
00116 }
00117 else
00118 {
00119 if ( y2 >= y3 && y2 <= y1 )
00120 {
00121 y2 = y1;
00122 y1 = y3;
00123 y3 = y2;
00124 goto Suite;
00125 }
00126 }
00127
00128 y1 = y3 = y1 - FT_MulDiv( y2 - y1, y2 - y1, y1 - 2*y2 + y3 );
00129
00130 Suite:
00131 if ( y1 < *min ) *min = y1;
00132 if ( y3 > *max ) *max = y3;
00133 }
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162 static int
00163 BBox_Conic_To( FT_Vector* control,
00164 FT_Vector* to,
00165 TBBox_Rec* user )
00166 {
00167
00168
00169
00170 if ( CHECK_X( control, user->bbox ) )
00171 BBox_Conic_Check( user->last.x,
00172 control->x,
00173 to->x,
00174 &user->bbox.xMin,
00175 &user->bbox.xMax );
00176
00177 if ( CHECK_Y( control, user->bbox ) )
00178 BBox_Conic_Check( user->last.y,
00179 control->y,
00180 to->y,
00181 &user->bbox.yMin,
00182 &user->bbox.yMax );
00183
00184 user->last = *to;
00185
00186 return 0;
00187 }
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215 #if 0
00216
00217 static void
00218 BBox_Cubic_Check( FT_Pos p1,
00219 FT_Pos p2,
00220 FT_Pos p3,
00221 FT_Pos p4,
00222 FT_Pos* min,
00223 FT_Pos* max )
00224 {
00225 FT_Pos stack[32*3 + 1], *arc;
00226
00227
00228 arc = stack;
00229
00230 arc[0] = p1;
00231 arc[1] = p2;
00232 arc[2] = p3;
00233 arc[3] = p4;
00234
00235 do
00236 {
00237 FT_Pos y1 = arc[0];
00238 FT_Pos y2 = arc[1];
00239 FT_Pos y3 = arc[2];
00240 FT_Pos y4 = arc[3];
00241
00242
00243 if ( y1 == y4 )
00244 {
00245 if ( y1 == y2 && y1 == y3 )
00246 goto Test;
00247 }
00248 else if ( y1 < y4 )
00249 {
00250 if ( y2 >= y1 && y2 <= y4 && y3 >= y1 && y3 <= y4 )
00251 goto Test;
00252 }
00253 else
00254 {
00255 if ( y2 >= y4 && y2 <= y1 && y3 >= y4 && y3 <= y1 )
00256 {
00257 y2 = y1;
00258 y1 = y4;
00259 y4 = y2;
00260 goto Test;
00261 }
00262 }
00263
00264
00265 arc[6] = y4;
00266 arc[1] = y1 = ( y1 + y2 ) / 2;
00267 arc[5] = y4 = ( y4 + y3 ) / 2;
00268 y2 = ( y2 + y3 ) / 2;
00269 arc[2] = y1 = ( y1 + y2 ) / 2;
00270 arc[4] = y4 = ( y4 + y2 ) / 2;
00271 arc[3] = ( y1 + y4 ) / 2;
00272
00273 arc += 3;
00274 goto Suite;
00275
00276 Test:
00277 if ( y1 < *min ) *min = y1;
00278 if ( y4 > *max ) *max = y4;
00279 arc -= 3;
00280
00281 Suite:
00282 ;
00283 } while ( arc >= stack );
00284 }
00285
00286 #else
00287
00288 static void
00289 test_cubic_extrema( FT_Pos y1,
00290 FT_Pos y2,
00291 FT_Pos y3,
00292 FT_Pos y4,
00293 FT_Fixed u,
00294 FT_Pos* min,
00295 FT_Pos* max )
00296 {
00297
00298 FT_Pos b = y3 - 2*y2 + y1;
00299 FT_Pos c = y2 - y1;
00300 FT_Pos d = y1;
00301 FT_Pos y;
00302 FT_Fixed uu;
00303
00304 FT_UNUSED ( y4 );
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321 if ( u > 0 && u < 0x10000L )
00322 {
00323 uu = FT_MulFix( u, u );
00324 y = d + FT_MulFix( c, 2*u ) + FT_MulFix( b, uu );
00325
00326 if ( y < *min ) *min = y;
00327 if ( y > *max ) *max = y;
00328 }
00329 }
00330
00331
00332 static void
00333 BBox_Cubic_Check( FT_Pos y1,
00334 FT_Pos y2,
00335 FT_Pos y3,
00336 FT_Pos y4,
00337 FT_Pos* min,
00338 FT_Pos* max )
00339 {
00340
00341 if ( y1 < *min ) *min = y1;
00342 else if ( y1 > *max ) *max = y1;
00343
00344 if ( y4 < *min ) *min = y4;
00345 else if ( y4 > *max ) *max = y4;
00346
00347
00348 if ( y1 <= y4 )
00349 {
00350
00351 if ( y1 <= y2 && y2 <= y4 && y1 <= y3 && y3 <= y4 )
00352 return;
00353 }
00354 else
00355 {
00356
00357 if ( y1 >= y2 && y2 >= y4 && y1 >= y3 && y3 >= y4 )
00358 return;
00359 }
00360
00361
00362 {
00363 FT_Pos a = y4 - 3*y3 + 3*y2 - y1;
00364 FT_Pos b = y3 - 2*y2 + y1;
00365 FT_Pos c = y2 - y1;
00366 FT_Pos d;
00367 FT_Fixed t;
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380 {
00381 FT_ULong t1, t2;
00382 int shift = 0;
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403 t1 = (FT_ULong)( ( a >= 0 ) ? a : -a );
00404 t2 = (FT_ULong)( ( b >= 0 ) ? b : -b );
00405 t1 |= t2;
00406 t2 = (FT_ULong)( ( c >= 0 ) ? c : -c );
00407 t1 |= t2;
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431 if ( t1 == 0 )
00432 return;
00433
00434 if ( t1 > 0x7FFFFFUL )
00435 {
00436 do
00437 {
00438 shift++;
00439 t1 >>= 1;
00440
00441 } while ( t1 > 0x7FFFFFUL );
00442
00443
00444
00445 a >>= shift;
00446 b >>= shift;
00447 c >>= shift;
00448 }
00449 else if ( t1 < 0x400000UL )
00450 {
00451 do
00452 {
00453 shift++;
00454 t1 <<= 1;
00455
00456 } while ( t1 < 0x400000UL );
00457
00458 a <<= shift;
00459 b <<= shift;
00460 c <<= shift;
00461 }
00462 }
00463
00464
00465 if ( a == 0 )
00466 {
00467 if ( b != 0 )
00468 {
00469 t = - FT_DivFix( c, b ) / 2;
00470 test_cubic_extrema( y1, y2, y3, y4, t, min, max );
00471 }
00472 }
00473 else
00474 {
00475
00476 d = FT_MulFix( b, b ) - FT_MulFix( a, c );
00477 if ( d < 0 )
00478 return;
00479
00480 if ( d == 0 )
00481 {
00482
00483 t = - FT_DivFix( b, a );
00484 test_cubic_extrema( y1, y2, y3, y4, t, min, max );
00485 }
00486 else
00487 {
00488
00489 d = FT_SqrtFixed( (FT_Int32)d );
00490 t = - FT_DivFix( b - d, a );
00491 test_cubic_extrema( y1, y2, y3, y4, t, min, max );
00492
00493 t = - FT_DivFix( b + d, a );
00494 test_cubic_extrema( y1, y2, y3, y4, t, min, max );
00495 }
00496 }
00497 }
00498 }
00499
00500 #endif
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531 static int
00532 BBox_Cubic_To( FT_Vector* control1,
00533 FT_Vector* control2,
00534 FT_Vector* to,
00535 TBBox_Rec* user )
00536 {
00537
00538
00539
00540 if ( CHECK_X( control1, user->bbox ) ||
00541 CHECK_X( control2, user->bbox ) )
00542 BBox_Cubic_Check( user->last.x,
00543 control1->x,
00544 control2->x,
00545 to->x,
00546 &user->bbox.xMin,
00547 &user->bbox.xMax );
00548
00549 if ( CHECK_Y( control1, user->bbox ) ||
00550 CHECK_Y( control2, user->bbox ) )
00551 BBox_Cubic_Check( user->last.y,
00552 control1->y,
00553 control2->y,
00554 to->y,
00555 &user->bbox.yMin,
00556 &user->bbox.yMax );
00557
00558 user->last = *to;
00559
00560 return 0;
00561 }
00562
00563 FT_DEFINE_OUTLINE_FUNCS(bbox_interface,
00564 (FT_Outline_MoveTo_Func) BBox_Move_To,
00565 (FT_Outline_LineTo_Func) BBox_Move_To,
00566 (FT_Outline_ConicTo_Func)BBox_Conic_To,
00567 (FT_Outline_CubicTo_Func)BBox_Cubic_To,
00568 0, 0
00569 )
00570
00571
00572
00573 FT_EXPORT_DEF( FT_Error )
00574 FT_Outline_Get_BBox( FT_Outline* outline,
00575 FT_BBox *abbox )
00576 {
00577 FT_BBox cbox;
00578 FT_BBox bbox;
00579 FT_Vector* vec;
00580 FT_UShort n;
00581
00582
00583 if ( !abbox )
00584 return FT_Err_Invalid_Argument;
00585
00586 if ( !outline )
00587 return FT_Err_Invalid_Outline;
00588
00589
00590 if ( outline->n_points == 0 || outline->n_contours <= 0 )
00591 {
00592 abbox->xMin = abbox->xMax = 0;
00593 abbox->yMin = abbox->yMax = 0;
00594 return 0;
00595 }
00596
00597
00598
00599
00600
00601 vec = outline->points;
00602 bbox.xMin = bbox.xMax = cbox.xMin = cbox.xMax = vec->x;
00603 bbox.yMin = bbox.yMax = cbox.yMin = cbox.yMax = vec->y;
00604 vec++;
00605
00606 for ( n = 1; n < outline->n_points; n++ )
00607 {
00608 FT_Pos x = vec->x;
00609 FT_Pos y = vec->y;
00610
00611
00612
00613 if ( x < cbox.xMin ) cbox.xMin = x;
00614 if ( x > cbox.xMax ) cbox.xMax = x;
00615
00616 if ( y < cbox.yMin ) cbox.yMin = y;
00617 if ( y > cbox.yMax ) cbox.yMax = y;
00618
00619 if ( FT_CURVE_TAG( outline->tags[n] ) == FT_CURVE_TAG_ON )
00620 {
00621
00622 if ( x < bbox.xMin ) bbox.xMin = x;
00623 if ( x > bbox.xMax ) bbox.xMax = x;
00624
00625 if ( y < bbox.yMin ) bbox.yMin = y;
00626 if ( y > bbox.yMax ) bbox.yMax = y;
00627 }
00628
00629 vec++;
00630 }
00631
00632
00633 if ( cbox.xMin < bbox.xMin || cbox.xMax > bbox.xMax ||
00634 cbox.yMin < bbox.yMin || cbox.yMax > bbox.yMax )
00635 {
00636
00637
00638
00639 FT_Error error;
00640 TBBox_Rec user;
00641
00642 #ifdef FT_CONFIG_OPTION_PIC
00643 FT_Outline_Funcs bbox_interface;
00644 Init_Class_bbox_interface(&bbox_interface);
00645 #endif
00646
00647 user.bbox = bbox;
00648
00649 error = FT_Outline_Decompose( outline, &bbox_interface, &user );
00650 if ( error )
00651 return error;
00652
00653 *abbox = user.bbox;
00654 }
00655 else
00656 *abbox = bbox;
00657
00658 return FT_Err_Ok;
00659 }
00660
00661
00662