/*
* Copyright 2006 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkAdvancedTypefaceMetrics.h"
#include "SkBitmap.h"
#include "SkCanvas.h"
#include "SkColorPriv.h"
#include "SkDescriptor.h"
#include "SkFDot6.h"
#include "SkFloatingPoint.h"
#include "SkFontHost.h"
#include "SkFontHost_FreeType_common.h"
#include "SkGlyph.h"
#include "SkMask.h"
#include "SkMaskGamma.h"
#include "SkMatrix22.h"
#include "SkOTUtils.h"
#include "SkOnce.h"
#include "SkScalerContext.h"
#include "SkStream.h"
#include "SkString.h"
#include "SkTemplates.h"
#include "SkThread.h"
#if defined(SK_CAN_USE_DLOPEN)
#include <dlfcn.h>
#endif
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_OUTLINE_H
#include FT_SIZES_H
#include FT_TRUETYPE_TABLES_H
#include FT_TYPE1_TABLES_H
#include FT_BITMAP_H
// In the past, FT_GlyphSlot_Own_Bitmap was defined in this header file.
#include FT_SYNTHESIS_H
#include FT_XFREE86_H
#ifdef FT_LCD_FILTER_H
#include FT_LCD_FILTER_H
#endif
// Defined in FreeType 2.3.8 and later.
// This is a silly build time check, we would need a runtime check if we really cared.
#ifdef FT_ADVANCES_H
#include FT_ADVANCES_H
#endif
#if 0
// Also include the files by name for build tools which require this.
#include <freetype/freetype.h>
#include <freetype/ftoutln.h>
#include <freetype/ftsizes.h>
#include <freetype/tttables.h>
#include <freetype/ftadvanc.h>
#include <freetype/ftlcdfil.h>
#include <freetype/ftbitmap.h>
#include <freetype/ftsynth.h>
#endif
// FT_LOAD_COLOR and the corresponding FT_Pixel_Mode::FT_PIXEL_MODE_BGRA
// were introduced in FreeType 2.5.0.
// The following may be removed once FreeType 2.5.0 is required to build.
#ifndef FT_LOAD_COLOR
# define FT_LOAD_COLOR ( 1L << 20 )
# define FT_PIXEL_MODE_BGRA 7
#endif
// FT_HAS_COLOR and the corresponding FT_FACE_FLAG_COLOR
// were introduced in FreeType 2.5.1
// The following may be removed once FreeType 2.5.1 is required to build.
#ifndef FT_HAS_COLOR
# define FT_HAS_COLOR(face) false
#endif
//#define ENABLE_GLYPH_SPEW // for tracing calls
//#define DUMP_STRIKE_CREATION
//#define SK_GAMMA_APPLY_TO_A8
using namespace skia_advanced_typeface_metrics_utils;
static bool isLCD(const SkScalerContext::Rec& rec) {
switch (rec.fMaskFormat) {
case SkMask::kLCD16_Format:
case SkMask::kLCD32_Format:
return true;
default:
return false;
}
}
//////////////////////////////////////////////////////////////////////////
struct SkFaceRec;
SK_DECLARE_STATIC_MUTEX(gFTMutex);
static int gFTCount;
static FT_Library gFTLibrary;
static SkFaceRec* gFaceRecHead;
static bool gLCDSupportValid; // true iff |gLCDSupport| has been set.
static bool gLCDSupport; // true iff LCD is supported by the runtime.
static int gLCDExtra; // number of extra pixels for filtering.
/////////////////////////////////////////////////////////////////////////
// FT_Library_SetLcdFilterWeights was introduced in FreeType 2.4.0.
// The following platforms provide FreeType of at least 2.4.0.
// Ubuntu >= 11.04 (previous deprecated April 2013)
// Debian >= 6.0 (good)
// OpenSuse >= 11.4 (previous deprecated January 2012 / Nov 2013 for Evergreen 11.2)
// Fedora >= 14 (good)
// Android >= Gingerbread (good)
typedef FT_Error (*FT_Library_SetLcdFilterWeightsProc)(FT_Library, unsigned char*);
// Caller must lock gFTMutex before calling this function.
static bool InitFreetype() {
FT_Error err = FT_Init_FreeType(&gFTLibrary);
if (err) {
return false;
}
// Setup LCD filtering. This reduces color fringes for LCD smoothed glyphs.
#ifdef FT_LCD_FILTER_H
// Use default { 0x10, 0x40, 0x70, 0x40, 0x10 }, as it adds up to 0x110, simulating ink spread.
// SetLcdFilter must be called before SetLcdFilterWeights.
err = FT_Library_SetLcdFilter(gFTLibrary, FT_LCD_FILTER_DEFAULT);
if (0 == err) {
gLCDSupport = true;
gLCDExtra = 2; //Using a filter adds one full pixel to each side.
#ifdef SK_FONTHOST_FREETYPE_USE_NORMAL_LCD_FILTER
// This also adds to 0x110 simulating ink spread, but provides better results than default.
static unsigned char gGaussianLikeHeavyWeights[] = { 0x1A, 0x43, 0x56, 0x43, 0x1A, };
#if defined(SK_FONTHOST_FREETYPE_RUNTIME_VERSION) && \
SK_FONTHOST_FREETYPE_RUNTIME_VERSION > 0x020400
err = FT_Library_SetLcdFilterWeights(gFTLibrary, gGaussianLikeHeavyWeights);
#elif defined(SK_CAN_USE_DLOPEN) && SK_CAN_USE_DLOPEN == 1
//The FreeType library is already loaded, so symbols are available in process.
void* self = dlopen(NULL, RTLD_LAZY);
if (NULL != self) {
FT_Library_SetLcdFilterWeightsProc setLcdFilterWeights;
//The following cast is non-standard, but safe for POSIX.
*reinterpret_cast<void**>(&setLcdFilterWeights) = dlsym(self, "FT_Library_SetLcdFilterWeights");
dlclose(self);
if (NULL != setLcdFilterWeights) {
err = setLcdFilterWeights(gFTLibrary, gGaussianLikeHeavyWeights);
}
}
#endif
#endif
}
#else
gLCDSupport = false;
#endif
gLCDSupportValid = true;
return true;
}
// Called while holding gFTMutex.
static void determine_lcd_support(bool* lcdSupported) {
if (!gLCDSupportValid) {
// This will determine LCD support as a side effect.
InitFreetype();
FT_Done_FreeType(gFTLibrary);
}
SkASSERT(gLCDSupportValid);
*lcdSupported = gLCDSupport;
}
// Lazy, once, wrapper to ask the FreeType Library if it can support LCD text
static bool is_lcd_supported() {
static bool lcdSupported = false;
SkOnce(&gLCDSupportValid, &gFTMutex, determine_lcd_support, &lcdSupported);
return lcdSupported;
}
class SkScalerContext_FreeType : public SkScalerContext_FreeType_Base {
public:
SkScalerContext_FreeType(SkTypeface*, const SkDescriptor* desc);
virtual ~SkScalerContext_FreeType();
bool success() const {
return fFaceRec != NULL &&
fFTSize != NULL &&
fFace != NULL;
}
protected:
virtual unsigned generateGlyphCount() SK_OVERRIDE;
virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE;
virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE;
virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE;
virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE;
virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE;
virtual void generateFontMetrics(SkPaint::FontMetrics* mx,
SkPaint::FontMetrics* my) SK_OVERRIDE;
virtual SkUnichar generateGlyphToChar(uint16_t glyph) SK_OVERRIDE;
private:
SkFaceRec* fFaceRec;
FT_Face fFace; // reference to shared face in gFaceRecHead
FT_Size fFTSize; // our own copy
FT_Int fStrikeIndex;
SkFixed fScaleX, fScaleY;
FT_Matrix fMatrix22;
uint32_t fLoadGlyphFlags;
bool fDoLinearMetrics;
bool fLCDIsVert;
// Need scalar versions for generateFontMetrics
SkVector fScale;
SkMatrix fMatrix22Scalar;
FT_Error setupSize();
void getBBoxForCurrentGlyph(SkGlyph* glyph, FT_BBox* bbox,
bool snapToPixelBoundary = false);
bool getCBoxForLetter(char letter, FT_BBox* bbox);
// Caller must lock gFTMutex before calling this function.
void updateGlyphIfLCD(SkGlyph* glyph);
// Caller must lock gFTMutex before calling this function.
// update FreeType2 glyph slot with glyph emboldened
void emboldenIfNeeded(FT_Face face, FT_GlyphSlot glyph);
};
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
struct SkFaceRec {
SkFaceRec* fNext;
FT_Face