1 /***************************************************************************/
2 /* */
3 /* pshints.c */
4 /* */
5 /* Adobe's code for handling CFF hints (body). */
6 /* */
7 /* Copyright 2007-2014 Adobe Systems Incorporated. */
8 /* */
9 /* This software, and all works of authorship, whether in source or */
10 /* object code form as indicated by the copyright notice(s) included */
11 /* herein (collectively, the "Work") is made available, and may only be */
12 /* used, modified, and distributed under the FreeType Project License, */
13 /* LICENSE.TXT. Additionally, subject to the terms and conditions of the */
14 /* FreeType Project License, each contributor to the Work hereby grants */
15 /* to any individual or legal entity exercising permissions granted by */
16 /* the FreeType Project License and this section (hereafter, "You" or */
17 /* "Your") a perpetual, worldwide, non-exclusive, no-charge, */
18 /* royalty-free, irrevocable (except as stated in this section) patent */
19 /* license to make, have made, use, offer to sell, sell, import, and */
20 /* otherwise transfer the Work, where such license applies only to those */
21 /* patent claims licensable by such contributor that are necessarily */
22 /* infringed by their contribution(s) alone or by combination of their */
23 /* contribution(s) with the Work to which such contribution(s) was */
24 /* submitted. If You institute patent litigation against any entity */
25 /* (including a cross-claim or counterclaim in a lawsuit) alleging that */
26 /* the Work or a contribution incorporated within the Work constitutes */
27 /* direct or contributory patent infringement, then any patent licenses */
28 /* granted to You under this License for that Work shall terminate as of */
29 /* the date such litigation is filed. */
30 /* */
31 /* By using, modifying, or distributing the Work you indicate that you */
32 /* have read and understood the terms and conditions of the */
33 /* FreeType Project License as well as those provided in this section, */
34 /* and you accept them fully. */
35 /* */
36 /***************************************************************************/
37
38
39 #include "psft.h"
40 #include FT_INTERNAL_DEBUG_H
41
42 #include "psglue.h"
43 #include "psfont.h"
44 #include "pshints.h"
45 #include "psintrp.h"
46
47
48 /*************************************************************************/
49 /* */
50 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
51 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
52 /* messages during execution. */
53 /* */
54 #undef FT_COMPONENT
55 #define FT_COMPONENT trace_cf2hints
56
57
58 typedef struct CF2_HintMoveRec_
59 {
60 size_t j; /* index of upper hint map edge */
61 CF2_Fixed moveUp; /* adjustment to optimum position */
62
63 } CF2_HintMoveRec, *CF2_HintMove;
64
65
66 /* Compute angular momentum for winding order detection. It is called */
67 /* for all lines and curves, but not necessarily in element order. */
68 static CF2_Int
69 cf2_getWindingMomentum( CF2_Fixed x1,
70 CF2_Fixed y1,
71 CF2_Fixed x2,
72 CF2_Fixed y2 )
73 {
74 /* cross product of pt1 position from origin with pt2 position from */
75 /* pt1; we reduce the precision so that the result fits into 32 bits */
200 hint->dsCoord = stemHint->minDS;
201
202 cf2_hint_lock( hint );
203 }
204 else
205 hint->dsCoord = FT_MulFix( hint->csCoord, scale );
206 }
207
208
209 /* initialize an invalid hint map element */
210 static void
211 cf2_hint_initZero( CF2_Hint hint )
212 {
213 FT_ZERO( hint );
214 }
215
216
217 FT_LOCAL_DEF( FT_Bool )
218 cf2_hint_isValid( const CF2_Hint hint )
219 {
220 return (FT_Bool)( hint->flags != 0 );
221 }
222
223
224 static FT_Bool
225 cf2_hint_isPair( const CF2_Hint hint )
226 {
227 return (FT_Bool)( ( hint->flags &
228 ( CF2_PairBottom | CF2_PairTop ) ) != 0 );
229 }
230
231
232 static FT_Bool
233 cf2_hint_isPairTop( const CF2_Hint hint )
234 {
235 return (FT_Bool)( ( hint->flags & CF2_PairTop ) != 0 );
236 }
237
238
239 FT_LOCAL_DEF( FT_Bool )
240 cf2_hint_isTop( const CF2_Hint hint )
241 {
242 return (FT_Bool)( ( hint->flags &
243 ( CF2_PairTop | CF2_GhostTop ) ) != 0 );
244 }
245
246
247 FT_LOCAL_DEF( FT_Bool )
248 cf2_hint_isBottom( const CF2_Hint hint )
249 {
250 return (FT_Bool)( ( hint->flags &
251 ( CF2_PairBottom | CF2_GhostBottom ) ) != 0 );
252 }
253
254
255 static FT_Bool
256 cf2_hint_isLocked( const CF2_Hint hint )
257 {
258 return (FT_Bool)( ( hint->flags & CF2_Locked ) != 0 );
259 }
260
261
262 static FT_Bool
263 cf2_hint_isSynthetic( const CF2_Hint hint )
264 {
265 return (FT_Bool)( ( hint->flags & CF2_Synthetic ) != 0 );
266 }
267
268
269 FT_LOCAL_DEF( void )
270 cf2_hint_lock( CF2_Hint hint )
271 {
272 hint->flags |= CF2_Locked;
273 }
274
275
276 FT_LOCAL_DEF( void )
277 cf2_hintmap_init( CF2_HintMap hintmap,
278 CF2_Font font,
279 CF2_HintMap initialMap,
280 CF2_ArrStack hintMoves,
281 CF2_Fixed scale )
282 {
283 FT_ZERO( hintmap );
284
285 /* copy parameters from font instance */
317 hint->index,
318 hint->csCoord / 65536.0,
319 hint->dsCoord / ( hint->scale * 1.0 ),
320 hint->scale,
321 ( cf2_hint_isPair( hint ) ? "p" : "g" ),
322 ( cf2_hint_isTop( hint ) ? "t" : "b" ),
323 ( cf2_hint_isLocked( hint ) ? "L" : ""),
324 ( cf2_hint_isSynthetic( hint ) ? "S" : "" ) ));
325 }
326 #else
327 FT_UNUSED( hintmap );
328 #endif
329 }
330
331
332 /* transform character space coordinate to device space using hint map */
333 static CF2_Fixed
334 cf2_hintmap_map( CF2_HintMap hintmap,
335 CF2_Fixed csCoord )
336 {
337 if ( hintmap->count == 0 || ! hintmap->hinted )
338 {
339 /* there are no hints; use uniform scale and zero offset */
340 return FT_MulFix( csCoord, hintmap->scale );
341 }
342 else
343 {
344 /* start linear search from last hit */
345 CF2_UInt i = hintmap->lastIndex;
346
347
348 FT_ASSERT( hintmap->lastIndex < CF2_MAX_HINT_EDGES );
349
350 /* search up */
351 while ( i < hintmap->count - 1 &&
352 csCoord >= hintmap->edge[i + 1].csCoord )
353 i += 1;
354
355 /* search down */
356 while ( i > 0 && csCoord < hintmap->edge[i].csCoord )
357 i -= 1;
480 hintmap->edge[i - 1].dsCoord <=
481 ADD_INT32( hintmap->edge[i].dsCoord,
482 moveDown - downMinCounter ) )
483 {
484 /* move smaller absolute amount */
485 move = ( -moveDown < moveUp ) ? moveDown : moveUp; /* optimum */
486 }
487 else
488 move = moveUp;
489 }
490 else
491 {
492 /* is there room to move down? */
493 if ( i == 0 ||
494 hintmap->edge[i - 1].dsCoord <=
495 ADD_INT32( hintmap->edge[i].dsCoord,
496 moveDown - downMinCounter ) )
497 {
498 move = moveDown;
499 /* true if non-optimum move */
500 saveEdge = (FT_Bool)( moveUp < -moveDown );
501 }
502 else
503 {
504 /* no room to move either way without overlapping or reducing */
505 /* the counter too much */
506 move = 0;
507 saveEdge = TRUE;
508 }
509 }
510
511 /* Identify non-moves and moves down that aren't optimal, and save */
512 /* them for second pass. */
513 /* Do this only if there is an unlocked edge above (which could */
514 /* possibly move). */
515 if ( saveEdge &&
516 j < hintmap->count - 1 &&
517 !cf2_hint_isLocked( &hintmap->edge[j + 1] ) )
518 {
519 CF2_HintMoveRec savedMove;
520
1008 i,
1009 font,
1010 hintOrigin,
1011 hintmap->scale,
1012 FALSE /* top */ );
1013
1014 cf2_hintmap_insertHint( hintmap, &bottomHintEdge, &topHintEdge );
1015 }
1016
1017 if ( ( i & 7 ) == 7 )
1018 {
1019 /* move to next mask byte */
1020 maskPtr++;
1021 maskByte = 0x80;
1022 }
1023 else
1024 maskByte >>= 1;
1025 }
1026 }
1027
1028 FT_TRACE6(( initialMap ? "flags: [p]air [g]host [t]op "
1029 "[b]ottom [L]ocked [S]ynthetic\n"
1030 "Initial hintmap\n"
1031 : "Hints:\n" ));
1032 cf2_hintmap_dump( hintmap );
1033
1034 /*
1035 * Note: The following line is a convenient place to break when
1036 * debugging hinting. Examine `hintmap->edge' for the list of
1037 * enabled hints, then step over the call to see the effect of
1038 * adjustment. We stop here first on the recursive call that
1039 * creates the initial map, and then on each counter group and
1040 * hint zone.
1041 */
1042
1043 /* adjust positions of hint edges that are not locked to blue zones */
1044 cf2_hintmap_adjustHints( hintmap );
1045
1046 FT_TRACE6(( "(adjusted)\n" ));
1047 cf2_hintmap_dump( hintmap );
1048
1049 /* save the position of all hints that were used in this hint map; */
1050 /* if we use them again, we'll locate them in the same position */
1051 if ( !initialMap )
1198 *
1199 */
1200 static FT_Bool
1201 cf2_glyphpath_computeIntersection( CF2_GlyphPath glyphpath,
1202 const FT_Vector* u1,
1203 const FT_Vector* u2,
1204 const FT_Vector* v1,
1205 const FT_Vector* v2,
1206 FT_Vector* intersection )
1207 {
1208 /*
1209 * Let `u' be a zero-based vector from the first segment, `v' from the
1210 * second segment.
1211 * Let `w 'be the zero-based vector from `u1' to `v1'.
1212 * `perp' is the `perpendicular dot product'; see
1213 * https://mathworld.wolfram.com/PerpDotProduct.html.
1214 * `s' is the parameter for the parametric line for the first segment
1215 * (`u').
1216 *
1217 * See notation in
1218 * http://softsurfer.com/Archive/algorithm_0104/algorithm_0104B.htm.
1219 * Calculations are done in 16.16, but must handle the squaring of
1220 * line lengths in character space. We scale all vectors by 1/32 to
1221 * avoid overflow. This allows values up to 4095 to be squared. The
1222 * scale factor cancels in the divide.
1223 *
1224 * TODO: the scale factor could be computed from UnitsPerEm.
1225 *
1226 */
1227
1228 #define cf2_perp( a, b ) \
1229 ( FT_MulFix( a.x, b.y ) - FT_MulFix( a.y, b.x ) )
1230
1231 /* round and divide by 32 */
1232 #define CF2_CS_SCALE( x ) \
1233 ( ( (x) + 0x10 ) >> 5 )
1234
1235 FT_Vector u, v, w; /* scaled vectors */
1236 CF2_Fixed denominator, s;
1237
1238
|
1 /****************************************************************************
2 *
3 * pshints.c
4 *
5 * Adobe's code for handling CFF hints (body).
6 *
7 * Copyright 2007-2014 Adobe Systems Incorporated.
8 *
9 * This software, and all works of authorship, whether in source or
10 * object code form as indicated by the copyright notice(s) included
11 * herein (collectively, the "Work") is made available, and may only be
12 * used, modified, and distributed under the FreeType Project License,
13 * LICENSE.TXT. Additionally, subject to the terms and conditions of the
14 * FreeType Project License, each contributor to the Work hereby grants
15 * to any individual or legal entity exercising permissions granted by
16 * the FreeType Project License and this section (hereafter, "You" or
17 * "Your") a perpetual, worldwide, non-exclusive, no-charge,
18 * royalty-free, irrevocable (except as stated in this section) patent
19 * license to make, have made, use, offer to sell, sell, import, and
20 * otherwise transfer the Work, where such license applies only to those
21 * patent claims licensable by such contributor that are necessarily
22 * infringed by their contribution(s) alone or by combination of their
23 * contribution(s) with the Work to which such contribution(s) was
24 * submitted. If You institute patent litigation against any entity
25 * (including a cross-claim or counterclaim in a lawsuit) alleging that
26 * the Work or a contribution incorporated within the Work constitutes
27 * direct or contributory patent infringement, then any patent licenses
28 * granted to You under this License for that Work shall terminate as of
29 * the date such litigation is filed.
30 *
31 * By using, modifying, or distributing the Work you indicate that you
32 * have read and understood the terms and conditions of the
33 * FreeType Project License as well as those provided in this section,
34 * and you accept them fully.
35 *
36 */
37
38
39 #include "psft.h"
40 #include FT_INTERNAL_DEBUG_H
41
42 #include "psglue.h"
43 #include "psfont.h"
44 #include "pshints.h"
45 #include "psintrp.h"
46
47
48 /**************************************************************************
49 *
50 * The macro FT_COMPONENT is used in trace mode. It is an implicit
51 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
52 * messages during execution.
53 */
54 #undef FT_COMPONENT
55 #define FT_COMPONENT cf2hints
56
57
58 typedef struct CF2_HintMoveRec_
59 {
60 size_t j; /* index of upper hint map edge */
61 CF2_Fixed moveUp; /* adjustment to optimum position */
62
63 } CF2_HintMoveRec, *CF2_HintMove;
64
65
66 /* Compute angular momentum for winding order detection. It is called */
67 /* for all lines and curves, but not necessarily in element order. */
68 static CF2_Int
69 cf2_getWindingMomentum( CF2_Fixed x1,
70 CF2_Fixed y1,
71 CF2_Fixed x2,
72 CF2_Fixed y2 )
73 {
74 /* cross product of pt1 position from origin with pt2 position from */
75 /* pt1; we reduce the precision so that the result fits into 32 bits */
200 hint->dsCoord = stemHint->minDS;
201
202 cf2_hint_lock( hint );
203 }
204 else
205 hint->dsCoord = FT_MulFix( hint->csCoord, scale );
206 }
207
208
209 /* initialize an invalid hint map element */
210 static void
211 cf2_hint_initZero( CF2_Hint hint )
212 {
213 FT_ZERO( hint );
214 }
215
216
217 FT_LOCAL_DEF( FT_Bool )
218 cf2_hint_isValid( const CF2_Hint hint )
219 {
220 return FT_BOOL( hint->flags );
221 }
222
223
224 static FT_Bool
225 cf2_hint_isPair( const CF2_Hint hint )
226 {
227 return FT_BOOL( hint->flags & ( CF2_PairBottom | CF2_PairTop ) );
228 }
229
230
231 static FT_Bool
232 cf2_hint_isPairTop( const CF2_Hint hint )
233 {
234 return FT_BOOL( hint->flags & CF2_PairTop );
235 }
236
237
238 FT_LOCAL_DEF( FT_Bool )
239 cf2_hint_isTop( const CF2_Hint hint )
240 {
241 return FT_BOOL( hint->flags & ( CF2_PairTop | CF2_GhostTop ) );
242 }
243
244
245 FT_LOCAL_DEF( FT_Bool )
246 cf2_hint_isBottom( const CF2_Hint hint )
247 {
248 return FT_BOOL( hint->flags & ( CF2_PairBottom | CF2_GhostBottom ) );
249 }
250
251
252 static FT_Bool
253 cf2_hint_isLocked( const CF2_Hint hint )
254 {
255 return FT_BOOL( hint->flags & CF2_Locked );
256 }
257
258
259 static FT_Bool
260 cf2_hint_isSynthetic( const CF2_Hint hint )
261 {
262 return FT_BOOL( hint->flags & CF2_Synthetic );
263 }
264
265
266 FT_LOCAL_DEF( void )
267 cf2_hint_lock( CF2_Hint hint )
268 {
269 hint->flags |= CF2_Locked;
270 }
271
272
273 FT_LOCAL_DEF( void )
274 cf2_hintmap_init( CF2_HintMap hintmap,
275 CF2_Font font,
276 CF2_HintMap initialMap,
277 CF2_ArrStack hintMoves,
278 CF2_Fixed scale )
279 {
280 FT_ZERO( hintmap );
281
282 /* copy parameters from font instance */
314 hint->index,
315 hint->csCoord / 65536.0,
316 hint->dsCoord / ( hint->scale * 1.0 ),
317 hint->scale,
318 ( cf2_hint_isPair( hint ) ? "p" : "g" ),
319 ( cf2_hint_isTop( hint ) ? "t" : "b" ),
320 ( cf2_hint_isLocked( hint ) ? "L" : ""),
321 ( cf2_hint_isSynthetic( hint ) ? "S" : "" ) ));
322 }
323 #else
324 FT_UNUSED( hintmap );
325 #endif
326 }
327
328
329 /* transform character space coordinate to device space using hint map */
330 static CF2_Fixed
331 cf2_hintmap_map( CF2_HintMap hintmap,
332 CF2_Fixed csCoord )
333 {
334 if ( hintmap->count == 0 || !hintmap->hinted )
335 {
336 /* there are no hints; use uniform scale and zero offset */
337 return FT_MulFix( csCoord, hintmap->scale );
338 }
339 else
340 {
341 /* start linear search from last hit */
342 CF2_UInt i = hintmap->lastIndex;
343
344
345 FT_ASSERT( hintmap->lastIndex < CF2_MAX_HINT_EDGES );
346
347 /* search up */
348 while ( i < hintmap->count - 1 &&
349 csCoord >= hintmap->edge[i + 1].csCoord )
350 i += 1;
351
352 /* search down */
353 while ( i > 0 && csCoord < hintmap->edge[i].csCoord )
354 i -= 1;
477 hintmap->edge[i - 1].dsCoord <=
478 ADD_INT32( hintmap->edge[i].dsCoord,
479 moveDown - downMinCounter ) )
480 {
481 /* move smaller absolute amount */
482 move = ( -moveDown < moveUp ) ? moveDown : moveUp; /* optimum */
483 }
484 else
485 move = moveUp;
486 }
487 else
488 {
489 /* is there room to move down? */
490 if ( i == 0 ||
491 hintmap->edge[i - 1].dsCoord <=
492 ADD_INT32( hintmap->edge[i].dsCoord,
493 moveDown - downMinCounter ) )
494 {
495 move = moveDown;
496 /* true if non-optimum move */
497 saveEdge = FT_BOOL( moveUp < -moveDown );
498 }
499 else
500 {
501 /* no room to move either way without overlapping or reducing */
502 /* the counter too much */
503 move = 0;
504 saveEdge = TRUE;
505 }
506 }
507
508 /* Identify non-moves and moves down that aren't optimal, and save */
509 /* them for second pass. */
510 /* Do this only if there is an unlocked edge above (which could */
511 /* possibly move). */
512 if ( saveEdge &&
513 j < hintmap->count - 1 &&
514 !cf2_hint_isLocked( &hintmap->edge[j + 1] ) )
515 {
516 CF2_HintMoveRec savedMove;
517
1005 i,
1006 font,
1007 hintOrigin,
1008 hintmap->scale,
1009 FALSE /* top */ );
1010
1011 cf2_hintmap_insertHint( hintmap, &bottomHintEdge, &topHintEdge );
1012 }
1013
1014 if ( ( i & 7 ) == 7 )
1015 {
1016 /* move to next mask byte */
1017 maskPtr++;
1018 maskByte = 0x80;
1019 }
1020 else
1021 maskByte >>= 1;
1022 }
1023 }
1024
1025 FT_TRACE6(( "%s\n", initialMap ? "flags: [p]air [g]host [t]op"
1026 " [b]ottom [L]ocked [S]ynthetic\n"
1027 "Initial hintmap"
1028 : "Hints:" ));
1029 cf2_hintmap_dump( hintmap );
1030
1031 /*
1032 * Note: The following line is a convenient place to break when
1033 * debugging hinting. Examine `hintmap->edge' for the list of
1034 * enabled hints, then step over the call to see the effect of
1035 * adjustment. We stop here first on the recursive call that
1036 * creates the initial map, and then on each counter group and
1037 * hint zone.
1038 */
1039
1040 /* adjust positions of hint edges that are not locked to blue zones */
1041 cf2_hintmap_adjustHints( hintmap );
1042
1043 FT_TRACE6(( "(adjusted)\n" ));
1044 cf2_hintmap_dump( hintmap );
1045
1046 /* save the position of all hints that were used in this hint map; */
1047 /* if we use them again, we'll locate them in the same position */
1048 if ( !initialMap )
1195 *
1196 */
1197 static FT_Bool
1198 cf2_glyphpath_computeIntersection( CF2_GlyphPath glyphpath,
1199 const FT_Vector* u1,
1200 const FT_Vector* u2,
1201 const FT_Vector* v1,
1202 const FT_Vector* v2,
1203 FT_Vector* intersection )
1204 {
1205 /*
1206 * Let `u' be a zero-based vector from the first segment, `v' from the
1207 * second segment.
1208 * Let `w 'be the zero-based vector from `u1' to `v1'.
1209 * `perp' is the `perpendicular dot product'; see
1210 * https://mathworld.wolfram.com/PerpDotProduct.html.
1211 * `s' is the parameter for the parametric line for the first segment
1212 * (`u').
1213 *
1214 * See notation in
1215 * http://geomalgorithms.com/a05-_intersect-1.html.
1216 * Calculations are done in 16.16, but must handle the squaring of
1217 * line lengths in character space. We scale all vectors by 1/32 to
1218 * avoid overflow. This allows values up to 4095 to be squared. The
1219 * scale factor cancels in the divide.
1220 *
1221 * TODO: the scale factor could be computed from UnitsPerEm.
1222 *
1223 */
1224
1225 #define cf2_perp( a, b ) \
1226 ( FT_MulFix( a.x, b.y ) - FT_MulFix( a.y, b.x ) )
1227
1228 /* round and divide by 32 */
1229 #define CF2_CS_SCALE( x ) \
1230 ( ( (x) + 0x10 ) >> 5 )
1231
1232 FT_Vector u, v, w; /* scaled vectors */
1233 CF2_Fixed denominator, s;
1234
1235
|