⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ftbbox.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 2 页
字号:
  static void
  BBox_Cubic_Check( FT_Pos   y1,
                    FT_Pos   y2,
                    FT_Pos   y3,
                    FT_Pos   y4,
                    FT_Pos*  min,
                    FT_Pos*  max )
  {
    /* always compare first and last points */
    if      ( y1 < *min )  *min = y1;
    else if ( y1 > *max )  *max = y1;

    if      ( y4 < *min )  *min = y4;
    else if ( y4 > *max )  *max = y4;

    /* now, try to see if there are split points here */
    if ( y1 <= y4 )
    {
      /* flat or ascending arc test */
      if ( y1 <= y2 && y2 <= y4 && y1 <= y3 && y3 <= y4 )
        return;
    }
    else /* y1 > y4 */
    {
      /* descending arc test */
      if ( y1 >= y2 && y2 >= y4 && y1 >= y3 && y3 >= y4 )
        return;
    }

    /* There are some split points.  Find them. */
    {
      FT_Pos    a = y4 - 3*y3 + 3*y2 - y1;
      FT_Pos    b = y3 - 2*y2 + y1;
      FT_Pos    c = y2 - y1;
      FT_Pos    d;
      FT_Fixed  t;


      /* We need to solve `ax^2+2bx+c' here, without floating points!      */
      /* The trick is to normalize to a different representation in order  */
      /* to use our 16.16 fixed point routines.                            */
      /*                                                                   */
      /* We compute FT_MulFix(b,b) and FT_MulFix(a,c) after normalization. */
      /* These values must fit into a single 16.16 value.                  */
      /*                                                                   */
      /* We normalize a, b, and c to `8.16' fixed float values to ensure   */
      /* that its product is held in a `16.16' value.                      */

      {
        FT_ULong  t1, t2;
        int       shift = 0;


        /* The following computation is based on the fact that for   */
        /* any value `y', if `n' is the position of the most         */
        /* significant bit of `abs(y)' (starting from 0 for the      */
        /* least significant bit), then `y' is in the range          */
        /*                                                           */
        /*   -2^n..2^n-1                                             */
        /*                                                           */
        /* We want to shift `a', `b', and `c' concurrently in order  */
        /* to ensure that they all fit in 8.16 values, which maps    */
        /* to the integer range `-2^23..2^23-1'.                     */
        /*                                                           */
        /* Necessarily, we need to shift `a', `b', and `c' so that   */
        /* the most significant bit of its absolute values is at     */
        /* _most_ at position 23.                                    */
        /*                                                           */
        /* We begin by computing `t1' as the bitwise `OR' of the     */
        /* absolute values of `a', `b', `c'.                         */

        t1  = (FT_ULong)( ( a >= 0 ) ? a : -a );
        t2  = (FT_ULong)( ( b >= 0 ) ? b : -b );
        t1 |= t2;
        t2  = (FT_ULong)( ( c >= 0 ) ? c : -c );
        t1 |= t2;

        /* Now we can be sure that the most significant bit of `t1'  */
        /* is the most significant bit of either `a', `b', or `c',   */
        /* depending on the greatest integer range of the particular */
        /* variable.                                                 */
        /*                                                           */
        /* Next, we compute the `shift', by shifting `t1' as many    */
        /* times as necessary to move its MSB to position 23.  This  */
        /* corresponds to a value of `t1' that is in the range       */
        /* 0x40_0000..0x7F_FFFF.                                     */
        /*                                                           */
        /* Finally, we shift `a', `b', and `c' by the same amount.   */
        /* This ensures that all values are now in the range         */
        /* -2^23..2^23, i.e., they are now expressed as 8.16         */
        /* fixed-float numbers.  This also means that we are using   */
        /* 24 bits of precision to compute the zeros, independently  */
        /* of the range of the original polynomial coefficients.     */
        /*                                                           */
        /* This algorithm should ensure reasonably accurate values   */
        /* for the zeros.  Note that they are only expressed with    */
        /* 16 bits when computing the extrema (the zeros need to     */
        /* be in 0..1 exclusive to be considered part of the arc).   */

        if ( t1 == 0 )  /* all coefficients are 0! */
          return;

        if ( t1 > 0x7FFFFFUL )
        {
          do
          {
            shift++;
            t1 >>= 1;

          } while ( t1 > 0x7FFFFFUL );

          /* this loses some bits of precision, but we use 24 of them */
          /* for the computation anyway                               */
          a >>= shift;
          b >>= shift;
          c >>= shift;
        }
        else if ( t1 < 0x400000UL )
        {
          do
          {
            shift++;
            t1 <<= 1;

          } while ( t1 < 0x400000UL );

          a <<= shift;
          b <<= shift;
          c <<= shift;
        }
      }

      /* handle a == 0 */
      if ( a == 0 )
      {
        if ( b != 0 )
        {
          t = - FT_DivFix( c, b ) / 2;
          test_cubic_extrema( y1, y2, y3, y4, t, min, max );
        }
      }
      else
      {
        /* solve the equation now */
        d = FT_MulFix( b, b ) - FT_MulFix( a, c );
        if ( d < 0 )
          return;

        if ( d == 0 )
        {
          /* there is a single split point at -b/a */
          t = - FT_DivFix( b, a );
          test_cubic_extrema( y1, y2, y3, y4, t, min, max );
        }
        else
        {
          /* there are two solutions; we need to filter them */
          d = FT_SqrtFixed( (FT_Int32)d );
          t = - FT_DivFix( b - d, a );
          test_cubic_extrema( y1, y2, y3, y4, t, min, max );

          t = - FT_DivFix( b + d, a );
          test_cubic_extrema( y1, y2, y3, y4, t, min, max );
        }
      }
    }
  }

#endif


  /*************************************************************************/
  /*                                                                       */
  /* <Function>                                                            */
  /*    BBox_Cubic_To                                                      */
  /*                                                                       */
  /* <Description>                                                         */
  /*    This function is used as a `cubic_to' emitter during               */
  /*    FT_Raster_Decompose().  It checks a cubic Bezier curve with the    */
  /*    current bounding box, and computes its extrema if necessary to     */
  /*    update it.                                                         */
  /*                                                                       */
  /* <Input>                                                               */
  /*    control1 :: A pointer to the first control point.                  */
  /*                                                                       */
  /*    control2 :: A pointer to the second control point.                 */
  /*                                                                       */
  /*    to       :: A pointer to the destination vector.                   */
  /*                                                                       */
  /* <InOut>                                                               */
  /*    user     :: The address of the current walk context.               */
  /*                                                                       */
  /* <Return>                                                              */
  /*    Always 0.  Needed for the interface only.                          */
  /*                                                                       */
  /* <Note>                                                                */
  /*    In the case of a non-monotonous arc, we don't compute directly     */
  /*    extremum coordinates, we subdivide instead.                        */
  /*                                                                       */
  static int
  BBox_Cubic_To( FT_Vector*  control1,
                 FT_Vector*  control2,
                 FT_Vector*  to,
                 TBBox_Rec*  user )
  {
    /* we don't need to check `to' since it is always an `on' point, thus */
    /* within the bbox                                                    */

    if ( CHECK_X( control1, user->bbox ) ||
         CHECK_X( control2, user->bbox ) )
      BBox_Cubic_Check( user->last.x,
                        control1->x,
                        control2->x,
                        to->x,
                        &user->bbox.xMin,
                        &user->bbox.xMax );

    if ( CHECK_Y( control1, user->bbox ) ||
         CHECK_Y( control2, user->bbox ) )
      BBox_Cubic_Check( user->last.y,
                        control1->y,
                        control2->y,
                        to->y,
                        &user->bbox.yMin,
                        &user->bbox.yMax );

    user->last = *to;

    return 0;
  }


  /* documentation is in ftbbox.h */

  FT_EXPORT_DEF( FT_Error )
  FT_Outline_Get_BBox( FT_Outline*  outline,
                       FT_BBox     *abbox )
  {
    FT_BBox     cbox;
    FT_BBox     bbox;
    FT_Vector*  vec;
    FT_UShort   n;


    if ( !abbox )
      return FT_Err_Invalid_Argument;

    if ( !outline )
      return FT_Err_Invalid_Outline;

    /* if outline is empty, return (0,0,0,0) */
    if ( outline->n_points == 0 || outline->n_contours <= 0 )
    {
      abbox->xMin = abbox->xMax = 0;
      abbox->yMin = abbox->yMax = 0;
      return 0;
    }

    /* We compute the control box as well as the bounding box of  */
    /* all `on' points in the outline.  Then, if the two boxes    */
    /* coincide, we exit immediately.                             */

    vec = outline->points;
    bbox.xMin = bbox.xMax = cbox.xMin = cbox.xMax = vec->x;
    bbox.yMin = bbox.yMax = cbox.yMin = cbox.yMax = vec->y;
    vec++;

    for ( n = 1; n < outline->n_points; n++ )
    {
      FT_Pos  x = vec->x;
      FT_Pos  y = vec->y;


      /* update control box */
      if ( x < cbox.xMin ) cbox.xMin = x;
      if ( x > cbox.xMax ) cbox.xMax = x;

      if ( y < cbox.yMin ) cbox.yMin = y;
      if ( y > cbox.yMax ) cbox.yMax = y;

      if ( FT_CURVE_TAG( outline->tags[n] ) == FT_CURVE_TAG_ON )
      {
        /* update bbox for `on' points only */
        if ( x < bbox.xMin ) bbox.xMin = x;
        if ( x > bbox.xMax ) bbox.xMax = x;

        if ( y < bbox.yMin ) bbox.yMin = y;
        if ( y > bbox.yMax ) bbox.yMax = y;
      }

      vec++;
    }

    /* test two boxes for equality */
    if ( cbox.xMin < bbox.xMin || cbox.xMax > bbox.xMax ||
         cbox.yMin < bbox.yMin || cbox.yMax > bbox.yMax )
    {
      /* the two boxes are different, now walk over the outline to */
      /* get the Bezier arc extrema.                               */

      static const FT_Outline_Funcs  bbox_interface =
      {
        (FT_Outline_MoveTo_Func) BBox_Move_To,
        (FT_Outline_LineTo_Func) BBox_Move_To,
        (FT_Outline_ConicTo_Func)BBox_Conic_To,
        (FT_Outline_CubicTo_Func)BBox_Cubic_To,
        0, 0
      };

      FT_Error   error;
      TBBox_Rec  user;


      user.bbox = bbox;

      error = FT_Outline_Decompose( outline, &bbox_interface, &user );
      if ( error )
        return error;

      *abbox = user.bbox;
    }
    else
      *abbox = bbox;

    return FT_Err_Ok;
  }


/* END */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -