1 /***************************************************************************/
5 /* Arithmetic computations (body). */
7 /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
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. */
16 /***************************************************************************/
18 /*************************************************************************/
20 /* Support for 1-complement arithmetic has been totally dropped in this */
21 /* release. You can still write your own code if you need it. */
23 /*************************************************************************/
25 /*************************************************************************/
27 /* Implementing basic computation routines. */
29 /* FT_MulDiv(), FT_MulFix(), FT_DivFix(), FT_RoundFix(), FT_CeilFix(), */
30 /* and FT_FloorFix() are declared in freetype.h. */
32 /*************************************************************************/
36 #include FT_INTERNAL_CALC_H
37 #include FT_INTERNAL_DEBUG_H
38 #include FT_INTERNAL_OBJECTS_H
41 /* we need to define a 64-bits data type here */
45 typedef FT_INT64 FT_Int64
;
49 typedef struct FT_Int64_
56 #endif /* FT_LONG64 */
59 /*************************************************************************/
61 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
62 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
63 /* messages during execution. */
66 #define FT_COMPONENT trace_calc
69 /* The following three functions are available regardless of whether */
70 /* FT_LONG64 is defined. */
72 /* documentation is in freetype.h */
74 FT_EXPORT_DEF( FT_Fixed
)
75 FT_RoundFix( FT_Fixed a
)
77 return ( a
>= 0 ) ? ( a
+ 0x8000L
) & ~0xFFFFL
78 : -((-a
+ 0x8000L
) & ~0xFFFFL
);
82 /* documentation is in freetype.h */
84 FT_EXPORT_DEF( FT_Fixed
)
85 FT_CeilFix( FT_Fixed a
)
87 return ( a
>= 0 ) ? ( a
+ 0xFFFFL
) & ~0xFFFFL
88 : -((-a
+ 0xFFFFL
) & ~0xFFFFL
);
92 /* documentation is in freetype.h */
94 FT_EXPORT_DEF( FT_Fixed
)
95 FT_FloorFix( FT_Fixed a
)
97 return ( a
>= 0 ) ? a
& ~0xFFFFL
98 : -((-a
) & ~0xFFFFL
);
102 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
104 /* documentation is in ftcalc.h */
106 FT_EXPORT_DEF( FT_Int32
)
107 FT_Sqrt32( FT_Int32 x
)
109 FT_ULong val
, root
, newroot
, mask
;
118 newroot
= root
+ mask
;
119 if ( newroot
<= val
)
122 root
= newroot
+ mask
;
128 } while ( mask
!= 0 );
133 #endif /* FT_CONFIG_OPTION_OLD_INTERNALS */
139 /* documentation is in freetype.h */
141 FT_EXPORT_DEF( FT_Long
)
142 FT_MulDiv( FT_Long a
,
151 if ( a
< 0 ) { a
= -a
; s
= -1; }
152 if ( b
< 0 ) { b
= -b
; s
= -s
; }
153 if ( c
< 0 ) { c
= -c
; s
= -s
; }
155 d
= (FT_Long
)( c
> 0 ? ( (FT_Int64
)a
* b
+ ( c
>> 1 ) ) / c
158 return ( s
> 0 ) ? d
: -d
;
162 #ifdef TT_USE_BYTECODE_INTERPRETER
164 /* documentation is in ftcalc.h */
166 FT_BASE_DEF( FT_Long
)
167 FT_MulDiv_No_Round( FT_Long a
,
176 if ( a
< 0 ) { a
= -a
; s
= -1; }
177 if ( b
< 0 ) { b
= -b
; s
= -s
; }
178 if ( c
< 0 ) { c
= -c
; s
= -s
; }
180 d
= (FT_Long
)( c
> 0 ? (FT_Int64
)a
* b
/ c
183 return ( s
> 0 ) ? d
: -d
;
186 #endif /* TT_USE_BYTECODE_INTERPRETER */
189 /* documentation is in freetype.h */
191 FT_EXPORT_DEF( FT_Long
)
192 FT_MulFix( FT_Long a
,
199 if ( a
< 0 ) { a
= -a
; s
= -1; }
200 if ( b
< 0 ) { b
= -b
; s
= -s
; }
202 c
= (FT_Long
)( ( (FT_Int64
)a
* b
+ 0x8000L
) >> 16 );
203 return ( s
> 0 ) ? c
: -c
;
207 /* documentation is in freetype.h */
209 FT_EXPORT_DEF( FT_Long
)
210 FT_DivFix( FT_Long a
,
217 if ( a
< 0 ) { a
= -a
; s
= -1; }
218 if ( b
< 0 ) { b
= -b
; s
= -s
; }
221 /* check for division by 0 */
224 /* compute result directly */
225 q
= (FT_UInt32
)( ( ( (FT_Int64
)a
<< 16 ) + ( b
>> 1 ) ) / b
);
227 return ( s
< 0 ? -(FT_Long
)q
: (FT_Long
)q
);
231 #else /* !FT_LONG64 */
235 ft_multo64( FT_UInt32 x
,
239 FT_UInt32 lo1
, hi1
, lo2
, hi2
, lo
, hi
, i1
, i2
;
242 lo1
= x
& 0x0000FFFFU
; hi1
= x
>> 16;
243 lo2
= y
& 0x0000FFFFU
; hi2
= y
>> 16;
250 /* Check carry overflow of i1 + i2 */
252 hi
+= (FT_UInt32
)( i1
< i2
) << 16;
257 /* Check carry overflow of i1 + lo */
267 ft_div64by32( FT_UInt32 hi
,
279 return (FT_UInt32
)0x7FFFFFFFL
;
288 if ( r
>= (FT_UInt32
)y
)
301 FT_Add64( FT_Int64
* x
,
305 register FT_UInt32 lo
, hi
;
309 hi
= x
->hi
+ y
->hi
+ ( lo
< x
->lo
);
316 /* documentation is in freetype.h */
318 /* The FT_MulDiv function has been optimized thanks to ideas from */
319 /* Graham Asher. The trick is to optimize computation when everything */
320 /* fits within 32-bits (a rather common case). */
322 /* we compute 'a*b+c/2', then divide it by 'c'. (positive values) */
324 /* 46340 is FLOOR(SQRT(2^31-1)). */
326 /* if ( a <= 46340 && b <= 46340 ) then ( a*b <= 0x7FFEA810 ) */
328 /* 0x7FFFFFFF - 0x7FFEA810 = 0x157F0 */
330 /* if ( c < 0x157F0*2 ) then ( a*b+c/2 <= 0x7FFFFFFF ) */
332 /* and 2*0x157F0 = 176096 */
335 FT_EXPORT_DEF( FT_Long
)
336 FT_MulDiv( FT_Long a
,
343 if ( a
== 0 || b
== c
)
346 s
= a
; a
= FT_ABS( a
);
347 s
^= b
; b
= FT_ABS( b
);
348 s
^= c
; c
= FT_ABS( c
);
350 if ( a
<= 46340L && b
<= 46340L && c
<= 176095L && c
> 0 )
351 a
= ( a
* b
+ ( c
>> 1 ) ) / c
;
355 FT_Int64 temp
, temp2
;
358 ft_multo64( a
, b
, &temp
);
361 temp2
.lo
= (FT_UInt32
)(c
>> 1);
362 FT_Add64( &temp
, &temp2
, &temp
);
363 a
= ft_div64by32( temp
.hi
, temp
.lo
, c
);
368 return ( s
< 0 ? -a
: a
);
372 #ifdef TT_USE_BYTECODE_INTERPRETER
374 FT_BASE_DEF( FT_Long
)
375 FT_MulDiv_No_Round( FT_Long a
,
382 if ( a
== 0 || b
== c
)
385 s
= a
; a
= FT_ABS( a
);
386 s
^= b
; b
= FT_ABS( b
);
387 s
^= c
; c
= FT_ABS( c
);
389 if ( a
<= 46340L && b
<= 46340L && c
> 0 )
397 ft_multo64( a
, b
, &temp
);
398 a
= ft_div64by32( temp
.hi
, temp
.lo
, c
);
403 return ( s
< 0 ? -a
: a
);
406 #endif /* TT_USE_BYTECODE_INTERPRETER */
409 /* documentation is in freetype.h */
411 FT_EXPORT_DEF( FT_Long
)
412 FT_MulFix( FT_Long a
,
415 /* use inline assembly to speed up things a bit */
417 #if defined( __GNUC__ ) && defined( i386 )
422 __asm__
__volatile__ (
424 "movl %%edx, %%ecx\n"
426 "addl $0x8000, %%ecx\n"
427 "addl %%ecx, %%eax\n"
431 "addl %%edx, %%eax\n"
445 if ( a
== 0 || b
== 0x10000L
)
448 sa
= ( a
>> ( sizeof ( a
) * 8 - 1 ) );
450 sb
= ( b
>> ( sizeof ( b
) * 8 - 1 ) );
456 if ( ua
<= 2048 && ub
<= 1048576L )
457 ua
= ( ua
* ub
+ 0x8000U
) >> 16;
460 FT_ULong al
= ua
& 0xFFFFU
;
463 ua
= ( ua
>> 16 ) * ub
+ al
* ( ub
>> 16 ) +
464 ( ( al
* ( ub
& 0xFFFFU
) + 0x8000U
) >> 16 );
468 ua
= (FT_ULong
)(( ua
^ sa
) - sa
);
478 if ( a
== 0 || b
== 0x10000L
)
481 s
= a
; a
= FT_ABS( a
);
482 s
^= b
; b
= FT_ABS( b
);
487 if ( ua
<= 2048 && ub
<= 1048576L )
488 ua
= ( ua
* ub
+ 0x8000UL
) >> 16;
491 FT_ULong al
= ua
& 0xFFFFUL
;
494 ua
= ( ua
>> 16 ) * ub
+ al
* ( ub
>> 16 ) +
495 ( ( al
* ( ub
& 0xFFFFUL
) + 0x8000UL
) >> 16 );
498 return ( s
< 0 ? -(FT_Long
)ua
: (FT_Long
)ua
);
505 /* documentation is in freetype.h */
507 FT_EXPORT_DEF( FT_Long
)
508 FT_DivFix( FT_Long a
,
515 s
= a
; a
= FT_ABS(a
);
516 s
^= b
; b
= FT_ABS(b
);
520 /* check for division by 0 */
523 else if ( ( a
>> 16 ) == 0 )
525 /* compute result directly */
526 q
= (FT_UInt32
)( (a
<< 16) + (b
>> 1) ) / (FT_UInt32
)b
;
530 /* we need more bits; we have to do it by hand */
531 FT_Int64 temp
, temp2
;
533 temp
.hi
= (FT_Int32
) (a
>> 16);
534 temp
.lo
= (FT_UInt32
)(a
<< 16);
536 temp2
.lo
= (FT_UInt32
)( b
>> 1 );
537 FT_Add64( &temp
, &temp2
, &temp
);
538 q
= ft_div64by32( temp
.hi
, temp
.lo
, b
);
541 return ( s
< 0 ? -(FT_Int32
)q
: (FT_Int32
)q
);
547 /* documentation is in ftcalc.h */
549 FT_EXPORT_DEF( void )
550 FT_MulTo64( FT_Int32 x
,
557 s
= x
; x
= FT_ABS( x
);
558 s
^= y
; y
= FT_ABS( y
);
560 ft_multo64( x
, y
, z
);
564 z
->lo
= (FT_UInt32
)-(FT_Int32
)z
->lo
;
565 z
->hi
= ~z
->hi
+ !( z
->lo
);
570 /* apparently, the second version of this code is not compiled correctly */
571 /* on Mac machines with the MPW C compiler.. tsk, tsk, tsk... */
575 FT_EXPORT_DEF( FT_Int32
)
576 FT_Div64by32( FT_Int64
* x
,
580 FT_UInt32 q
, r
, i
, lo
;
586 x
->lo
= (FT_UInt32
)-(FT_Int32
)x
->lo
;
587 x
->hi
= ~x
->hi
+ !x
->lo
;
589 s
^= y
; y
= FT_ABS( y
);
599 return ( s
< 0 ? -(FT_Int32
)q
: (FT_Int32
)q
);
605 if ( r
>= (FT_UInt32
)y
) /* we know y is to be treated as unsigned here */
606 return ( s
< 0 ? 0x80000001UL
: 0x7FFFFFFFUL
);
607 /* Return Max/Min Int32 if division overflow. */
608 /* This includes division by zero! */
610 for ( i
= 0; i
< 32; i
++ )
616 if ( r
>= (FT_UInt32
)y
)
624 return ( s
< 0 ? -(FT_Int32
)q
: (FT_Int32
)q
);
629 FT_EXPORT_DEF( FT_Int32
)
630 FT_Div64by32( FT_Int64
* x
,
640 x
->lo
= (FT_UInt32
)-(FT_Int32
)x
->lo
;
641 x
->hi
= ~x
->hi
+ !x
->lo
;
643 s
^= y
; y
= FT_ABS( y
);
649 q
= ( x
->lo
+ ( y
>> 1 ) ) / y
;
653 return ( s
< 0 ? -(FT_Int32
)q
: (FT_Int32
)q
);
656 q
= ft_div64by32( x
->hi
, x
->lo
, y
);
658 return ( s
< 0 ? -(FT_Int32
)q
: (FT_Int32
)q
);
666 #endif /* FT_LONG64 */
669 /* documentation is in ftcalc.h */
671 FT_BASE_DEF( FT_Int32
)
672 FT_SqrtFixed( FT_Int32 x
)
674 FT_UInt32 root
, rem_hi
, rem_lo
, test_div
;
687 rem_hi
= ( rem_hi
<< 2 ) | ( rem_lo
>> 30 );
690 test_div
= ( root
<< 1 ) + 1;
692 if ( rem_hi
>= test_div
)
700 return (FT_Int32
)root
;
704 /* documentation is in ftcalc.h */
706 FT_BASE_DEF( FT_Int
)
707 ft_corner_orientation( FT_Pos in_x
,
715 /* deal with the trivial cases quickly */
723 else if ( in_x
== 0 )
730 else if ( out_y
== 0 )
737 else if ( out_x
== 0 )
744 else /* general case */
748 FT_Int64 delta
= (FT_Int64
)in_x
* out_y
- (FT_Int64
)in_y
* out_x
;
754 result
= 1 - 2 * ( delta
< 0 );
761 ft_multo64( in_x
, out_y
, &z1
);
762 ft_multo64( in_y
, out_x
, &z2
);
766 else if ( z1
.hi
< z2
.hi
)
768 else if ( z1
.lo
> z2
.lo
)
770 else if ( z1
.lo
< z2
.lo
)
782 /* documentation is in ftcalc.h */
784 FT_BASE_DEF( FT_Int
)
785 ft_corner_is_flat( FT_Pos in_x
,
793 FT_Pos d_in
, d_out
, d_corner
;
818 return ( d_in
+ d_out
- d_corner
) < ( d_corner
>> 4 );