📄 ftbbox.c
字号:
/***************************************************************************//* *//* ftbbox.c *//* *//* FreeType bbox computation (body). *//* *//* Copyright 1996-2001, 2002, 2004, 2006 by *//* David Turner, Robert Wilhelm, and Werner Lemberg. *//* *//* This file is part of the FreeType project, and may only be used *//* modified and distributed under the terms of the FreeType project *//* license, LICENSE.TXT. By continuing to use, modify, or distribute *//* this file you indicate that you have read the license and *//* understand and accept it fully. *//* *//***************************************************************************/ /*************************************************************************/ /* */ /* This component has a _single_ role: to compute exact outline bounding */ /* boxes. */ /* */ /*************************************************************************/#include <ft2build.h>#include FT_BBOX_H#include FT_IMAGE_H#include FT_OUTLINE_H#include FT_INTERNAL_CALC_H typedef struct TBBox_Rec_ { FT_Vector last; FT_BBox bbox; } TBBox_Rec; /*************************************************************************/ /* */ /* <Function> */ /* BBox_Move_To */ /* */ /* <Description> */ /* This function is used as a `move_to' and `line_to' emitter during */ /* FT_Outline_Decompose(). It simply records the destination point */ /* in `user->last'; no further computations are necessary since we */ /* use the cbox as the starting bbox which must be refined. */ /* */ /* <Input> */ /* to :: A pointer to the destination vector. */ /* */ /* <InOut> */ /* user :: A pointer to the current walk context. */ /* */ /* <Return> */ /* Always 0. Needed for the interface only. */ /* */ static int BBox_Move_To( FT_Vector* to, TBBox_Rec* user ) { user->last = *to; return 0; }#define CHECK_X( p, bbox ) \ ( p->x < bbox.xMin || p->x > bbox.xMax )#define CHECK_Y( p, bbox ) \ ( p->y < bbox.yMin || p->y > bbox.yMax ) /*************************************************************************/ /* */ /* <Function> */ /* BBox_Conic_Check */ /* */ /* <Description> */ /* Finds the extrema of a 1-dimensional conic Bezier curve and update */ /* a bounding range. This version uses direct computation, as it */ /* doesn't need square roots. */ /* */ /* <Input> */ /* y1 :: The start coordinate. */ /* */ /* y2 :: The coordinate of the control point. */ /* */ /* y3 :: The end coordinate. */ /* */ /* <InOut> */ /* min :: The address of the current minimum. */ /* */ /* max :: The address of the current maximum. */ /* */ static void BBox_Conic_Check( FT_Pos y1, FT_Pos y2, FT_Pos y3, FT_Pos* min, FT_Pos* max ) { if ( y1 <= y3 && y2 == y1 ) /* flat arc */ goto Suite; if ( y1 < y3 ) { if ( y2 >= y1 && y2 <= y3 ) /* ascending arc */ goto Suite; } else { if ( y2 >= y3 && y2 <= y1 ) /* descending arc */ { y2 = y1; y1 = y3; y3 = y2; goto Suite; } } y1 = y3 = y1 - FT_MulDiv( y2 - y1, y2 - y1, y1 - 2*y2 + y3 ); Suite: if ( y1 < *min ) *min = y1; if ( y3 > *max ) *max = y3; } /*************************************************************************/ /* */ /* <Function> */ /* BBox_Conic_To */ /* */ /* <Description> */ /* This function is used as a `conic_to' emitter during */ /* FT_Raster_Decompose(). It checks a conic Bezier curve with the */ /* current bounding box, and computes its extrema if necessary to */ /* update it. */ /* */ /* <Input> */ /* control :: A pointer to a 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 compute directly the */ /* extremum coordinates, as it is sufficiently fast. */ /* */ static int BBox_Conic_To( FT_Vector* control, 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( control, user->bbox ) ) BBox_Conic_Check( user->last.x, control->x, to->x, &user->bbox.xMin, &user->bbox.xMax ); if ( CHECK_Y( control, user->bbox ) ) BBox_Conic_Check( user->last.y, control->y, to->y, &user->bbox.yMin, &user->bbox.yMax ); user->last = *to; return 0; } /*************************************************************************/ /* */ /* <Function> */ /* BBox_Cubic_Check */ /* */ /* <Description> */ /* Finds the extrema of a 1-dimensional cubic Bezier curve and */ /* updates a bounding range. This version uses splitting because we */ /* don't want to use square roots and extra accuracy. */ /* */ /* <Input> */ /* p1 :: The start coordinate. */ /* */ /* p2 :: The coordinate of the first control point. */ /* */ /* p3 :: The coordinate of the second control point. */ /* */ /* p4 :: The end coordinate. */ /* */ /* <InOut> */ /* min :: The address of the current minimum. */ /* */ /* max :: The address of the current maximum. */ /* */#if 0 static void BBox_Cubic_Check( FT_Pos p1, FT_Pos p2, FT_Pos p3, FT_Pos p4, FT_Pos* min, FT_Pos* max ) { FT_Pos stack[32*3 + 1], *arc; arc = stack; arc[0] = p1; arc[1] = p2; arc[2] = p3; arc[3] = p4; do { FT_Pos y1 = arc[0]; FT_Pos y2 = arc[1]; FT_Pos y3 = arc[2]; FT_Pos y4 = arc[3]; if ( y1 == y4 ) { if ( y1 == y2 && y1 == y3 ) /* flat */ goto Test; } else if ( y1 < y4 ) { if ( y2 >= y1 && y2 <= y4 && y3 >= y1 && y3 <= y4 ) /* ascending */ goto Test; } else { if ( y2 >= y4 && y2 <= y1 && y3 >= y4 && y3 <= y1 ) /* descending */ { y2 = y1; y1 = y4; y4 = y2; goto Test; } } /* unknown direction -- split the arc in two */ arc[6] = y4; arc[1] = y1 = ( y1 + y2 ) / 2; arc[5] = y4 = ( y4 + y3 ) / 2; y2 = ( y2 + y3 ) / 2; arc[2] = y1 = ( y1 + y2 ) / 2; arc[4] = y4 = ( y4 + y2 ) / 2; arc[3] = ( y1 + y4 ) / 2; arc += 3; goto Suite; Test: if ( y1 < *min ) *min = y1; if ( y4 > *max ) *max = y4; arc -= 3; Suite: ; } while ( arc >= stack ); }#else static void test_cubic_extrema( FT_Pos y1, FT_Pos y2, FT_Pos y3, FT_Pos y4, FT_Fixed u, FT_Pos* min, FT_Pos* max ) { /* FT_Pos a = y4 - 3*y3 + 3*y2 - y1; */ FT_Pos b = y3 - 2*y2 + y1; FT_Pos c = y2 - y1; FT_Pos d = y1; FT_Pos y; FT_Fixed uu; FT_UNUSED ( y4 ); /* The polynomial is */ /* */ /* P(x) = a*x^3 + 3b*x^2 + 3c*x + d , */ /* */ /* dP/dx = 3a*x^2 + 6b*x + 3c . */ /* */ /* However, we also have */ /* */ /* dP/dx(u) = 0 , */ /* */ /* which implies by subtraction that */ /* */ /* P(u) = b*u^2 + 2c*u + d . */ if ( u > 0 && u < 0x10000L ) { uu = FT_MulFix( u, u ); y = d + FT_MulFix( c, 2*u ) + FT_MulFix( b, uu ); if ( y < *min ) *min = y; if ( y > *max ) *max = y; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -