/src/freetype/src/base/ftbbox.c

https://bitbucket.org/cabalistic/ogredeps/ · C · 662 lines · 334 code · 98 blank · 230 comment · 89 complexity · 5c93f2657a78014622bef5c5fc08d21e MD5 · raw file

  1. /***************************************************************************/
  2. /* */
  3. /* ftbbox.c */
  4. /* */
  5. /* FreeType bbox computation (body). */
  6. /* */
  7. /* Copyright 1996-2001, 2002, 2004, 2006, 2010 by */
  8. /* David Turner, Robert Wilhelm, and Werner Lemberg. */
  9. /* */
  10. /* This file is part of the FreeType project, and may only be used */
  11. /* modified and distributed under the terms of the FreeType project */
  12. /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
  13. /* this file you indicate that you have read the license and */
  14. /* understand and accept it fully. */
  15. /* */
  16. /***************************************************************************/
  17. /*************************************************************************/
  18. /* */
  19. /* This component has a _single_ role: to compute exact outline bounding */
  20. /* boxes. */
  21. /* */
  22. /*************************************************************************/
  23. #include <ft2build.h>
  24. #include FT_BBOX_H
  25. #include FT_IMAGE_H
  26. #include FT_OUTLINE_H
  27. #include FT_INTERNAL_CALC_H
  28. #include FT_INTERNAL_OBJECTS_H
  29. typedef struct TBBox_Rec_
  30. {
  31. FT_Vector last;
  32. FT_BBox bbox;
  33. } TBBox_Rec;
  34. /*************************************************************************/
  35. /* */
  36. /* <Function> */
  37. /* BBox_Move_To */
  38. /* */
  39. /* <Description> */
  40. /* This function is used as a `move_to' and `line_to' emitter during */
  41. /* FT_Outline_Decompose(). It simply records the destination point */
  42. /* in `user->last'; no further computations are necessary since we */
  43. /* use the cbox as the starting bbox which must be refined. */
  44. /* */
  45. /* <Input> */
  46. /* to :: A pointer to the destination vector. */
  47. /* */
  48. /* <InOut> */
  49. /* user :: A pointer to the current walk context. */
  50. /* */
  51. /* <Return> */
  52. /* Always 0. Needed for the interface only. */
  53. /* */
  54. static int
  55. BBox_Move_To( FT_Vector* to,
  56. TBBox_Rec* user )
  57. {
  58. user->last = *to;
  59. return 0;
  60. }
  61. #define CHECK_X( p, bbox ) \
  62. ( p->x < bbox.xMin || p->x > bbox.xMax )
  63. #define CHECK_Y( p, bbox ) \
  64. ( p->y < bbox.yMin || p->y > bbox.yMax )
  65. /*************************************************************************/
  66. /* */
  67. /* <Function> */
  68. /* BBox_Conic_Check */
  69. /* */
  70. /* <Description> */
  71. /* Finds the extrema of a 1-dimensional conic Bezier curve and update */
  72. /* a bounding range. This version uses direct computation, as it */
  73. /* doesn't need square roots. */
  74. /* */
  75. /* <Input> */
  76. /* y1 :: The start coordinate. */
  77. /* */
  78. /* y2 :: The coordinate of the control point. */
  79. /* */
  80. /* y3 :: The end coordinate. */
  81. /* */
  82. /* <InOut> */
  83. /* min :: The address of the current minimum. */
  84. /* */
  85. /* max :: The address of the current maximum. */
  86. /* */
  87. static void
  88. BBox_Conic_Check( FT_Pos y1,
  89. FT_Pos y2,
  90. FT_Pos y3,
  91. FT_Pos* min,
  92. FT_Pos* max )
  93. {
  94. if ( y1 <= y3 && y2 == y1 ) /* flat arc */
  95. goto Suite;
  96. if ( y1 < y3 )
  97. {
  98. if ( y2 >= y1 && y2 <= y3 ) /* ascending arc */
  99. goto Suite;
  100. }
  101. else
  102. {
  103. if ( y2 >= y3 && y2 <= y1 ) /* descending arc */
  104. {
  105. y2 = y1;
  106. y1 = y3;
  107. y3 = y2;
  108. goto Suite;
  109. }
  110. }
  111. y1 = y3 = y1 - FT_MulDiv( y2 - y1, y2 - y1, y1 - 2*y2 + y3 );
  112. Suite:
  113. if ( y1 < *min ) *min = y1;
  114. if ( y3 > *max ) *max = y3;
  115. }
  116. /*************************************************************************/
  117. /* */
  118. /* <Function> */
  119. /* BBox_Conic_To */
  120. /* */
  121. /* <Description> */
  122. /* This function is used as a `conic_to' emitter during */
  123. /* FT_Outline_Decompose(). It checks a conic Bezier curve with the */
  124. /* current bounding box, and computes its extrema if necessary to */
  125. /* update it. */
  126. /* */
  127. /* <Input> */
  128. /* control :: A pointer to a control point. */
  129. /* */
  130. /* to :: A pointer to the destination vector. */
  131. /* */
  132. /* <InOut> */
  133. /* user :: The address of the current walk context. */
  134. /* */
  135. /* <Return> */
  136. /* Always 0. Needed for the interface only. */
  137. /* */
  138. /* <Note> */
  139. /* In the case of a non-monotonous arc, we compute directly the */
  140. /* extremum coordinates, as it is sufficiently fast. */
  141. /* */
  142. static int
  143. BBox_Conic_To( FT_Vector* control,
  144. FT_Vector* to,
  145. TBBox_Rec* user )
  146. {
  147. /* we don't need to check `to' since it is always an `on' point, thus */
  148. /* within the bbox */
  149. if ( CHECK_X( control, user->bbox ) )
  150. BBox_Conic_Check( user->last.x,
  151. control->x,
  152. to->x,
  153. &user->bbox.xMin,
  154. &user->bbox.xMax );
  155. if ( CHECK_Y( control, user->bbox ) )
  156. BBox_Conic_Check( user->last.y,
  157. control->y,
  158. to->y,
  159. &user->bbox.yMin,
  160. &user->bbox.yMax );
  161. user->last = *to;
  162. return 0;
  163. }
  164. /*************************************************************************/
  165. /* */
  166. /* <Function> */
  167. /* BBox_Cubic_Check */
  168. /* */
  169. /* <Description> */
  170. /* Finds the extrema of a 1-dimensional cubic Bezier curve and */
  171. /* updates a bounding range. This version uses splitting because we */
  172. /* don't want to use square roots and extra accuracy. */
  173. /* */
  174. /* <Input> */
  175. /* p1 :: The start coordinate. */
  176. /* */
  177. /* p2 :: The coordinate of the first control point. */
  178. /* */
  179. /* p3 :: The coordinate of the second control point. */
  180. /* */
  181. /* p4 :: The end coordinate. */
  182. /* */
  183. /* <InOut> */
  184. /* min :: The address of the current minimum. */
  185. /* */
  186. /* max :: The address of the current maximum. */
  187. /* */
  188. #if 0
  189. static void
  190. BBox_Cubic_Check( FT_Pos p1,
  191. FT_Pos p2,
  192. FT_Pos p3,
  193. FT_Pos p4,
  194. FT_Pos* min,
  195. FT_Pos* max )
  196. {
  197. FT_Pos stack[32*3 + 1], *arc;
  198. arc = stack;
  199. arc[0] = p1;
  200. arc[1] = p2;
  201. arc[2] = p3;
  202. arc[3] = p4;
  203. do
  204. {
  205. FT_Pos y1 = arc[0];
  206. FT_Pos y2 = arc[1];
  207. FT_Pos y3 = arc[2];
  208. FT_Pos y4 = arc[3];
  209. if ( y1 == y4 )
  210. {
  211. if ( y1 == y2 && y1 == y3 ) /* flat */
  212. goto Test;
  213. }
  214. else if ( y1 < y4 )
  215. {
  216. if ( y2 >= y1 && y2 <= y4 && y3 >= y1 && y3 <= y4 ) /* ascending */
  217. goto Test;
  218. }
  219. else
  220. {
  221. if ( y2 >= y4 && y2 <= y1 && y3 >= y4 && y3 <= y1 ) /* descending */
  222. {
  223. y2 = y1;
  224. y1 = y4;
  225. y4 = y2;
  226. goto Test;
  227. }
  228. }
  229. /* unknown direction -- split the arc in two */
  230. arc[6] = y4;
  231. arc[1] = y1 = ( y1 + y2 ) / 2;
  232. arc[5] = y4 = ( y4 + y3 ) / 2;
  233. y2 = ( y2 + y3 ) / 2;
  234. arc[2] = y1 = ( y1 + y2 ) / 2;
  235. arc[4] = y4 = ( y4 + y2 ) / 2;
  236. arc[3] = ( y1 + y4 ) / 2;
  237. arc += 3;
  238. goto Suite;
  239. Test:
  240. if ( y1 < *min ) *min = y1;
  241. if ( y4 > *max ) *max = y4;
  242. arc -= 3;
  243. Suite:
  244. ;
  245. } while ( arc >= stack );
  246. }
  247. #else
  248. static void
  249. test_cubic_extrema( FT_Pos y1,
  250. FT_Pos y2,
  251. FT_Pos y3,
  252. FT_Pos y4,
  253. FT_Fixed u,
  254. FT_Pos* min,
  255. FT_Pos* max )
  256. {
  257. /* FT_Pos a = y4 - 3*y3 + 3*y2 - y1; */
  258. FT_Pos b = y3 - 2*y2 + y1;
  259. FT_Pos c = y2 - y1;
  260. FT_Pos d = y1;
  261. FT_Pos y;
  262. FT_Fixed uu;
  263. FT_UNUSED ( y4 );
  264. /* The polynomial is */
  265. /* */
  266. /* P(x) = a*x^3 + 3b*x^2 + 3c*x + d , */
  267. /* */
  268. /* dP/dx = 3a*x^2 + 6b*x + 3c . */
  269. /* */
  270. /* However, we also have */
  271. /* */
  272. /* dP/dx(u) = 0 , */
  273. /* */
  274. /* which implies by subtraction that */
  275. /* */
  276. /* P(u) = b*u^2 + 2c*u + d . */
  277. if ( u > 0 && u < 0x10000L )
  278. {
  279. uu = FT_MulFix( u, u );
  280. y = d + FT_MulFix( c, 2*u ) + FT_MulFix( b, uu );
  281. if ( y < *min ) *min = y;
  282. if ( y > *max ) *max = y;
  283. }
  284. }
  285. static void
  286. BBox_Cubic_Check( FT_Pos y1,
  287. FT_Pos y2,
  288. FT_Pos y3,
  289. FT_Pos y4,
  290. FT_Pos* min,
  291. FT_Pos* max )
  292. {
  293. /* always compare first and last points */
  294. if ( y1 < *min ) *min = y1;
  295. else if ( y1 > *max ) *max = y1;
  296. if ( y4 < *min ) *min = y4;
  297. else if ( y4 > *max ) *max = y4;
  298. /* now, try to see if there are split points here */
  299. if ( y1 <= y4 )
  300. {
  301. /* flat or ascending arc test */
  302. if ( y1 <= y2 && y2 <= y4 && y1 <= y3 && y3 <= y4 )
  303. return;
  304. }
  305. else /* y1 > y4 */
  306. {
  307. /* descending arc test */
  308. if ( y1 >= y2 && y2 >= y4 && y1 >= y3 && y3 >= y4 )
  309. return;
  310. }
  311. /* There are some split points. Find them. */
  312. {
  313. FT_Pos a = y4 - 3*y3 + 3*y2 - y1;
  314. FT_Pos b = y3 - 2*y2 + y1;
  315. FT_Pos c = y2 - y1;
  316. FT_Pos d;
  317. FT_Fixed t;
  318. /* We need to solve `ax^2+2bx+c' here, without floating points! */
  319. /* The trick is to normalize to a different representation in order */
  320. /* to use our 16.16 fixed point routines. */
  321. /* */
  322. /* We compute FT_MulFix(b,b) and FT_MulFix(a,c) after normalization. */
  323. /* These values must fit into a single 16.16 value. */
  324. /* */
  325. /* We normalize a, b, and c to `8.16' fixed float values to ensure */
  326. /* that its product is held in a `16.16' value. */
  327. {
  328. FT_ULong t1, t2;
  329. int shift = 0;
  330. /* The following computation is based on the fact that for */
  331. /* any value `y', if `n' is the position of the most */
  332. /* significant bit of `abs(y)' (starting from 0 for the */
  333. /* least significant bit), then `y' is in the range */
  334. /* */
  335. /* -2^n..2^n-1 */
  336. /* */
  337. /* We want to shift `a', `b', and `c' concurrently in order */
  338. /* to ensure that they all fit in 8.16 values, which maps */
  339. /* to the integer range `-2^23..2^23-1'. */
  340. /* */
  341. /* Necessarily, we need to shift `a', `b', and `c' so that */
  342. /* the most significant bit of its absolute values is at */
  343. /* _most_ at position 23. */
  344. /* */
  345. /* We begin by computing `t1' as the bitwise `OR' of the */
  346. /* absolute values of `a', `b', `c'. */
  347. t1 = (FT_ULong)( ( a >= 0 ) ? a : -a );
  348. t2 = (FT_ULong)( ( b >= 0 ) ? b : -b );
  349. t1 |= t2;
  350. t2 = (FT_ULong)( ( c >= 0 ) ? c : -c );
  351. t1 |= t2;
  352. /* Now we can be sure that the most significant bit of `t1' */
  353. /* is the most significant bit of either `a', `b', or `c', */
  354. /* depending on the greatest integer range of the particular */
  355. /* variable. */
  356. /* */
  357. /* Next, we compute the `shift', by shifting `t1' as many */
  358. /* times as necessary to move its MSB to position 23. This */
  359. /* corresponds to a value of `t1' that is in the range */
  360. /* 0x40_0000..0x7F_FFFF. */
  361. /* */
  362. /* Finally, we shift `a', `b', and `c' by the same amount. */
  363. /* This ensures that all values are now in the range */
  364. /* -2^23..2^23, i.e., they are now expressed as 8.16 */
  365. /* fixed-float numbers. This also means that we are using */
  366. /* 24 bits of precision to compute the zeros, independently */
  367. /* of the range of the original polynomial coefficients. */
  368. /* */
  369. /* This algorithm should ensure reasonably accurate values */
  370. /* for the zeros. Note that they are only expressed with */
  371. /* 16 bits when computing the extrema (the zeros need to */
  372. /* be in 0..1 exclusive to be considered part of the arc). */
  373. if ( t1 == 0 ) /* all coefficients are 0! */
  374. return;
  375. if ( t1 > 0x7FFFFFUL )
  376. {
  377. do
  378. {
  379. shift++;
  380. t1 >>= 1;
  381. } while ( t1 > 0x7FFFFFUL );
  382. /* this loses some bits of precision, but we use 24 of them */
  383. /* for the computation anyway */
  384. a >>= shift;
  385. b >>= shift;
  386. c >>= shift;
  387. }
  388. else if ( t1 < 0x400000UL )
  389. {
  390. do
  391. {
  392. shift++;
  393. t1 <<= 1;
  394. } while ( t1 < 0x400000UL );
  395. a <<= shift;
  396. b <<= shift;
  397. c <<= shift;
  398. }
  399. }
  400. /* handle a == 0 */
  401. if ( a == 0 )
  402. {
  403. if ( b != 0 )
  404. {
  405. t = - FT_DivFix( c, b ) / 2;
  406. test_cubic_extrema( y1, y2, y3, y4, t, min, max );
  407. }
  408. }
  409. else
  410. {
  411. /* solve the equation now */
  412. d = FT_MulFix( b, b ) - FT_MulFix( a, c );
  413. if ( d < 0 )
  414. return;
  415. if ( d == 0 )
  416. {
  417. /* there is a single split point at -b/a */
  418. t = - FT_DivFix( b, a );
  419. test_cubic_extrema( y1, y2, y3, y4, t, min, max );
  420. }
  421. else
  422. {
  423. /* there are two solutions; we need to filter them */
  424. d = FT_SqrtFixed( (FT_Int32)d );
  425. t = - FT_DivFix( b - d, a );
  426. test_cubic_extrema( y1, y2, y3, y4, t, min, max );
  427. t = - FT_DivFix( b + d, a );
  428. test_cubic_extrema( y1, y2, y3, y4, t, min, max );
  429. }
  430. }
  431. }
  432. }
  433. #endif
  434. /*************************************************************************/
  435. /* */
  436. /* <Function> */
  437. /* BBox_Cubic_To */
  438. /* */
  439. /* <Description> */
  440. /* This function is used as a `cubic_to' emitter during */
  441. /* FT_Outline_Decompose(). It checks a cubic Bezier curve with the */
  442. /* current bounding box, and computes its extrema if necessary to */
  443. /* update it. */
  444. /* */
  445. /* <Input> */
  446. /* control1 :: A pointer to the first control point. */
  447. /* */
  448. /* control2 :: A pointer to the second control point. */
  449. /* */
  450. /* to :: A pointer to the destination vector. */
  451. /* */
  452. /* <InOut> */
  453. /* user :: The address of the current walk context. */
  454. /* */
  455. /* <Return> */
  456. /* Always 0. Needed for the interface only. */
  457. /* */
  458. /* <Note> */
  459. /* In the case of a non-monotonous arc, we don't compute directly */
  460. /* extremum coordinates, we subdivide instead. */
  461. /* */
  462. static int
  463. BBox_Cubic_To( FT_Vector* control1,
  464. FT_Vector* control2,
  465. FT_Vector* to,
  466. TBBox_Rec* user )
  467. {
  468. /* we don't need to check `to' since it is always an `on' point, thus */
  469. /* within the bbox */
  470. if ( CHECK_X( control1, user->bbox ) ||
  471. CHECK_X( control2, user->bbox ) )
  472. BBox_Cubic_Check( user->last.x,
  473. control1->x,
  474. control2->x,
  475. to->x,
  476. &user->bbox.xMin,
  477. &user->bbox.xMax );
  478. if ( CHECK_Y( control1, user->bbox ) ||
  479. CHECK_Y( control2, user->bbox ) )
  480. BBox_Cubic_Check( user->last.y,
  481. control1->y,
  482. control2->y,
  483. to->y,
  484. &user->bbox.yMin,
  485. &user->bbox.yMax );
  486. user->last = *to;
  487. return 0;
  488. }
  489. FT_DEFINE_OUTLINE_FUNCS(bbox_interface,
  490. (FT_Outline_MoveTo_Func) BBox_Move_To,
  491. (FT_Outline_LineTo_Func) BBox_Move_To,
  492. (FT_Outline_ConicTo_Func)BBox_Conic_To,
  493. (FT_Outline_CubicTo_Func)BBox_Cubic_To,
  494. 0, 0
  495. )
  496. /* documentation is in ftbbox.h */
  497. FT_EXPORT_DEF( FT_Error )
  498. FT_Outline_Get_BBox( FT_Outline* outline,
  499. FT_BBox *abbox )
  500. {
  501. FT_BBox cbox;
  502. FT_BBox bbox;
  503. FT_Vector* vec;
  504. FT_UShort n;
  505. if ( !abbox )
  506. return FT_Err_Invalid_Argument;
  507. if ( !outline )
  508. return FT_Err_Invalid_Outline;
  509. /* if outline is empty, return (0,0,0,0) */
  510. if ( outline->n_points == 0 || outline->n_contours <= 0 )
  511. {
  512. abbox->xMin = abbox->xMax = 0;
  513. abbox->yMin = abbox->yMax = 0;
  514. return 0;
  515. }
  516. /* We compute the control box as well as the bounding box of */
  517. /* all `on' points in the outline. Then, if the two boxes */
  518. /* coincide, we exit immediately. */
  519. vec = outline->points;
  520. bbox.xMin = bbox.xMax = cbox.xMin = cbox.xMax = vec->x;
  521. bbox.yMin = bbox.yMax = cbox.yMin = cbox.yMax = vec->y;
  522. vec++;
  523. for ( n = 1; n < outline->n_points; n++ )
  524. {
  525. FT_Pos x = vec->x;
  526. FT_Pos y = vec->y;
  527. /* update control box */
  528. if ( x < cbox.xMin ) cbox.xMin = x;
  529. if ( x > cbox.xMax ) cbox.xMax = x;
  530. if ( y < cbox.yMin ) cbox.yMin = y;
  531. if ( y > cbox.yMax ) cbox.yMax = y;
  532. if ( FT_CURVE_TAG( outline->tags[n] ) == FT_CURVE_TAG_ON )
  533. {
  534. /* update bbox for `on' points only */
  535. if ( x < bbox.xMin ) bbox.xMin = x;
  536. if ( x > bbox.xMax ) bbox.xMax = x;
  537. if ( y < bbox.yMin ) bbox.yMin = y;
  538. if ( y > bbox.yMax ) bbox.yMax = y;
  539. }
  540. vec++;
  541. }
  542. /* test two boxes for equality */
  543. if ( cbox.xMin < bbox.xMin || cbox.xMax > bbox.xMax ||
  544. cbox.yMin < bbox.yMin || cbox.yMax > bbox.yMax )
  545. {
  546. /* the two boxes are different, now walk over the outline to */
  547. /* get the Bezier arc extrema. */
  548. FT_Error error;
  549. TBBox_Rec user;
  550. #ifdef FT_CONFIG_OPTION_PIC
  551. FT_Outline_Funcs bbox_interface;
  552. Init_Class_bbox_interface(&bbox_interface);
  553. #endif
  554. user.bbox = bbox;
  555. error = FT_Outline_Decompose( outline, &bbox_interface, &user );
  556. if ( error )
  557. return error;
  558. *abbox = user.bbox;
  559. }
  560. else
  561. *abbox = bbox;
  562. return FT_Err_Ok;
  563. }
  564. /* END */