1 /***************************************************************************/
5 /* Arithmetic computations (body). */
7 /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2008 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 /*************************************************************************/
37 #include FT_INTERNAL_CALC_H
38 #include FT_INTERNAL_DEBUG_H
39 #include FT_INTERNAL_OBJECTS_H
42 /* we need to define a 64-bits data type here */
46 typedef FT_INT64 FT_Int64
;
50 typedef struct FT_Int64_
57 #endif /* FT_LONG64 */
60 /*************************************************************************/
62 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
63 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
64 /* messages during execution. */
67 #define FT_COMPONENT trace_calc
70 /* The following three functions are available regardless of whether */
71 /* FT_LONG64 is defined. */
73 /* documentation is in freetype.h */
75 FT_EXPORT_DEF( FT_Fixed
)
76 FT_RoundFix( FT_Fixed a
)
78 return ( a
>= 0 ) ? ( a
+ 0x8000L
) & ~0xFFFFL
79 : -((-a
+ 0x8000L
) & ~0xFFFFL
);
83 /* documentation is in freetype.h */
85 FT_EXPORT_DEF( FT_Fixed
)
86 FT_CeilFix( FT_Fixed a
)
88 return ( a
>= 0 ) ? ( a
+ 0xFFFFL
) & ~0xFFFFL
89 : -((-a
+ 0xFFFFL
) & ~0xFFFFL
);
93 /* documentation is in freetype.h */
95 FT_EXPORT_DEF( FT_Fixed
)
96 FT_FloorFix( FT_Fixed a
)
98 return ( a
>= 0 ) ? a
& ~0xFFFFL
99 : -((-a
) & ~0xFFFFL
);
103 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
105 /* documentation is in ftcalc.h */
107 FT_EXPORT_DEF( FT_Int32
)
108 FT_Sqrt32( FT_Int32 x
)
110 FT_ULong val
, root
, newroot
, mask
;
119 newroot
= root
+ mask
;
120 if ( newroot
<= val
)
123 root
= newroot
+ mask
;
129 } while ( mask
!= 0 );
134 #endif /* FT_CONFIG_OPTION_OLD_INTERNALS */
140 /* documentation is in freetype.h */
142 FT_EXPORT_DEF( FT_Long
)
143 FT_MulDiv( FT_Long a
,
152 if ( a
< 0 ) { a
= -a
; s
= -1; }
153 if ( b
< 0 ) { b
= -b
; s
= -s
; }
154 if ( c
< 0 ) { c
= -c
; s
= -s
; }
156 d
= (FT_Long
)( c
> 0 ? ( (FT_Int64
)a
* b
+ ( c
>> 1 ) ) / c
159 return ( s
> 0 ) ? d
: -d
;
163 #ifdef TT_USE_BYTECODE_INTERPRETER
165 /* documentation is in ftcalc.h */
167 FT_BASE_DEF( FT_Long
)
168 FT_MulDiv_No_Round( FT_Long a
,
177 if ( a
< 0 ) { a
= -a
; s
= -1; }
178 if ( b
< 0 ) { b
= -b
; s
= -s
; }
179 if ( c
< 0 ) { c
= -c
; s
= -s
; }
181 d
= (FT_Long
)( c
> 0 ? (FT_Int64
)a
* b
/ c
184 return ( s
> 0 ) ? d
: -d
;
187 #endif /* TT_USE_BYTECODE_INTERPRETER */
190 /* documentation is in freetype.h */
192 FT_EXPORT_DEF( FT_Long
)
193 FT_MulFix( FT_Long a
,
200 if ( a
< 0 ) { a
= -a
; s
= -1; }
201 if ( b
< 0 ) { b
= -b
; s
= -s
; }
203 c
= (FT_Long
)( ( (FT_Int64
)a
* b
+ 0x8000L
) >> 16 );
204 return ( s
> 0 ) ? c
: -c
;
208 /* documentation is in freetype.h */
210 FT_EXPORT_DEF( FT_Long
)
211 FT_DivFix( FT_Long a
,
218 if ( a
< 0 ) { a
= -a
; s
= -1; }
219 if ( b
< 0 ) { b
= -b
; s
= -s
; }
222 /* check for division by 0 */
225 /* compute result directly */
226 q
= (FT_UInt32
)( ( ( (FT_Int64
)a
<< 16 ) + ( b
>> 1 ) ) / b
);
228 return ( s
< 0 ? -(FT_Long
)q
: (FT_Long
)q
);
232 #else /* !FT_LONG64 */
236 ft_multo64( FT_UInt32 x
,
240 FT_UInt32 lo1
, hi1
, lo2
, hi2
, lo
, hi
, i1
, i2
;
243 lo1
= x
& 0x0000FFFFU
; hi1
= x
>> 16;
244 lo2
= y
& 0x0000FFFFU
; hi2
= y
>> 16;
251 /* Check carry overflow of i1 + i2 */
253 hi
+= (FT_UInt32
)( i1
< i2
) << 16;
258 /* Check carry overflow of i1 + lo */
268 ft_div64by32( FT_UInt32 hi
,
280 return (FT_UInt32
)0x7FFFFFFFL
;
289 if ( r
>= (FT_UInt32
)y
)
302 FT_Add64( FT_Int64
* x
,
306 register FT_UInt32 lo
, hi
;
310 hi
= x
->hi
+ y
->hi
+ ( lo
< x
->lo
);
317 /* documentation is in freetype.h */
319 /* The FT_MulDiv function has been optimized thanks to ideas from */
320 /* Graham Asher. The trick is to optimize computation when everything */
321 /* fits within 32-bits (a rather common case). */
323 /* we compute 'a*b+c/2', then divide it by 'c'. (positive values) */
325 /* 46340 is FLOOR(SQRT(2^31-1)). */
327 /* if ( a <= 46340 && b <= 46340 ) then ( a*b <= 0x7FFEA810 ) */
329 /* 0x7FFFFFFF - 0x7FFEA810 = 0x157F0 */
331 /* if ( c < 0x157F0*2 ) then ( a*b+c/2 <= 0x7FFFFFFF ) */
333 /* and 2*0x157F0 = 176096 */
336 FT_EXPORT_DEF( FT_Long
)
337 FT_MulDiv( FT_Long a
,
344 if ( a
== 0 || b
== c
)
347 s
= a
; a
= FT_ABS( a
);
348 s
^= b
; b
= FT_ABS( b
);
349 s
^= c
; c
= FT_ABS( c
);
351 if ( a
<= 46340L && b
<= 46340L && c
<= 176095L && c
> 0 )
352 a
= ( a
* b
+ ( c
>> 1 ) ) / c
;
356 FT_Int64 temp
, temp2
;
359 ft_multo64( a
, b
, &temp
);
362 temp2
.lo
= (FT_UInt32
)(c
>> 1);
363 FT_Add64( &temp
, &temp2
, &temp
);
364 a
= ft_div64by32( temp
.hi
, temp
.lo
, c
);
369 return ( s
< 0 ? -a
: a
);
373 #ifdef TT_USE_BYTECODE_INTERPRETER
375 FT_BASE_DEF( FT_Long
)
376 FT_MulDiv_No_Round( FT_Long a
,
383 if ( a
== 0 || b
== c
)
386 s
= a
; a
= FT_ABS( a
);
387 s
^= b
; b
= FT_ABS( b
);
388 s
^= c
; c
= FT_ABS( c
);
390 if ( a
<= 46340L && b
<= 46340L && c
> 0 )
398 ft_multo64( a
, b
, &temp
);
399 a
= ft_div64by32( temp
.hi
, temp
.lo
, c
);
404 return ( s
< 0 ? -a
: a
);
407 #endif /* TT_USE_BYTECODE_INTERPRETER */
410 /* documentation is in freetype.h */
412 FT_EXPORT_DEF( FT_Long
)
413 FT_MulFix( FT_Long a
,
416 /* use inline assembly to speed up things a bit */
418 #if defined( __GNUC__ ) && defined( i386 )
423 __asm__
__volatile__ (
425 "movl %%edx, %%ecx\n"
427 "addl $0x8000, %%ecx\n"
428 "addl %%ecx, %%eax\n"
432 "addl %%edx, %%eax\n"
434 : "=a"(result
), "+d"(b
)
446 if ( a
== 0 || b
== 0x10000L
)
449 sa
= ( a
>> ( sizeof ( a
) * 8 - 1 ) );
451 sb
= ( b
>> ( sizeof ( b
) * 8 - 1 ) );
457 if ( ua
<= 2048 && ub
<= 1048576L )
458 ua
= ( ua
* ub
+ 0x8000U
) >> 16;
461 FT_ULong al
= ua
& 0xFFFFU
;
464 ua
= ( ua
>> 16 ) * ub
+ al
* ( ub
>> 16 ) +
465 ( ( al
* ( ub
& 0xFFFFU
) + 0x8000U
) >> 16 );
469 ua
= (FT_ULong
)(( ua
^ sa
) - sa
);
479 if ( a
== 0 || b
== 0x10000L
)
482 s
= a
; a
= FT_ABS( a
);
483 s
^= b
; b
= FT_ABS( b
);
488 if ( ua
<= 2048 && ub
<= 1048576L )
489 ua
= ( ua
* ub
+ 0x8000UL
) >> 16;
492 FT_ULong al
= ua
& 0xFFFFUL
;
495 ua
= ( ua
>> 16 ) * ub
+ al
* ( ub
>> 16 ) +
496 ( ( al
* ( ub
& 0xFFFFUL
) + 0x8000UL
) >> 16 );
499 return ( s
< 0 ? -(FT_Long
)ua
: (FT_Long
)ua
);
506 /* documentation is in freetype.h */
508 FT_EXPORT_DEF( FT_Long
)
509 FT_DivFix( FT_Long a
,
516 s
= a
; a
= FT_ABS( a
);
517 s
^= b
; b
= FT_ABS( b
);
521 /* check for division by 0 */
524 else if ( ( a
>> 16 ) == 0 )
526 /* compute result directly */
527 q
= (FT_UInt32
)( (a
<< 16) + (b
>> 1) ) / (FT_UInt32
)b
;
531 /* we need more bits; we have to do it by hand */
532 FT_Int64 temp
, temp2
;
534 temp
.hi
= (FT_Int32
) (a
>> 16);
535 temp
.lo
= (FT_UInt32
)(a
<< 16);
537 temp2
.lo
= (FT_UInt32
)( b
>> 1 );
538 FT_Add64( &temp
, &temp2
, &temp
);
539 q
= ft_div64by32( temp
.hi
, temp
.lo
, b
);
542 return ( s
< 0 ? -(FT_Int32
)q
: (FT_Int32
)q
);
548 /* documentation is in ftcalc.h */
550 FT_EXPORT_DEF( void )
551 FT_MulTo64( FT_Int32 x
,
558 s
= x
; x
= FT_ABS( x
);
559 s
^= y
; y
= FT_ABS( y
);
561 ft_multo64( x
, y
, z
);
565 z
->lo
= (FT_UInt32
)-(FT_Int32
)z
->lo
;
566 z
->hi
= ~z
->hi
+ !( z
->lo
);
571 /* apparently, the second version of this code is not compiled correctly */
572 /* on Mac machines with the MPW C compiler.. tsk, tsk, tsk... */
576 FT_EXPORT_DEF( FT_Int32
)
577 FT_Div64by32( FT_Int64
* x
,
581 FT_UInt32 q
, r
, i
, lo
;
587 x
->lo
= (FT_UInt32
)-(FT_Int32
)x
->lo
;
588 x
->hi
= ~x
->hi
+ !x
->lo
;
590 s
^= y
; y
= FT_ABS( y
);
600 return ( s
< 0 ? -(FT_Int32
)q
: (FT_Int32
)q
);
606 if ( r
>= (FT_UInt32
)y
) /* we know y is to be treated as unsigned here */
607 return ( s
< 0 ? 0x80000001UL
: 0x7FFFFFFFUL
);
608 /* Return Max/Min Int32 if division overflow. */
609 /* This includes division by zero! */
611 for ( i
= 0; i
< 32; i
++ )
617 if ( r
>= (FT_UInt32
)y
)
625 return ( s
< 0 ? -(FT_Int32
)q
: (FT_Int32
)q
);
630 FT_EXPORT_DEF( FT_Int32
)
631 FT_Div64by32( FT_Int64
* x
,
641 x
->lo
= (FT_UInt32
)-(FT_Int32
)x
->lo
;
642 x
->hi
= ~x
->hi
+ !x
->lo
;
644 s
^= y
; y
= FT_ABS( y
);
650 q
= ( x
->lo
+ ( y
>> 1 ) ) / y
;
654 return ( s
< 0 ? -(FT_Int32
)q
: (FT_Int32
)q
);
657 q
= ft_div64by32( x
->hi
, x
->lo
, y
);
659 return ( s
< 0 ? -(FT_Int32
)q
: (FT_Int32
)q
);
667 #endif /* FT_LONG64 */
670 /* documentation is in ftglyph.h */
672 FT_EXPORT_DEF( void )
673 FT_Matrix_Multiply( const FT_Matrix
* a
,
676 FT_Fixed xx
, xy
, yx
, yy
;
682 xx
= FT_MulFix( a
->xx
, b
->xx
) + FT_MulFix( a
->xy
, b
->yx
);
683 xy
= FT_MulFix( a
->xx
, b
->xy
) + FT_MulFix( a
->xy
, b
->yy
);
684 yx
= FT_MulFix( a
->yx
, b
->xx
) + FT_MulFix( a
->yy
, b
->yx
);
685 yy
= FT_MulFix( a
->yx
, b
->xy
) + FT_MulFix( a
->yy
, b
->yy
);
687 b
->xx
= xx
; b
->xy
= xy
;
688 b
->yx
= yx
; b
->yy
= yy
;
692 /* documentation is in ftglyph.h */
694 FT_EXPORT_DEF( FT_Error
)
695 FT_Matrix_Invert( FT_Matrix
* matrix
)
697 FT_Pos delta
, xx
, yy
;
701 return FT_Err_Invalid_Argument
;
703 /* compute discriminant */
704 delta
= FT_MulFix( matrix
->xx
, matrix
->yy
) -
705 FT_MulFix( matrix
->xy
, matrix
->yx
);
708 return FT_Err_Invalid_Argument
; /* matrix can't be inverted */
710 matrix
->xy
= - FT_DivFix( matrix
->xy
, delta
);
711 matrix
->yx
= - FT_DivFix( matrix
->yx
, delta
);
716 matrix
->xx
= FT_DivFix( yy
, delta
);
717 matrix
->yy
= FT_DivFix( xx
, delta
);
723 /* documentation is in ftcalc.h */
726 FT_Matrix_Multiply_Scaled( const FT_Matrix
* a
,
730 FT_Fixed xx
, xy
, yx
, yy
;
732 FT_Long val
= 0x10000L
* scaling
;
738 xx
= FT_MulDiv( a
->xx
, b
->xx
, val
) + FT_MulDiv( a
->xy
, b
->yx
, val
);
739 xy
= FT_MulDiv( a
->xx
, b
->xy
, val
) + FT_MulDiv( a
->xy
, b
->yy
, val
);
740 yx
= FT_MulDiv( a
->yx
, b
->xx
, val
) + FT_MulDiv( a
->yy
, b
->yx
, val
);
741 yy
= FT_MulDiv( a
->yx
, b
->xy
, val
) + FT_MulDiv( a
->yy
, b
->yy
, val
);
743 b
->xx
= xx
; b
->xy
= xy
;
744 b
->yx
= yx
; b
->yy
= yy
;
748 /* documentation is in ftcalc.h */
751 FT_Vector_Transform_Scaled( FT_Vector
* vector
,
752 const FT_Matrix
* matrix
,
757 FT_Long val
= 0x10000L
* scaling
;
760 if ( !vector
|| !matrix
)
763 xz
= FT_MulDiv( vector
->x
, matrix
->xx
, val
) +
764 FT_MulDiv( vector
->y
, matrix
->xy
, val
);
766 yz
= FT_MulDiv( vector
->x
, matrix
->yx
, val
) +
767 FT_MulDiv( vector
->y
, matrix
->yy
, val
);
774 /* documentation is in ftcalc.h */
776 FT_BASE_DEF( FT_Int32
)
777 FT_SqrtFixed( FT_Int32 x
)
779 FT_UInt32 root
, rem_hi
, rem_lo
, test_div
;
792 rem_hi
= ( rem_hi
<< 2 ) | ( rem_lo
>> 30 );
795 test_div
= ( root
<< 1 ) + 1;
797 if ( rem_hi
>= test_div
)
805 return (FT_Int32
)root
;
809 /* documentation is in ftcalc.h */
811 FT_BASE_DEF( FT_Int
)
812 ft_corner_orientation( FT_Pos in_x
,
820 /* deal with the trivial cases quickly */
828 else if ( in_x
== 0 )
835 else if ( out_y
== 0 )
842 else if ( out_x
== 0 )
849 else /* general case */
853 FT_Int64 delta
= (FT_Int64
)in_x
* out_y
- (FT_Int64
)in_y
* out_x
;
859 result
= 1 - 2 * ( delta
< 0 );
866 ft_multo64( in_x
, out_y
, &z1
);
867 ft_multo64( in_y
, out_x
, &z2
);
871 else if ( z1
.hi
< z2
.hi
)
873 else if ( z1
.lo
> z2
.lo
)
875 else if ( z1
.lo
< z2
.lo
)
887 /* documentation is in ftcalc.h */
889 FT_BASE_DEF( FT_Int
)
890 ft_corner_is_flat( FT_Pos in_x
,
898 FT_Pos d_in
, d_out
, d_corner
;
923 return ( d_in
+ d_out
- d_corner
) < ( d_corner
>> 4 );