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