ftstroker.c 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364
  1. #include <ft2build.h>
  2. #include FT_STROKER_H
  3. #include FT_TRIGONOMETRY_H
  4. #include FT_INTERNAL_MEMORY_H
  5. #include FT_INTERNAL_DEBUG_H
  6. /***************************************************************************/
  7. /***************************************************************************/
  8. /***** *****/
  9. /***** BEZIER COMPUTATIONS *****/
  10. /***** *****/
  11. /***************************************************************************/
  12. /***************************************************************************/
  13. #define FT_SMALL_CONIC_THRESHOLD (FT_ANGLE_PI/6)
  14. #define FT_SMALL_CUBIC_THRESHOLD (FT_ANGLE_PI/6)
  15. #define FT_EPSILON 2
  16. #define FT_IS_SMALL(x) ((x) > -FT_EPSILON && (x) < FT_EPSILON)
  17. static FT_Pos
  18. ft_pos_abs( FT_Pos x )
  19. {
  20. return x >= 0 ? x : -x ;
  21. }
  22. static void
  23. ft_conic_split( FT_Vector* base )
  24. {
  25. FT_Pos a, b;
  26. base[4].x = base[2].x;
  27. b = base[1].x;
  28. a = base[3].x = ( base[2].x + b )/2;
  29. b = base[1].x = ( base[0].x + b )/2;
  30. base[2].x = ( a + b )/2;
  31. base[4].y = base[2].y;
  32. b = base[1].y;
  33. a = base[3].y = ( base[2].y + b )/2;
  34. b = base[1].y = ( base[0].y + b )/2;
  35. base[2].y = ( a + b )/2;
  36. }
  37. static FT_Bool
  38. ft_conic_is_small_enough( FT_Vector* base,
  39. FT_Angle *angle_in,
  40. FT_Angle *angle_out )
  41. {
  42. FT_Vector d1, d2;
  43. FT_Angle theta;
  44. FT_Int close1, close2;
  45. d1.x = base[1].x - base[2].x;
  46. d1.y = base[1].y - base[2].y;
  47. d2.x = base[0].x - base[1].x;
  48. d2.y = base[0].y - base[1].y;
  49. close1 = FT_IS_SMALL(d1.x) && FT_IS_SMALL(d1.y);
  50. close2 = FT_IS_SMALL(d2.x) && FT_IS_SMALL(d2.y);
  51. if (close1)
  52. {
  53. if (close2)
  54. *angle_in = *angle_out = 0;
  55. else
  56. *angle_in = *angle_out = FT_Atan2( d2.x, d2.y );
  57. }
  58. else if (close2)
  59. {
  60. *angle_in = *angle_out = FT_Atan2( d1.x, d1.y );
  61. }
  62. else
  63. {
  64. *angle_in = FT_Atan2( d1.x, d1.y );
  65. *angle_out = FT_Atan2( d2.x, d2.y );
  66. }
  67. theta = ft_pos_abs( FT_Angle_Diff( *angle_in, *angle_out ) );
  68. return FT_BOOL( theta < FT_SMALL_CONIC_THRESHOLD );
  69. }
  70. static void
  71. ft_cubic_split( FT_Vector* base )
  72. {
  73. FT_Pos a, b, c, d;
  74. base[6].x = base[3].x;
  75. c = base[1].x;
  76. d = base[2].x;
  77. base[1].x = a = ( base[0].x + c )/2;
  78. base[5].x = b = ( base[3].x + d )/2;
  79. c = ( c + d )/2;
  80. base[2].x = a = ( a + c )/2;
  81. base[4].x = b = ( b + c )/2;
  82. base[3].x = ( a + b )/2;
  83. base[6].y = base[3].y;
  84. c = base[1].y;
  85. d = base[2].y;
  86. base[1].y = a = ( base[0].y + c )/2;
  87. base[5].y = b = ( base[3].y + d )/2;
  88. c = ( c + d )/2;
  89. base[2].y = a = ( a + c )/2;
  90. base[4].y = b = ( b + c )/2;
  91. base[3].y = ( a + b )/2;
  92. }
  93. static FT_Bool
  94. ft_cubic_is_small_enough( FT_Vector* base,
  95. FT_Angle *angle_in,
  96. FT_Angle *angle_mid,
  97. FT_Angle *angle_out )
  98. {
  99. FT_Vector d1, d2, d3;
  100. FT_Angle theta1, theta2;
  101. FT_Int close1, close2, close3;
  102. d1.x = base[2].x - base[3].x;
  103. d1.y = base[2].y - base[3].y;
  104. d2.x = base[1].x - base[2].x;
  105. d2.y = base[1].y - base[2].y;
  106. d3.x = base[0].x - base[1].x;
  107. d3.y = base[0].y - base[1].y;
  108. close1 = FT_IS_SMALL(d1.x) && FT_IS_SMALL(d1.y);
  109. close2 = FT_IS_SMALL(d2.x) && FT_IS_SMALL(d2.y);
  110. close3 = FT_IS_SMALL(d3.x) && FT_IS_SMALL(d3.y);
  111. if (close1 || close3)
  112. {
  113. if (close2)
  114. {
  115. /* basically a point */
  116. *angle_in = *angle_out = *angle_mid = 0;
  117. }
  118. else if (close1)
  119. {
  120. *angle_in = *angle_mid = FT_Atan2( d2.x, d2.y );
  121. *angle_out = FT_Atan2( d3.x, d3.y );
  122. }
  123. else /* close2 */
  124. {
  125. *angle_in = FT_Atan2( d1.x, d1.y );
  126. *angle_mid = *angle_out = FT_Atan2( d2.x, d2.y );
  127. }
  128. }
  129. else if (close2)
  130. {
  131. *angle_in = *angle_mid = FT_Atan2( d1.x, d1.y );
  132. *angle_out = FT_Atan2( d3.x, d3.y );
  133. }
  134. else
  135. {
  136. *angle_in = FT_Atan2( d1.x, d1.y );
  137. *angle_mid = FT_Atan2( d2.x, d2.y );
  138. *angle_out = FT_Atan2( d3.x, d3.y );
  139. }
  140. theta1 = ft_pos_abs( FT_Angle_Diff( *angle_in, *angle_mid ) );
  141. theta2 = ft_pos_abs( FT_Angle_Diff( *angle_mid, *angle_out ) );
  142. return FT_BOOL( theta1 < FT_SMALL_CUBIC_THRESHOLD &&
  143. theta2 < FT_SMALL_CUBIC_THRESHOLD );
  144. }
  145. /***************************************************************************/
  146. /***************************************************************************/
  147. /***** *****/
  148. /***** STROKE BORDERS *****/
  149. /***** *****/
  150. /***************************************************************************/
  151. /***************************************************************************/
  152. typedef enum
  153. {
  154. FT_STROKE_TAG_ON = 1, /* on-curve point */
  155. FT_STROKE_TAG_CUBIC = 2, /* cubic off-point */
  156. FT_STROKE_TAG_BEGIN = 4, /* sub-path start */
  157. FT_STROKE_TAG_END = 8 /* sub-path end */
  158. } FT_StrokeTags;
  159. typedef struct FT_StrokeBorderRec_
  160. {
  161. FT_UInt num_points;
  162. FT_UInt max_points;
  163. FT_Vector* points;
  164. FT_Byte* tags;
  165. FT_Bool movable;
  166. FT_Int start; /* index of current sub-path start point */
  167. FT_Memory memory;
  168. } FT_StrokeBorderRec, *FT_StrokeBorder;
  169. static FT_Error
  170. ft_stroke_border_grow( FT_StrokeBorder border,
  171. FT_UInt new_points )
  172. {
  173. FT_UInt old_max = border->max_points;
  174. FT_UInt new_max = border->num_points + new_points;
  175. FT_Error error = 0;
  176. if ( new_max > old_max )
  177. {
  178. FT_UInt cur_max = old_max;
  179. FT_Memory memory = border->memory;
  180. while ( cur_max < new_max )
  181. cur_max += (cur_max >> 1) + 16;
  182. if ( FT_RENEW_ARRAY( border->points, old_max, cur_max ) ||
  183. FT_RENEW_ARRAY( border->tags, old_max, cur_max ) )
  184. goto Exit;
  185. border->max_points = cur_max;
  186. }
  187. Exit:
  188. return error;
  189. }
  190. static void
  191. ft_stroke_border_close( FT_StrokeBorder border )
  192. {
  193. FT_ASSERT( border->start >= 0 );
  194. border->tags[ border->start ] |= FT_STROKE_TAG_BEGIN;
  195. border->tags[ border->num_points-1 ] |= FT_STROKE_TAG_END;
  196. border->start = -1;
  197. border->movable = 0;
  198. }
  199. static FT_Error
  200. ft_stroke_border_lineto( FT_StrokeBorder border,
  201. FT_Vector* to,
  202. FT_Bool movable )
  203. {
  204. FT_Error error = 0;
  205. FT_ASSERT( border->start >= 0 );
  206. if ( border->movable )
  207. {
  208. /* move last point */
  209. border->points[ border->num_points-1 ] = *to;
  210. }
  211. else
  212. {
  213. /* add one point */
  214. error = ft_stroke_border_grow( border, 1 );
  215. if (!error)
  216. {
  217. FT_Vector* vec = border->points + border->num_points;
  218. FT_Byte* tag = border->tags + border->num_points;
  219. vec[0] = *to;
  220. tag[0] = FT_STROKE_TAG_ON;
  221. border->num_points += 1;
  222. }
  223. }
  224. border->movable = movable;
  225. return error;
  226. }
  227. static FT_Error
  228. ft_stroke_border_conicto( FT_StrokeBorder border,
  229. FT_Vector* control,
  230. FT_Vector* to )
  231. {
  232. FT_Error error;
  233. FT_ASSERT( border->start >= 0 );
  234. error = ft_stroke_border_grow( border, 2 );
  235. if (!error)
  236. {
  237. FT_Vector* vec = border->points + border->num_points;
  238. FT_Byte* tag = border->tags + border->num_points;
  239. vec[0] = *control;
  240. vec[1] = *to;
  241. tag[0] = 0;
  242. tag[1] = FT_STROKE_TAG_ON;
  243. border->num_points += 2;
  244. }
  245. border->movable = 0;
  246. return error;
  247. }
  248. static FT_Error
  249. ft_stroke_border_cubicto( FT_StrokeBorder border,
  250. FT_Vector* control1,
  251. FT_Vector* control2,
  252. FT_Vector* to )
  253. {
  254. FT_Error error;
  255. FT_ASSERT( border->start >= 0 );
  256. error = ft_stroke_border_grow( border, 3 );
  257. if (!error)
  258. {
  259. FT_Vector* vec = border->points + border->num_points;
  260. FT_Byte* tag = border->tags + border->num_points;
  261. vec[0] = *control1;
  262. vec[1] = *control2;
  263. vec[2] = *to;
  264. tag[0] = FT_STROKE_TAG_CUBIC;
  265. tag[1] = FT_STROKE_TAG_CUBIC;
  266. tag[2] = FT_STROKE_TAG_ON;
  267. border->num_points += 3;
  268. }
  269. border->movable = 0;
  270. return error;
  271. }
  272. #define FT_ARC_CUBIC_ANGLE (FT_ANGLE_PI/2)
  273. static FT_Error
  274. ft_stroke_border_arcto( FT_StrokeBorder border,
  275. FT_Vector* center,
  276. FT_Fixed radius,
  277. FT_Angle angle_start,
  278. FT_Angle angle_diff )
  279. {
  280. FT_Angle total, angle, step, rotate, next, theta;
  281. FT_Vector a, b, a2, b2;
  282. FT_Fixed length;
  283. FT_Error error = 0;
  284. /* compute start point */
  285. FT_Vector_From_Polar( &a, radius, angle_start );
  286. a.x += center->x;
  287. a.y += center->y;
  288. total = angle_diff;
  289. angle = angle_start;
  290. rotate = ( angle_diff >= 0 ) ? FT_ANGLE_PI2 : -FT_ANGLE_PI2;
  291. while (total != 0)
  292. {
  293. step = total;
  294. if ( step > FT_ARC_CUBIC_ANGLE )
  295. step = FT_ARC_CUBIC_ANGLE;
  296. else if ( step < -FT_ARC_CUBIC_ANGLE )
  297. step = -FT_ARC_CUBIC_ANGLE;
  298. next = angle + step;
  299. theta = step;
  300. if ( theta < 0 )
  301. theta = -theta;
  302. theta >>= 1;
  303. /* compute end point */
  304. FT_Vector_From_Polar( &b, radius, next );
  305. b.x += center->x;
  306. b.y += center->y;
  307. /* compute first and second control points */
  308. length = FT_MulDiv( radius, FT_Sin(theta)*4,
  309. (0x10000L + FT_Cos(theta))*3 );
  310. FT_Vector_From_Polar( &a2, length, angle + rotate );
  311. a2.x += a.x;
  312. a2.y += a.y;
  313. FT_Vector_From_Polar( &b2, length, next - rotate );
  314. b2.x += b.x;
  315. b2.y += b.y;
  316. /* add cubic arc */
  317. error = ft_stroke_border_cubicto( border, &a2, &b2, &b );
  318. if (error) break;
  319. /* process the rest of the arc ?? */
  320. a = b;
  321. total -= step;
  322. angle = next;
  323. }
  324. return error;
  325. }
  326. static FT_Error
  327. ft_stroke_border_moveto( FT_StrokeBorder border,
  328. FT_Vector* to )
  329. {
  330. /* close current open path if any ? */
  331. if ( border->start >= 0 )
  332. ft_stroke_border_close( border );
  333. border->start = border->num_points;
  334. border->movable = 0;
  335. return ft_stroke_border_lineto( border, to, 0 );
  336. }
  337. static void
  338. ft_stroke_border_init( FT_StrokeBorder border,
  339. FT_Memory memory )
  340. {
  341. border->memory = memory;
  342. border->points = NULL;
  343. border->tags = NULL;
  344. border->num_points = 0;
  345. border->max_points = 0;
  346. border->start = -1;
  347. }
  348. static void
  349. ft_stroke_border_reset( FT_StrokeBorder border )
  350. {
  351. border->num_points = 0;
  352. border->start = -1;
  353. }
  354. static void
  355. ft_stroke_border_done( FT_StrokeBorder border )
  356. {
  357. FT_Memory memory = border->memory;
  358. FT_FREE( border->points );
  359. FT_FREE( border->tags );
  360. border->num_points = 0;
  361. border->max_points = 0;
  362. border->start = -1;
  363. }
  364. static FT_Error
  365. ft_stroke_border_get_counts( FT_StrokeBorder border,
  366. FT_UInt *anum_points,
  367. FT_UInt *anum_contours )
  368. {
  369. FT_Error error = 0;
  370. FT_UInt num_points = 0;
  371. FT_UInt num_contours = 0;
  372. FT_UInt count = border->num_points;
  373. FT_Vector* point = border->points;
  374. FT_Byte* tags = border->tags;
  375. FT_Int in_contour = 0;
  376. for ( ; count > 0; count--, point++, tags++ )
  377. {
  378. if ( tags[0] & FT_STROKE_TAG_BEGIN )
  379. {
  380. if ( in_contour != 0 )
  381. goto Fail;
  382. in_contour = 1;
  383. }
  384. else if ( in_contour == 0 )
  385. goto Fail;
  386. if ( tags[0] & FT_STROKE_TAG_END )
  387. {
  388. if ( in_contour == 0 )
  389. goto Fail;
  390. in_contour = 0;
  391. num_contours++;
  392. }
  393. }
  394. if ( in_contour != 0 )
  395. goto Fail;
  396. Exit:
  397. *anum_points = num_points;
  398. *anum_contours = num_contours;
  399. return error;
  400. Fail:
  401. num_points = 0;
  402. num_contours = 0;
  403. goto Exit;
  404. }
  405. static void
  406. ft_stroke_border_export( FT_StrokeBorder border,
  407. FT_Outline* outline )
  408. {
  409. /* copy point locations */
  410. FT_MEM_COPY( outline->points + outline->n_points,
  411. border->points,
  412. border->num_points * sizeof(FT_Vector) );
  413. /* copy tags */
  414. {
  415. FT_UInt count = border->num_points;
  416. FT_Byte* read = border->tags;
  417. FT_Byte* write = (FT_Byte*) outline->tags + outline->n_points;
  418. for ( ; count > 0; count--, read++, write++ )
  419. {
  420. if ( *read & FT_STROKE_TAG_ON )
  421. *write = FT_CURVE_TAG_ON;
  422. else if ( *read & FT_STROKE_TAG_CUBIC )
  423. *write = FT_CURVE_TAG_CUBIC;
  424. else
  425. *write = FT_CURVE_TAG_CONIC;
  426. }
  427. }
  428. /* copy contours */
  429. {
  430. FT_UInt count = border->num_points;
  431. FT_Byte* tags = border->tags;
  432. FT_Short* write = outline->contours + outline->n_contours;
  433. FT_Short index = (FT_Short) outline->n_points;
  434. for ( ; count > 0; count--, tags++, write++, index++ )
  435. {
  436. if ( *tags & FT_STROKE_TAG_END )
  437. {
  438. *write++ = index;
  439. outline->n_contours++;
  440. }
  441. }
  442. }
  443. outline->n_points = (short)( outline->n_points + border->num_points );
  444. FT_ASSERT( FT_Outline_Check( outline ) == 0 );
  445. }
  446. /***************************************************************************/
  447. /***************************************************************************/
  448. /***** *****/
  449. /***** STROKER *****/
  450. /***** *****/
  451. /***************************************************************************/
  452. /***************************************************************************/
  453. #define FT_SIDE_TO_ROTATE(s) (FT_ANGLE_PI2 - (s)*FT_ANGLE_PI)
  454. typedef struct FT_StrokerRec_
  455. {
  456. FT_Angle angle_in;
  457. FT_Angle angle_out;
  458. FT_Vector center;
  459. FT_Bool first_point;
  460. FT_Bool subpath_open;
  461. FT_Angle subpath_angle;
  462. FT_Vector subpath_start;
  463. FT_Stroker_LineCap line_cap;
  464. FT_Stroker_LineJoin line_join;
  465. FT_Fixed miter_limit;
  466. FT_Fixed radius;
  467. FT_Bool valid;
  468. FT_StrokeBorderRec borders[2];
  469. FT_Memory memory;
  470. } FT_StrokerRec;
  471. FT_EXPORT_DEF( FT_Error )
  472. FT_Stroker_New( FT_Memory memory,
  473. FT_Stroker *astroker )
  474. {
  475. FT_Error error;
  476. FT_Stroker stroker;
  477. if ( !FT_NEW( stroker ) )
  478. {
  479. stroker->memory = memory;
  480. ft_stroke_border_init( &stroker->borders[0], memory );
  481. ft_stroke_border_init( &stroker->borders[1], memory );
  482. }
  483. *astroker = stroker;
  484. return error;
  485. }
  486. FT_EXPORT_DEF( void )
  487. FT_Stroker_Set( FT_Stroker stroker,
  488. FT_Fixed radius,
  489. FT_Stroker_LineCap line_cap,
  490. FT_Stroker_LineJoin line_join,
  491. FT_Fixed miter_limit )
  492. {
  493. stroker->radius = radius;
  494. stroker->line_cap = line_cap;
  495. stroker->line_join = line_join;
  496. stroker->miter_limit = miter_limit;
  497. stroker->valid = 0;
  498. ft_stroke_border_reset( &stroker->borders[0] );
  499. ft_stroke_border_reset( &stroker->borders[1] );
  500. }
  501. FT_EXPORT_DEF( void )
  502. FT_Stroker_Done( FT_Stroker stroker )
  503. {
  504. if ( stroker )
  505. {
  506. FT_Memory memory = stroker->memory;
  507. ft_stroke_border_done( &stroker->borders[0] );
  508. ft_stroke_border_done( &stroker->borders[1] );
  509. stroker->memory = NULL;
  510. FT_FREE( stroker );
  511. }
  512. }
  513. /* creates a circular arc at a corner or cap */
  514. static FT_Error
  515. ft_stroker_arcto( FT_Stroker stroker,
  516. FT_Int side )
  517. {
  518. FT_Angle total, rotate;
  519. FT_Fixed radius = stroker->radius;
  520. FT_Error error = 0;
  521. FT_StrokeBorder border = stroker->borders + side;
  522. rotate = FT_SIDE_TO_ROTATE(side);
  523. total = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
  524. if (total == FT_ANGLE_PI)
  525. total = -rotate*2;
  526. error = ft_stroke_border_arcto( border,
  527. &stroker->center,
  528. radius,
  529. stroker->angle_in + rotate,
  530. total );
  531. border->movable = 0;
  532. return error;
  533. }
  534. /* adds a cap at the end of an opened path */
  535. static FT_Error
  536. ft_stroker_cap( FT_Stroker stroker,
  537. FT_Angle angle,
  538. FT_Int side )
  539. {
  540. FT_Error error = 0;
  541. if ( stroker->line_cap == FT_STROKER_LINECAP_ROUND )
  542. {
  543. /* add a round cap */
  544. stroker->angle_in = angle;
  545. stroker->angle_out = angle + FT_ANGLE_PI;
  546. error = ft_stroker_arcto( stroker, side );
  547. }
  548. else if ( stroker->line_cap == FT_STROKER_LINECAP_SQUARE )
  549. {
  550. /* add a square cap */
  551. FT_Vector delta, delta2;
  552. FT_Angle rotate = FT_SIDE_TO_ROTATE(side);
  553. FT_Fixed radius = stroker->radius;
  554. FT_StrokeBorder border = stroker->borders + side;
  555. FT_Vector_From_Polar( &delta2, radius, angle+rotate );
  556. FT_Vector_From_Polar( &delta, radius, angle );
  557. delta.x += stroker->center.x + delta2.x;
  558. delta.y += stroker->center.y + delta2.y;
  559. error = ft_stroke_border_lineto( border, &delta, 0 );
  560. if (error) goto Exit;
  561. FT_Vector_From_Polar( &delta2, radius, angle-rotate );
  562. FT_Vector_From_Polar( &delta, radius, angle );
  563. delta.x += delta2.x + stroker->center.x;
  564. delta.y += delta2.y + stroker->center.y;
  565. error = ft_stroke_border_lineto( border, &delta, 0 );
  566. }
  567. Exit:
  568. return error;
  569. }
  570. /* process an inside corner, i.e. compute intersection */
  571. static FT_Error
  572. ft_stroker_inside( FT_Stroker stroker,
  573. FT_Int side)
  574. {
  575. FT_StrokeBorder border = stroker->borders + side;
  576. FT_Angle phi, theta, rotate;
  577. FT_Fixed length, thcos, sigma;
  578. FT_Vector delta;
  579. FT_Error error = 0;
  580. rotate = FT_SIDE_TO_ROTATE(side);
  581. /* compute median angle */
  582. theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
  583. if ( theta == FT_ANGLE_PI )
  584. theta = rotate;
  585. else
  586. theta = theta/2;
  587. phi = stroker->angle_in + theta;
  588. thcos = FT_Cos( theta );
  589. sigma = FT_MulFix( stroker->miter_limit, thcos );
  590. if ( sigma < 0x10000L )
  591. {
  592. FT_Vector_From_Polar( &delta, stroker->radius, stroker->angle_out + rotate );
  593. delta.x += stroker->center.x;
  594. delta.y += stroker->center.y;
  595. border->movable = 0;
  596. }
  597. else
  598. {
  599. length = FT_DivFix( stroker->radius, thcos );
  600. FT_Vector_From_Polar( &delta, length, phi + rotate );
  601. delta.x += stroker->center.x;
  602. delta.y += stroker->center.y;
  603. }
  604. error = ft_stroke_border_lineto( border, &delta, 0 );
  605. return error;
  606. }
  607. /* process an outside corner, i.e. compute bevel/miter/round */
  608. static FT_Error
  609. ft_stroker_outside( FT_Stroker stroker,
  610. FT_Int side )
  611. {
  612. FT_StrokeBorder border = stroker->borders + side;
  613. FT_Error error;
  614. FT_Angle rotate;
  615. if ( stroker->line_join == FT_STROKER_LINEJOIN_ROUND )
  616. {
  617. error = ft_stroker_arcto( stroker, side );
  618. }
  619. else
  620. {
  621. /* this is a mitered or beveled corner */
  622. FT_Fixed sigma, radius = stroker->radius;
  623. FT_Angle theta, phi;
  624. FT_Fixed thcos;
  625. FT_Bool miter;
  626. rotate = FT_SIDE_TO_ROTATE(side);
  627. miter = FT_BOOL( stroker->line_join == FT_STROKER_LINEJOIN_MITER );
  628. theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
  629. if (theta == FT_ANGLE_PI)
  630. theta = rotate;
  631. else
  632. theta = theta/2;
  633. thcos = FT_Cos( theta );
  634. sigma = FT_MulFix( stroker->miter_limit, thcos );
  635. if ( sigma >= 0x10000L )
  636. miter = 0;
  637. phi = stroker->angle_in + theta + rotate;
  638. if (miter) /* this is a miter (broken angle) */
  639. {
  640. FT_Vector middle, delta;
  641. FT_Fixed length;
  642. /* compute middle point */
  643. FT_Vector_From_Polar( &middle, FT_MulFix( radius, stroker->miter_limit ),
  644. phi );
  645. middle.x += stroker->center.x;
  646. middle.y += stroker->center.y;
  647. /* compute first angle point */
  648. length = FT_MulFix( radius, FT_DivFix( 0x10000L - sigma,
  649. ft_pos_abs( FT_Sin( theta ) ) ) );
  650. FT_Vector_From_Polar( &delta, length, phi + rotate );
  651. delta.x += middle.x;
  652. delta.y += middle.y;
  653. error = ft_stroke_border_lineto( border, &delta, 0 );
  654. if (error) goto Exit;
  655. /* compute second angle point */
  656. FT_Vector_From_Polar( &delta, length, phi - rotate );
  657. delta.x += middle.x;
  658. delta.y += middle.y;
  659. error = ft_stroke_border_lineto( border, &delta, 0 );
  660. if (error) goto Exit;
  661. /* finally, add a movable end point */
  662. FT_Vector_From_Polar( &delta, radius, stroker->angle_out + rotate );
  663. delta.x += stroker->center.x;
  664. delta.y += stroker->center.y;
  665. error = ft_stroke_border_lineto( border, &delta, 1 );
  666. }
  667. else /* this is a bevel (intersection) */
  668. {
  669. FT_Fixed length;
  670. FT_Vector delta;
  671. length = FT_DivFix( stroker->radius, thcos );
  672. FT_Vector_From_Polar( &delta, length, phi );
  673. delta.x += stroker->center.x;
  674. delta.y += stroker->center.y;
  675. error = ft_stroke_border_lineto( border, &delta, 0 );
  676. if (error) goto Exit;
  677. /* now add end point */
  678. FT_Vector_From_Polar( &delta, stroker->radius, stroker->angle_out + rotate );
  679. delta.x += stroker->center.x;
  680. delta.y += stroker->center.y;
  681. error = ft_stroke_border_lineto( border, &delta, 1 );
  682. }
  683. }
  684. Exit:
  685. return error;
  686. }
  687. static FT_Error
  688. ft_stroker_process_corner( FT_Stroker stroker )
  689. {
  690. FT_Error error = 0;
  691. FT_Angle turn;
  692. FT_Int inside_side;
  693. turn = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
  694. /* no specific corner processing is required if the turn is 0 */
  695. if (turn == 0)
  696. goto Exit;
  697. /* when we turn to the right, the inside side is 0 */
  698. inside_side = 0;
  699. /* otherwise, the inside side is 1 */
  700. if (turn < 0)
  701. inside_side = 1;
  702. /* process the inside side */
  703. error = ft_stroker_inside( stroker, inside_side );
  704. if (error) goto Exit;
  705. /* process the outside side */
  706. error = ft_stroker_outside( stroker, 1-inside_side );
  707. Exit:
  708. return error;
  709. }
  710. /* add two points to the left and right borders corresponding to the */
  711. /* start of the subpath.. */
  712. static FT_Error
  713. ft_stroker_subpath_start( FT_Stroker stroker,
  714. FT_Angle start_angle )
  715. {
  716. FT_Vector delta;
  717. FT_Vector point;
  718. FT_Error error;
  719. FT_StrokeBorder border;
  720. FT_Vector_From_Polar( &delta, stroker->radius, start_angle + FT_ANGLE_PI2 );
  721. point.x = stroker->center.x + delta.x;
  722. point.y = stroker->center.y + delta.y;
  723. border = stroker->borders;
  724. error = ft_stroke_border_moveto( border, &point );
  725. if (error) goto Exit;
  726. point.x = stroker->center.x - delta.x;
  727. point.y = stroker->center.y - delta.y;
  728. border++;
  729. error = ft_stroke_border_moveto( border, &point );
  730. /* save angle for last cap */
  731. stroker->subpath_angle = start_angle;
  732. stroker->first_point = 0;
  733. Exit:
  734. return error;
  735. }
  736. FT_EXPORT_DEF( FT_Error )
  737. FT_Stroker_LineTo( FT_Stroker stroker,
  738. FT_Vector* to )
  739. {
  740. FT_Error error = 0;
  741. FT_StrokeBorder border;
  742. FT_Vector delta;
  743. FT_Angle angle;
  744. FT_Int side;
  745. delta.x = to->x - stroker->center.x;
  746. delta.y = to->y - stroker->center.y;
  747. angle = FT_Atan2( delta.x, delta.y );
  748. FT_Vector_From_Polar( &delta, stroker->radius, angle + FT_ANGLE_PI2 );
  749. /* process corner if necessary */
  750. if ( stroker->first_point )
  751. {
  752. /* this is the first segment of a subpath. We need to */
  753. /* add a point to each border at their respective starting */
  754. /* point locations.. */
  755. error = ft_stroker_subpath_start( stroker, angle );
  756. if (error) goto Exit;
  757. }
  758. else
  759. {
  760. /* process the current corner */
  761. stroker->angle_out = angle;
  762. error = ft_stroker_process_corner( stroker );
  763. if (error) goto Exit;
  764. }
  765. /* now add a line segment to both the "inside" and "outside" paths */
  766. for ( border = stroker->borders, side = 1; side >= 0; side--, border++ )
  767. {
  768. FT_Vector point;
  769. point.x = to->x + delta.x;
  770. point.y = to->y + delta.y;
  771. error = ft_stroke_border_lineto( border, &point, 1 );
  772. if (error) goto Exit;
  773. delta.x = -delta.x;
  774. delta.y = -delta.y;
  775. }
  776. stroker->angle_in = angle;
  777. stroker->center = *to;
  778. Exit:
  779. return error;
  780. }
  781. FT_EXPORT_DEF( FT_Error )
  782. FT_Stroker_ConicTo( FT_Stroker stroker,
  783. FT_Vector* control,
  784. FT_Vector* to )
  785. {
  786. FT_Error error = 0;
  787. FT_Vector bez_stack[34];
  788. FT_Vector* arc;
  789. FT_Vector* limit = bez_stack + 30;
  790. FT_Angle start_angle;
  791. FT_Bool first_arc = 1;
  792. arc = bez_stack;
  793. arc[0] = *to;
  794. arc[1] = *control;
  795. arc[2] = stroker->center;
  796. while ( arc >= bez_stack )
  797. {
  798. FT_Angle angle_in, angle_out;
  799. angle_in = angle_out = 0; /* remove compiler warnings */
  800. if ( arc < limit &&
  801. !ft_conic_is_small_enough( arc, &angle_in, &angle_out ) )
  802. {
  803. ft_conic_split( arc );
  804. arc += 2;
  805. continue;
  806. }
  807. if ( first_arc )
  808. {
  809. first_arc = 0;
  810. start_angle = angle_in;
  811. /* process corner if necessary */
  812. if ( stroker->first_point )
  813. error = ft_stroker_subpath_start( stroker, start_angle );
  814. else
  815. {
  816. stroker->angle_out = start_angle;
  817. error = ft_stroker_process_corner( stroker );
  818. }
  819. }
  820. /* the arc's angle is small enough, we can add it directly to each */
  821. /* border.. */
  822. {
  823. FT_Vector ctrl, end;
  824. FT_Angle theta, phi, rotate;
  825. FT_Fixed length;
  826. FT_Int side;
  827. theta = FT_Angle_Diff( angle_in, angle_out )/2;
  828. phi = angle_in + theta;
  829. length = FT_DivFix( stroker->radius, FT_Cos(theta) );
  830. for ( side = 0; side <= 1; side++ )
  831. {
  832. rotate = FT_SIDE_TO_ROTATE(side);
  833. /* compute control point */
  834. FT_Vector_From_Polar( &ctrl, length, phi + rotate );
  835. ctrl.x += arc[1].x;
  836. ctrl.y += arc[1].y;
  837. /* compute end point */
  838. FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate );
  839. end.x += arc[0].x;
  840. end.y += arc[0].y;
  841. error = ft_stroke_border_conicto( stroker->borders + side, &ctrl, &end );
  842. if (error) goto Exit;
  843. }
  844. }
  845. arc -= 2;
  846. if (arc < bez_stack)
  847. stroker->angle_in = angle_out;
  848. }
  849. stroker->center = *to;
  850. Exit:
  851. return error;
  852. }
  853. FT_EXPORT_DEF( FT_Error )
  854. FT_Stroker_CubicTo( FT_Stroker stroker,
  855. FT_Vector* control1,
  856. FT_Vector* control2,
  857. FT_Vector* to )
  858. {
  859. FT_Error error = 0;
  860. FT_Vector bez_stack[37];
  861. FT_Vector* arc;
  862. FT_Vector* limit = bez_stack + 32;
  863. FT_Angle start_angle;
  864. FT_Bool first_arc = 1;
  865. arc = bez_stack;
  866. arc[0] = *to;
  867. arc[1] = *control2;
  868. arc[2] = *control1;
  869. arc[3] = stroker->center;
  870. while ( arc >= bez_stack )
  871. {
  872. FT_Angle angle_in, angle_mid, angle_out;
  873. /* remove compiler warnings */
  874. angle_in = angle_out = angle_mid = 0;
  875. if ( arc < limit &&
  876. !ft_cubic_is_small_enough( arc, &angle_in, &angle_mid, &angle_out ) )
  877. {
  878. ft_cubic_split( arc );
  879. arc += 3;
  880. continue;
  881. }
  882. if ( first_arc )
  883. {
  884. first_arc = 0;
  885. /* process corner if necessary */
  886. start_angle = angle_in;
  887. if ( stroker->first_point )
  888. error = ft_stroker_subpath_start( stroker, start_angle );
  889. else
  890. {
  891. stroker->angle_out = start_angle;
  892. error = ft_stroker_process_corner( stroker );
  893. }
  894. if (error) goto Exit;
  895. }
  896. /* the arc's angle is small enough, we can add it directly to each */
  897. /* border.. */
  898. {
  899. FT_Vector ctrl1, ctrl2, end;
  900. FT_Angle theta1, phi1, theta2, phi2, rotate;
  901. FT_Fixed length1, length2;
  902. FT_Int side;
  903. theta1 = ft_pos_abs( angle_mid - angle_in )/2;
  904. theta2 = ft_pos_abs( angle_out - angle_mid )/2;
  905. phi1 = (angle_mid+angle_in)/2;
  906. phi2 = (angle_mid+angle_out)/2;
  907. length1 = FT_DivFix( stroker->radius, FT_Cos(theta1) );
  908. length2 = FT_DivFix( stroker->radius, FT_Cos(theta2) );
  909. for ( side = 0; side <= 1; side++ )
  910. {
  911. rotate = FT_SIDE_TO_ROTATE(side);
  912. /* compute control points */
  913. FT_Vector_From_Polar( &ctrl1, length1, phi1 + rotate );
  914. ctrl1.x += arc[2].x;
  915. ctrl1.y += arc[2].y;
  916. FT_Vector_From_Polar( &ctrl2, length2, phi2 + rotate );
  917. ctrl2.x += arc[1].x;
  918. ctrl2.y += arc[1].y;
  919. /* compute end point */
  920. FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate );
  921. end.x += arc[0].x;
  922. end.y += arc[0].y;
  923. error = ft_stroke_border_cubicto( stroker->borders + side, &ctrl1, &ctrl2, &end );
  924. if (error) goto Exit;
  925. }
  926. }
  927. arc -= 3;
  928. if (arc < bez_stack)
  929. stroker->angle_in = angle_out;
  930. }
  931. stroker->center = *to;
  932. Exit:
  933. return error;
  934. }
  935. FT_EXPORT_DEF( FT_Error )
  936. FT_Stroker_BeginSubPath( FT_Stroker stroker,
  937. FT_Vector* to,
  938. FT_Bool open )
  939. {
  940. /* we cannot process the first point, because there is not enough */
  941. /* information regarding its corner/cap. The latter will be processed */
  942. /* in the "end_subpath" routine */
  943. /* */
  944. stroker->first_point = 1;
  945. stroker->center = *to;
  946. stroker->subpath_open = open;
  947. /* record the subpath start point index for each border */
  948. stroker->subpath_start = *to;
  949. return 0;
  950. }
  951. static
  952. FT_Error ft_stroker_add_reverse_left( FT_Stroker stroker,
  953. FT_Bool open )
  954. {
  955. FT_StrokeBorder right = stroker->borders + 0;
  956. FT_StrokeBorder left = stroker->borders + 1;
  957. FT_Int new_points;
  958. FT_Error error = 0;
  959. FT_ASSERT( left->start >= 0 );
  960. new_points = left->num_points - left->start;
  961. if ( new_points > 0 )
  962. {
  963. error = ft_stroke_border_grow( right, (FT_UInt)new_points );
  964. if (error) goto Exit;
  965. {
  966. FT_Vector* dst_point = right->points + right->num_points;
  967. FT_Byte* dst_tag = right->tags + right->num_points;
  968. FT_Vector* src_point = left->points + left->num_points - 1;
  969. FT_Byte* src_tag = left->tags + left->num_points - 1;
  970. while ( src_point >= left->points + left->start )
  971. {
  972. *dst_point = *src_point;
  973. *dst_tag = *src_tag;
  974. if (open)
  975. dst_tag[0] &= ~(FT_STROKE_TAG_BEGIN | FT_STROKE_TAG_END);
  976. else
  977. {
  978. /* switch begin/end tags if necessary.. */
  979. if (dst_tag[0] & (FT_STROKE_TAG_BEGIN | FT_STROKE_TAG_END))
  980. dst_tag[0] ^= (FT_STROKE_TAG_BEGIN | FT_STROKE_TAG_END);
  981. }
  982. src_point--;
  983. src_tag--;
  984. dst_point++;
  985. dst_tag++;
  986. }
  987. }
  988. left->num_points = left->start;
  989. right->num_points += new_points;
  990. right->movable = 0;
  991. left->movable = 0;
  992. }
  993. Exit:
  994. return error;
  995. }
  996. /* there's a lot of magic in this function !! */
  997. FT_EXPORT_DEF( FT_Error )
  998. FT_Stroker_EndSubPath( FT_Stroker stroker )
  999. {
  1000. FT_Error error = 0;
  1001. if ( stroker->subpath_open )
  1002. {
  1003. FT_StrokeBorder right = stroker->borders;
  1004. /* all right, this is an opened path, we need to add a cap between */
  1005. /* right & left, add the reverse of left, then add a final cap between */
  1006. /* left & right.. */
  1007. error = ft_stroker_cap( stroker, stroker->angle_in, 0 );
  1008. if (error) goto Exit;
  1009. /* add reversed points from "left" to "right" */
  1010. error = ft_stroker_add_reverse_left( stroker, 1 );
  1011. if (error) goto Exit;
  1012. /* now add the final cap */
  1013. stroker->center = stroker->subpath_start;
  1014. error = ft_stroker_cap( stroker, stroker->subpath_angle+FT_ANGLE_PI, 0 );
  1015. if (error) goto Exit;
  1016. /* now, end the right subpath accordingly. the left one is */
  1017. /* rewind and doesn't need further processing.. */
  1018. ft_stroke_border_close( right );
  1019. }
  1020. else
  1021. {
  1022. FT_Angle turn;
  1023. FT_Int inside_side;
  1024. /* process the corner ... */
  1025. stroker->angle_out = stroker->subpath_angle;
  1026. turn = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
  1027. /* no specific corner processing is required if the turn is 0 */
  1028. if (turn != 0)
  1029. {
  1030. /* when we turn to the right, the inside side is 0 */
  1031. inside_side = 0;
  1032. /* otherwise, the inside side is 1 */
  1033. if (turn < 0)
  1034. inside_side = 1;
  1035. /* IMPORTANT: WE DO NOT PROCESS THE INSIDE BORDER HERE !! */
  1036. /* process the inside side */
  1037. /* error = ft_stroker_inside( stroker, inside_side );
  1038. if (error) goto Exit; */
  1039. /* process the outside side */
  1040. error = ft_stroker_outside( stroker, 1-inside_side );
  1041. if (error) goto Exit;
  1042. }
  1043. /* we will first end our two subpaths */
  1044. ft_stroke_border_close( stroker->borders + 0 );
  1045. ft_stroke_border_close( stroker->borders + 1 );
  1046. /* now, add the reversed left subpath to "right" */
  1047. error = ft_stroker_add_reverse_left( stroker, 0 );
  1048. if (error) goto Exit;
  1049. }
  1050. Exit:
  1051. return error;
  1052. }
  1053. FT_EXPORT_DEF( FT_Error )
  1054. FT_Stroker_GetCounts( FT_Stroker stroker,
  1055. FT_UInt *anum_points,
  1056. FT_UInt *anum_contours )
  1057. {
  1058. FT_UInt count1, count2, num_points = 0;
  1059. FT_UInt count3, count4, num_contours = 0;
  1060. FT_Error error;
  1061. error = ft_stroke_border_get_counts( stroker->borders+0, &count1, &count2 );
  1062. if (error) goto Exit;
  1063. error = ft_stroke_border_get_counts( stroker->borders+1, &count3, &count4 );
  1064. if (error) goto Exit;
  1065. num_points = count1 + count3;
  1066. num_contours = count2 + count4;
  1067. stroker->valid = 1;
  1068. Exit:
  1069. *anum_points = num_points;
  1070. *anum_contours = num_contours;
  1071. return error;
  1072. }
  1073. FT_EXPORT_DEF( void )
  1074. FT_Stroker_Export( FT_Stroker stroker,
  1075. FT_Outline* outline )
  1076. {
  1077. if ( stroker->valid )
  1078. {
  1079. ft_stroke_border_export( stroker->borders+0, outline );
  1080. ft_stroke_border_export( stroker->borders+1, outline );
  1081. }
  1082. }