cf2_blues_init( CF2_Blues blues, CF2_Font font ) { /* pointer to parsed font object */ CFF_Decoder* decoder = font->decoder; CF2_Fixed zoneHeight; CF2_Fixed maxZoneHeight = 0; CF2_Fixed csUnitsPerPixel; size_t numBlueValues; size_t numOtherBlues; size_t numFamilyBlues; size_t numFamilyOtherBlues; FT_Pos* blueValues; FT_Pos* otherBlues; FT_Pos* familyBlues; FT_Pos* familyOtherBlues; size_t i; CF2_Fixed emBoxBottom, emBoxTop; CF2_Int unitsPerEm = font->unitsPerEm; if ( unitsPerEm == 0 ) unitsPerEm = 1000; FT_ZERO( blues ); blues->scale = font->innerTransform.d; cf2_getBlueMetrics( decoder, &blues->blueScale, &blues->blueShift, &blues->blueFuzz ); cf2_getBlueValues( decoder, &numBlueValues, &blueValues ); cf2_getOtherBlues( decoder, &numOtherBlues, &otherBlues ); cf2_getFamilyBlues( decoder, &numFamilyBlues, &familyBlues ); cf2_getFamilyOtherBlues( decoder, &numFamilyOtherBlues, &familyOtherBlues ); /* * synthetic em box hint heuristic * * Apply this when ideographic dictionary (LanguageGroup 1) has no * real alignment zones. Adobe tools generate dummy zones at -250 and * 1100 for a 1000 unit em. Fonts with ICF-based alignment zones * should not enable the heuristic. When the heuristic is enabled, * the font's blue zones are ignored. * */ /* get em box from OS/2 typoAscender/Descender */ /* TODO: FreeType does not parse these metrics. Skip them for now. */ #if 0 FCM_getHorizontalLineMetrics( &e, font->font, &ascender, &descender, &linegap ); if ( ascender - descender == unitsPerEm ) { emBoxBottom = cf2_intToFixed( descender ); emBoxTop = cf2_intToFixed( ascender ); } else #endif { emBoxBottom = CF2_ICF_Bottom; emBoxTop = CF2_ICF_Top; } if ( cf2_getLanguageGroup( decoder ) == 1 && ( numBlueValues == 0 || ( numBlueValues == 4 && cf2_blueToFixed( blueValues[0] ) < emBoxBottom && cf2_blueToFixed( blueValues[1] ) < emBoxBottom && cf2_blueToFixed( blueValues[2] ) > emBoxTop && cf2_blueToFixed( blueValues[3] ) > emBoxTop ) ) ) { /* * Construct hint edges suitable for synthetic ghost hints at top * and bottom of em box. +-CF2_MIN_COUNTER allows for unhinted * features above or below the last hinted edge. This also gives a * net 1 pixel boost to the height of ideographic glyphs. * * Note: Adjust synthetic hints outward by epsilon (0x.0001) to * avoid interference. E.g., some fonts have real hints at * 880 and -120. */ blues->emBoxBottomEdge.csCoord = emBoxBottom - CF2_FIXED_EPSILON; blues->emBoxBottomEdge.dsCoord = cf2_fixedRound( FT_MulFix( blues->emBoxBottomEdge.csCoord, blues->scale ) ) - CF2_MIN_COUNTER; blues->emBoxBottomEdge.scale = blues->scale; blues->emBoxBottomEdge.flags = CF2_GhostBottom | CF2_Locked | CF2_Synthetic; blues->emBoxTopEdge.csCoord = emBoxTop + CF2_FIXED_EPSILON + 2 * font->darkenY; blues->emBoxTopEdge.dsCoord = cf2_fixedRound( FT_MulFix( blues->emBoxTopEdge.csCoord, blues->scale ) ) + CF2_MIN_COUNTER; blues->emBoxTopEdge.scale = blues->scale; blues->emBoxTopEdge.flags = CF2_GhostTop | CF2_Locked | CF2_Synthetic; blues->doEmBoxHints = TRUE; /* enable the heuristic */ return; } /* copy `BlueValues' and `OtherBlues' to a combined array of top and */ /* bottom zones */ for ( i = 0; i < numBlueValues; i += 2 ) { blues->zone[blues->count].csBottomEdge = cf2_blueToFixed( blueValues[i] ); blues->zone[blues->count].csTopEdge = cf2_blueToFixed( blueValues[i + 1] ); zoneHeight = blues->zone[blues->count].csTopEdge - blues->zone[blues->count].csBottomEdge; if ( zoneHeight < 0 ) { FT_TRACE4(( "cf2_blues_init: ignoring negative zone height\n" )); continue; /* reject this zone */ } if ( zoneHeight > maxZoneHeight ) { /* take maximum before darkening adjustment */ /* so overshoot suppression point doesn't change */ maxZoneHeight = zoneHeight; } /* adjust both edges of top zone upward by twice darkening amount */ if ( i != 0 ) { blues->zone[blues->count].csTopEdge += 2 * font->darkenY; blues->zone[blues->count].csBottomEdge += 2 * font->darkenY; } /* first `BlueValue' is bottom zone; others are top */ if ( i == 0 ) { blues->zone[blues->count].bottomZone = TRUE; blues->zone[blues->count].csFlatEdge = blues->zone[blues->count].csTopEdge; } else { blues->zone[blues->count].bottomZone = FALSE; blues->zone[blues->count].csFlatEdge = blues->zone[blues->count].csBottomEdge; } blues->count += 1; } for ( i = 0; i < numOtherBlues; i += 2 ) { blues->zone[blues->count].csBottomEdge = cf2_blueToFixed( otherBlues[i] ); blues->zone[blues->count].csTopEdge = cf2_blueToFixed( otherBlues[i + 1] ); zoneHeight = blues->zone[blues->count].csTopEdge - blues->zone[blues->count].csBottomEdge; if ( zoneHeight < 0 ) { FT_TRACE4(( "cf2_blues_init: ignoring negative zone height\n" )); continue; /* reject this zone */ } if ( zoneHeight > maxZoneHeight ) { /* take maximum before darkening adjustment */ /* so overshoot suppression point doesn't change */ maxZoneHeight = zoneHeight; } /* Note: bottom zones are not adjusted for darkening amount */ /* all OtherBlues are bottom zone */ blues->zone[blues->count].bottomZone = TRUE; blues->zone[blues->count].csFlatEdge = blues->zone[blues->count].csTopEdge; blues->count += 1; } /* Adjust for FamilyBlues */ /* Search for the nearest flat edge in `FamilyBlues' or */ /* `FamilyOtherBlues'. According to the Black Book, any matching edge */ /* must be within one device pixel */ csUnitsPerPixel = FT_DivFix( cf2_intToFixed( 1 ), blues->scale ); /* loop on all zones in this font */ for ( i = 0; i < blues->count; i++ ) { size_t j; CF2_Fixed minDiff; CF2_Fixed flatFamilyEdge, diff; /* value for this font */ CF2_Fixed flatEdge = blues->zone[i].csFlatEdge; if ( blues->zone[i].bottomZone ) { /* In a bottom zone, the top edge is the flat edge. */ /* Search `FamilyOtherBlues' for bottom zones; look for closest */ /* Family edge that is within the one pixel threshold. */ minDiff = CF2_FIXED_MAX; for ( j = 0; j < numFamilyOtherBlues; j += 2 ) { /* top edge */ flatFamilyEdge = cf2_blueToFixed( familyOtherBlues[j + 1] ); diff = cf2_fixedAbs( flatEdge - flatFamilyEdge ); if ( diff < minDiff && diff < csUnitsPerPixel ) { blues->zone[i].csFlatEdge = flatFamilyEdge; minDiff = diff; if ( diff == 0 ) break; } } /* check the first member of FamilyBlues, which is a bottom zone */ if ( numFamilyBlues >= 2 ) { /* top edge */ flatFamilyEdge = cf2_blueToFixed( familyBlues[1] ); diff = cf2_fixedAbs( flatEdge - flatFamilyEdge ); if ( diff < minDiff && diff < csUnitsPerPixel ) blues->zone[i].csFlatEdge = flatFamilyEdge; } } else { /* In a top zone, the bottom edge is the flat edge. */ /* Search `FamilyBlues' for top zones; skip first zone, which is a */ /* bottom zone; look for closest Family edge that is within the */ /* one pixel threshold */ minDiff = CF2_FIXED_MAX; for ( j = 2; j < numFamilyBlues; j += 2 ) { /* bottom edge */ flatFamilyEdge = cf2_blueToFixed( familyBlues[j] ); /* adjust edges of top zone upward by twice darkening amount */ flatFamilyEdge += 2 * font->darkenY; /* bottom edge */ diff = cf2_fixedAbs( flatEdge - flatFamilyEdge ); if ( diff < minDiff && diff < csUnitsPerPixel ) { blues->zone[i].csFlatEdge = flatFamilyEdge; minDiff = diff; if ( diff == 0 ) break; } } } } /* TODO: enforce separation of zones, including BlueFuzz */ /* Adjust BlueScale; similar to AdjustBlueScale() in coretype */ /* `bcsetup.c'. */ if ( maxZoneHeight > 0 ) { if ( blues->blueScale > FT_DivFix( cf2_intToFixed( 1 ), maxZoneHeight ) ) { /* clamp at maximum scale */ blues->blueScale = FT_DivFix( cf2_intToFixed( 1 ), maxZoneHeight ); } /* * TODO: Revisit the bug fix for 613448. The minimum scale * requirement catches a number of library fonts. For * example, with default BlueScale (.039625) and 0.4 minimum, * the test below catches any font with maxZoneHeight < 10.1. * There are library fonts ranging from 2 to 10 that get * caught, including e.g., Eurostile LT Std Medium with * maxZoneHeight of 6. * */ #if 0 if ( blueScale < .4 / maxZoneHeight ) { tetraphilia_assert( 0 ); /* clamp at minimum scale, per bug 0613448 fix */ blueScale = .4 / maxZoneHeight; } #endif } /* * Suppress overshoot and boost blue zones at small sizes. Boost * amount varies linearly from 0.5 pixel near 0 to 0 pixel at * blueScale cutoff. * Note: This boost amount is different from the coretype heuristic. * */ if ( blues->scale < blues->blueScale ) { blues->suppressOvershoot = TRUE; /* Change rounding threshold for `dsFlatEdge'. */ /* Note: constant changed from 0.5 to 0.6 to avoid a problem with */ /* 10ppem Arial */ blues->boost = FT_MulFix( cf2_floatToFixed( .6 ), ( cf2_intToFixed( 1 ) - FT_DivFix( blues->scale, blues->blueScale ) ) ); if ( blues->boost > 0x7FFF ) { /* boost must remain less than 0.5, or baseline could go negative */ blues->boost = 0x7FFF; } } /* boost and darkening have similar effects; don't do both */ if ( font->stemDarkened ) blues->boost = 0; /* set device space alignment for each zone; */ /* apply boost amount before rounding flat edge */ for ( i = 0; i < blues->count; i++ ) { if ( blues->zone[i].bottomZone ) blues->zone[i].dsFlatEdge = cf2_fixedRound( FT_MulFix( blues->zone[i].csFlatEdge, blues->scale ) - blues->boost ); else blues->zone[i].dsFlatEdge = cf2_fixedRound( FT_MulFix( blues->zone[i].csFlatEdge, blues->scale ) + blues->boost ); } }
static void cf2_doFlex( CF2_Stack opStack, CF2_Fixed* curX, CF2_Fixed* curY, CF2_GlyphPath glyphPath, const FT_Bool* readFromStack, FT_Bool doConditionalLastRead ) { CF2_Fixed vals[14]; CF2_UInt index; FT_Bool isHFlex; CF2_Int top, i, j; vals[0] = *curX; vals[1] = *curY; index = 0; isHFlex = readFromStack[9] == FALSE; top = isHFlex ? 9 : 10; for ( i = 0; i < top; i++ ) { vals[i + 2] = vals[i]; if ( readFromStack[i] ) vals[i + 2] += cf2_stack_getReal( opStack, index++ ); } if ( isHFlex ) vals[9 + 2] = *curY; if ( doConditionalLastRead ) { FT_Bool lastIsX = (FT_Bool)( cf2_fixedAbs( vals[10] - *curX ) > cf2_fixedAbs( vals[11] - *curY ) ); CF2_Fixed lastVal = cf2_stack_getReal( opStack, index ); if ( lastIsX ) { vals[12] = vals[10] + lastVal; vals[13] = *curY; } else { vals[12] = *curX; vals[13] = vals[11] + lastVal; } } else { if ( readFromStack[10] ) vals[12] = vals[10] + cf2_stack_getReal( opStack, index++ ); else vals[12] = *curX; if ( readFromStack[11] ) vals[13] = vals[11] + cf2_stack_getReal( opStack, index ); else vals[13] = *curY; } for ( j = 0; j < 2; j++ ) cf2_glyphpath_curveTo( glyphPath, vals[j * 6 + 2], vals[j * 6 + 3], vals[j * 6 + 4], vals[j * 6 + 5], vals[j * 6 + 6], vals[j * 6 + 7] ); cf2_stack_clear( opStack ); *curX = vals[12]; *curY = vals[13]; }