Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/gfx/skia/skia/src/ports/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 21 kB image not shown  

Quelle  SkFontHost_cairo.cpp   Sprache: C

 

/*
 * Copyright 2012 Mozilla Foundation
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */


#include "src/ports/SkFontHost_FreeType_common.h"

#include "src/core/SkAdvancedTypefaceMetrics.h"
#include "src/core/SkFDot6.h"
#include "include/core/SkFontMetrics.h"
#include "include/core/SkFontTypes.h"
#include "include/core/SkPath.h"
#include "include/core/SkStream.h"
#include "src/core/SkScalerContext.h"
#include "src/core/SkTypefaceCache.h"

#include <cfloat>
#include <cmath>

#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_OUTLINE_H

// for FT_GlyphSlot_Embolden
#ifdef FT_SYNTHESIS_H
#include FT_SYNTHESIS_H
#endif

// for FT_Library_SetLcdFilter
#ifdef FT_LCD_FILTER_H
#include FT_LCD_FILTER_H
#else
typedef enum FT_LcdFilter_
{
    FT_LCD_FILTER_NONE    = 0,
    FT_LCD_FILTER_DEFAULT = 1,
    FT_LCD_FILTER_LIGHT   = 2,
    FT_LCD_FILTER_LEGACY  = 16,
} FT_LcdFilter;
#endif

// If compiling with FreeType before 2.5.0
#ifndef FT_LOAD_COLOR
#    define FT_LOAD_COLOR ( 1L << 20 )
#    define FT_PIXEL_MODE_BGRA 7
#endif

// If compiling with FreeType before 2.12.0
#ifndef FT_FACE_FLAG_SVG
// We need the format tag so that we can switch on it and handle a possibly-
// newer version of the library at runtime.
static constexpr FT_UInt32 FT_IMAGE_TAG(FT_GLYPH_FORMAT_SVG, 'S''V''G'' ');
#endif

#ifndef SK_CAN_USE_DLOPEN
#define SK_CAN_USE_DLOPEN 1
#endif
#if SK_CAN_USE_DLOPEN
#include <dlfcn.h>
#endif

#ifndef SK_FONTHOST_CAIRO_STANDALONE
#define SK_FONTHOST_CAIRO_STANDALONE 1
#endif

static bool gFontHintingEnabled = true;
static FT_Error (*gSetLcdFilter)(FT_Library, FT_LcdFilter) = nullptr;

extern "C"
{
    void mozilla_LockFTLibrary(FT_Library aLibrary);
    void mozilla_UnlockFTLibrary(FT_Library aLibrary);
    void mozilla_AddRefSharedFTFace(void* aContext);
    void mozilla_ReleaseSharedFTFace(void* aContext, void* aOwner);
    void mozilla_ForgetSharedFTFaceLockOwner(void* aContext, void* aOwner);
    int mozilla_LockSharedFTFace(void* aContext, void* aOwner);
    void mozilla_UnlockSharedFTFace(void* aContext);
    FT_Error mozilla_LoadFTGlyph(FT_Face aFace, uint32_t aGlyphIndex, int32_t aFlags);
    void mozilla_glyphslot_embolden_less(FT_GlyphSlot slot);
}

void SkInitCairoFT(bool fontHintingEnabled)
{
    gFontHintingEnabled = fontHintingEnabled;
#if SK_CAN_USE_DLOPEN
    gSetLcdFilter = (FT_Error (*)(FT_Library, FT_LcdFilter))dlsym(RTLD_DEFAULT, "FT_Library_SetLcdFilter");
#else
    gSetLcdFilter = &FT_Library_SetLcdFilter;
#endif
    // FT_Library_SetLcdFilter may be provided but have no effect if FreeType
    // is built without FT_CONFIG_OPTION_SUBPIXEL_RENDERING.
    if (gSetLcdFilter &&
        gSetLcdFilter(nullptr, FT_LCD_FILTER_NONE) == FT_Err_Unimplemented_Feature) {
        gSetLcdFilter = nullptr;
    }
}

class SkScalerContext_CairoFT : public SkScalerContext {
public:
    SkScalerContext_CairoFT(sk_sp<SkTypeface> typeface,
                            const SkScalerContextEffects& effects,
                            const SkDescriptor* desc, FT_Face face,
                            void* faceContext, SkPixelGeometry pixelGeometry,
                            FT_LcdFilter lcdFilter);

    virtual ~SkScalerContext_CairoFT() {
        mozilla_ForgetSharedFTFaceLockOwner(fFTFaceContext, this);
    }

    bool isValid() const { return fFTFaceContext != nullptr; }

    void Lock() {
        if (!mozilla_LockSharedFTFace(fFTFaceContext, this)) {
            FT_Set_Transform(fFTFace, fHaveShape ? &fShapeMatrixFT : nullptr, nullptr);
            FT_Set_Char_Size(fFTFace, FT_F26Dot6(fScaleX * 64.0f + 0.5f),
                             FT_F26Dot6(fScaleY * 64.0f + 0.5f), 0, 0);
        }
    }

    void Unlock() { mozilla_UnlockSharedFTFace(fFTFaceContext); }

protected:
    GlyphMetrics generateMetrics(const SkGlyph& glyph, SkArenaAlloc* arena) override;
    void generateImage(const SkGlyph& glyph, void* imageBuffer) override;
    bool generatePath(const SkGlyph& glyph, SkPath* path, bool* modified) override;
    void generateFontMetrics(SkFontMetrics* metrics) override;

private:
    bool computeShapeMatrix(const SkMatrix& m);
    bool prepareGlyph(FT_GlyphSlot glyph);

    SkScalerContextFTUtils fUtils;
    FT_Face fFTFace;
    void* fFTFaceContext;
    FT_Int32 fLoadGlyphFlags;
    FT_LcdFilter fLcdFilter;
    SkScalar fScaleX;
    SkScalar fScaleY;
    SkMatrix fShapeMatrix;
    FT_Matrix fShapeMatrixFT;
    bool fHaveShape;
};

class AutoLockFTFace {
public:
    AutoLockFTFace(SkScalerContext_CairoFT* scalerContext)
        : fScalerContext(scalerContext) {
        fScalerContext->Lock();
    }

    ~AutoLockFTFace() { fScalerContext->Unlock(); }

private:
    SkScalerContext_CairoFT* fScalerContext;
};

static bool isLCD(const SkScalerContextRec& rec) {
    return SkMask::kLCD16_Format == rec.fMaskFormat;
}

static bool bothZero(SkScalar a, SkScalar b) {
    return 0 == a && 0 == b;
}

// returns false if there is any non-90-rotation or skew
static bool isAxisAligned(const SkScalerContextRec& rec) {
    return 0 == rec.fPreSkewX &&
           (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
            bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
}

class SkCairoFTTypeface : public SkTypeface {
public:
    std::unique_ptr<SkStreamAsset> onOpenStream(int*) const override { return nullptr; }

    std::unique_ptr<SkAdvancedTypefaceMetrics> onGetAdvancedMetrics() const override
    {
        SkDEBUGCODE(SkDebugf("SkCairoFTTypeface::onGetAdvancedMetrics unimplemented\n"));
        return nullptr;
    }

    std::unique_ptr<SkScalerContext> onCreateScalerContext(const SkScalerContextEffects&&nbsp;effects, const SkDescriptor* desc) const override
    {
        SkScalerContext_CairoFT* ctx = new SkScalerContext_CairoFT(
            sk_ref_sp(const_cast<SkCairoFTTypeface*>(this)), effects, desc,
            fFTFace, fFTFaceContext, fPixelGeometry, fLcdFilter);
        std::unique_ptr<SkScalerContext> result(ctx);
        if (!ctx->isValid()) {
            return nullptr;
        }
        return result;
    }

    void onFilterRec(SkScalerContextRec* rec) const override
    {
        // rotated text looks bad with hinting, so we disable it as needed
        if (!gFontHintingEnabled || !isAxisAligned(*rec)) {
            rec->setHinting(SkFontHinting::kNone);
        }

        // Don't apply any gamma so that we match cairo-ft's results.
        rec->ignorePreBlend();
    }

    void onGetFontDescriptor(SkFontDescriptor*, bool*) const override
    {
        SkDEBUGCODE(SkDebugf("SkCairoFTTypeface::onGetFontDescriptor unimplemented\n"));
    }

    void onCharsToGlyphs(const SkUnichar* chars, int count, SkGlyphID glyphs[]) const override
    {
        mozilla_LockSharedFTFace(fFTFaceContext, nullptr);
        for (int i = 0; i < count; ++i) {
            glyphs[i] = SkToU16(FT_Get_Char_Index(fFTFace, chars[i]));
        }
        mozilla_UnlockSharedFTFace(fFTFaceContext);
    }

    int onCountGlyphs() const override
    {
        return fFTFace->num_glyphs;
    }

    int onGetUPEM() const override
    {
        return 0;
    }

    SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override
    {
        return nullptr;
    }

    void onGetFamilyName(SkString* familyName) const override
    {
        familyName->reset();
    }

    bool onGetPostScriptName(SkString*) const override {
        return false;
    }

    bool onGlyphMaskNeedsCurrentColor() const override {
        return false;
    }

    int onGetTableTags(SkFontTableTag*) const override
    {
        return 0;
    }

    size_t onGetTableData(SkFontTableTag, size_t, size_t, void*) const override
    {
        return 0;
    }

    void getPostScriptGlyphNames(SkString*) const override {}

    void getGlyphToUnicodeMap(SkUnichar*) const override {}

    int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
                                     int coordinateCount) const override
    {
        return 0;
    }

    int onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],
                                       int parameterCount) const override
    {
        return 0;
    }

    sk_sp<SkTypeface> onMakeClone(const SkFontArguments& args) const override {
        return sk_ref_sp(this);
    }

    SkCairoFTTypeface(FT_Face face, void* faceContext,
                      SkPixelGeometry pixelGeometry, FT_LcdFilter lcdFilter)
        : SkTypeface(SkFontStyle::Normal())
        , fFTFace(face)
        , fFTFaceContext(faceContext)
        , fPixelGeometry(pixelGeometry)
        , fLcdFilter(lcdFilter)
    {
        mozilla_AddRefSharedFTFace(fFTFaceContext);
    }

    void* GetFTFaceContext() const { return fFTFaceContext; }

    bool hasColorGlyphs() const override
    {
        // Check if the font has scalable outlines. If not, then avoid trying
        // to render it as a path.
        if (fFTFace) {
            return !FT_IS_SCALABLE(fFTFace);
        }
        return false;
    }

private:
    ~SkCairoFTTypeface()
    {
        mozilla_ReleaseSharedFTFace(fFTFaceContext, nullptr);
    }

    FT_Face            fFTFace;
    void*              fFTFaceContext;
    SkPixelGeometry    fPixelGeometry;
    FT_LcdFilter       fLcdFilter;
};

static bool FindByFTFaceContext(SkTypeface* typeface, void* context) {
    return static_cast<SkCairoFTTypeface*>(typeface)->GetFTFaceContext() == context;
}

SkTypeface* SkCreateTypefaceFromCairoFTFont(FT_Face face, void* faceContext,
                                            SkPixelGeometry pixelGeometry,
                                            uint8_t lcdFilter)
{
    sk_sp<SkTypeface> typeface =
        SkTypefaceCache::FindByProcAndRef(FindByFTFaceContext, faceContext);
    if (!typeface) {
        typeface = sk_make_sp<SkCairoFTTypeface>(face, faceContext, pixelGeometry,
                                                 (FT_LcdFilter)lcdFilter);
        SkTypefaceCache::Add(typeface);
    }

    return typeface.release();
}

SkScalerContext_CairoFT::SkScalerContext_CairoFT(
    sk_sp<SkTypeface> typeface, const SkScalerContextEffects& effects,
    const SkDescriptor* desc, FT_Face face, void* faceContext,
    SkPixelGeometry pixelGeometry, FT_LcdFilter lcdFilter)
    : SkScalerContext(std::move(typeface), effects, desc)
    , fFTFace(face)
    , fFTFaceContext(faceContext)
    , fLcdFilter(lcdFilter)
{
    SkMatrix matrix;
    fRec.getSingleMatrix(&matrix);

    computeShapeMatrix(matrix);

    FT_Int32 loadFlags = FT_LOAD_DEFAULT;

    if (SkMask::kBW_Format == fRec.fMaskFormat) {
        if (fRec.getHinting() == SkFontHinting::kNone) {
            loadFlags |= FT_LOAD_NO_HINTING;
        } else {
            loadFlags = FT_LOAD_TARGET_MONO;
        }
        loadFlags |= FT_LOAD_MONOCHROME;
    } else {
        if (isLCD(fRec)) {
            switch (pixelGeometry) {
            case kRGB_H_SkPixelGeometry:
            default:
                break;
            case kRGB_V_SkPixelGeometry:
                fRec.fFlags |= SkScalerContext::kLCD_Vertical_Flag;
                break;
            case kBGR_H_SkPixelGeometry:
                fRec.fFlags |= SkScalerContext::kLCD_BGROrder_Flag;
                break;
            case kBGR_V_SkPixelGeometry:
                fRec.fFlags |= SkScalerContext::kLCD_Vertical_Flag |
                               SkScalerContext::kLCD_BGROrder_Flag;
                break;
            }
        }

        switch (fRec.getHinting()) {
        case SkFontHinting::kNone:
            loadFlags |= FT_LOAD_NO_HINTING;
            break;
        case SkFontHinting::kSlight:
            loadFlags = FT_LOAD_TARGET_LIGHT;  // This implies FORCE_AUTOHINT
            break;
        case SkFontHinting::kNormal:
            if (fRec.fFlags & SkScalerContext::kForceAutohinting_Flag) {
                loadFlags |= FT_LOAD_FORCE_AUTOHINT;
            }
            break;
        case SkFontHinting::kFull:
            if (isLCD(fRec)) {
                if (fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag) {
                    loadFlags = FT_LOAD_TARGET_LCD_V;
                } else {
                    loadFlags = FT_LOAD_TARGET_LCD;
                }
            }
            if (fRec.fFlags & SkScalerContext::kForceAutohinting_Flag) {
                loadFlags |= FT_LOAD_FORCE_AUTOHINT;
            }
            break;
        default:
            SkDebugf("---------- UNKNOWN hinting %d\n", (int)fRec.getHinting());
            break;
        }
    }

    // Disable autohinting when asked to disable hinting, except for "tricky" fonts.
    if (!gFontHintingEnabled) {
        if (fFTFace && !(fFTFace->face_flags & FT_FACE_FLAG_TRICKY)) {
            loadFlags |= FT_LOAD_NO_AUTOHINT;
        }
    }

    if ((fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag) == 0) {
        loadFlags |= FT_LOAD_NO_BITMAP;
    }

    // Always using FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH to get correct
    // advances, as fontconfig and cairo do.
    // See http://code.google.com/p/skia/issues/detail?id=222.
    loadFlags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;

    loadFlags |= FT_LOAD_COLOR;

    fLoadGlyphFlags = loadFlags;

    fUtils.init(fRec.fForegroundColor, (SkScalerContext::Flags)fRec.fFlags);
}

bool SkScalerContext_CairoFT::computeShapeMatrix(const SkMatrix& m)
{
    // Compute a shape matrix compatible with Cairo's _compute_transform.
    // Finds major/minor scales and uses them to normalize the transform.
    double scaleX = m.getScaleX();
    double skewX = m.getSkewX();
    double skewY = m.getSkewY();
    double scaleY = m.getScaleY();
    double det = scaleX * scaleY - skewY * skewX;
    if (!std::isfinite(det)) {
        fScaleX = fRec.fTextSize * fRec.fPreScaleX;
        fScaleY = fRec.fTextSize;
        fHaveShape = false;
        return false;
    }
    double major = det != 0.0 ? hypot(scaleX, skewY) : 0.0;
    double minor = major != 0.0 ? fabs(det) / major : 0.0;
    // Limit scales to be above 1pt.
    major = std::max(major, 1.0);
    minor = std::max(minor, 1.0);

    // If the font is not scalable, then choose the best available size.
    if (fFTFace && !FT_IS_SCALABLE(fFTFace)) {
        double bestDist = DBL_MAX;
        FT_Int bestSize = -1;
        for (FT_Int i = 0; i < fFTFace->num_fixed_sizes; i++) {
            // Distance is positive if strike is larger than desired size,
            // or negative if smaller. If previously a found smaller strike,
            // then prefer a larger strike. Otherwise, minimize distance.
            double dist = fFTFace->available_sizes[i].y_ppem / 64.0 - minor;
            if (bestDist < 0 ? dist >= bestDist : fabs(dist) <= bestDist) {
                bestDist = dist;
                bestSize = i;
            }
        }
        if (bestSize < 0) {
            fScaleX = fRec.fTextSize * fRec.fPreScaleX;
            fScaleY = fRec.fTextSize;
            fHaveShape = false;
            return false;
        }
        major = fFTFace->available_sizes[bestSize].x_ppem / 64.0;
        minor = fFTFace->available_sizes[bestSize].y_ppem / 64.0;
        fHaveShape = true;
    } else {
        fHaveShape = !m.isScaleTranslate() || scaleX < 0.0 || scaleY < 0.0;
    }

    fScaleX = SkDoubleToScalar(major);
    fScaleY = SkDoubleToScalar(minor);

    if (fHaveShape) {
        // Normalize the transform and convert to fixed-point.
        fShapeMatrix = m;
        fShapeMatrix.preScale(SkDoubleToScalar(1.0 / major), SkDoubleToScalar(1.0 / minor));

        fShapeMatrixFT.xx = SkScalarToFixed(fShapeMatrix.getScaleX());
        fShapeMatrixFT.yx = SkScalarToFixed(-fShapeMatrix.getSkewY());
        fShapeMatrixFT.xy = SkScalarToFixed(-fShapeMatrix.getSkewX());
        fShapeMatrixFT.yy = SkScalarToFixed(fShapeMatrix.getScaleY());
    }
    return true;
}

bool SkScalerContext_CairoFT::prepareGlyph(FT_GlyphSlot glyph)
{
    bool modified = false;
    if (fRec.fFlags & SkScalerContext::kEmbolden_Flag) {
        // Not FT_GlyphSlot_Embolden because we want a less extreme effect.
        mozilla_glyphslot_embolden_less(glyph);
        modified = true;
    }
    return modified;
}

SkScalerContext::GlyphMetrics SkScalerContext_CairoFT::generateMetrics(const SkGlyph& glyph, SkArenaAlloc* arena)
{
    GlyphMetrics mx(glyph.maskFormat());

    AutoLockFTFace faceLock(this);

    FT_Error err = mozilla_LoadFTGlyph(fFTFace, glyph.getGlyphID(), fLoadGlyphFlags);
    if (err != 0) {
        return mx;
    }

    prepareGlyph(fFTFace->glyph);

    mx.advance.fX = SkFDot6ToFloat(fFTFace->glyph->advance.x);
    mx.advance.fY = -SkFDot6ToFloat(fFTFace->glyph->advance.y);

    SkIRect bounds;
    switch (fFTFace->glyph->format) {
    case FT_GLYPH_FORMAT_OUTLINE:
        if (!fFTFace->glyph->outline.n_contours) {
            return mx;
        }

        FT_BBox bbox;
        FT_Outline_Get_CBox(&fFTFace->glyph->outline, &bbox);
        if (this->isSubpixel()) {
            int dx = SkFixedToFDot6(glyph.getSubXFixed());
            int dy = SkFixedToFDot6(glyph.getSubYFixed());
            bbox.xMin += dx;
            bbox.yMin -= dy;
            bbox.xMax += dx;
            bbox.yMax -= dy;
        }
        bbox.xMin &= ~63;
        bbox.yMin &= ~63;
        bbox.xMax = (bbox.xMax + 63) & ~63;
        bbox.yMax = (bbox.yMax + 63) & ~63;
        bounds = SkIRect::MakeLTRB(SkFDot6Floor(bbox.xMin),
                                   -SkFDot6Floor(bbox.yMax),
                                   SkFDot6Floor(bbox.xMax),
                                   -SkFDot6Floor(bbox.yMin));

        if (isLCD(fRec)) {
            // In FreeType < 2.8.1, LCD filtering, if explicitly used, may
            // add padding to the glyph. When not used, there is no padding.
            // As of 2.8.1, LCD filtering is now always supported and may
            // add padding even if an LCD filter is not explicitly set.
            // Regardless, if no LCD filtering is used, or if LCD filtering
            // doesn't add padding, it is safe to modify the glyph's bounds
            // here. generateGlyphImage will detect if the mask is smaller
            // than the bounds and clip things appropriately.
            if (fRec.fFlags & kLCD_Vertical_Flag) {
                bounds.outset(0, 1);
            } else {
                bounds.outset(1, 0);
            }
        }
        break;
    case FT_GLYPH_FORMAT_BITMAP:
        mx.neverRequestPath = true;

        if (fFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) {
            mx.maskFormat = SkMask::kARGB32_Format;
        }

        if (isLCD(fRec)) {
            fRec.fMaskFormat = SkMask::kA8_Format;
        }

        if (fHaveShape) {
            // Ensure filtering is preserved when the bitmap is transformed.
            // Otherwise, the result will look horrifically aliased.
            if (fRec.fMaskFormat == SkMask::kBW_Format) {
                fRec.fMaskFormat = SkMask::kA8_Format;
            }

            // Apply the shape matrix to the glyph's bounding box.
            SkRect srcRect = SkRect::MakeXYWH(
                SkIntToScalar(fFTFace->glyph->bitmap_left),
                -SkIntToScalar(fFTFace->glyph->bitmap_top),
                SkIntToScalar(fFTFace->glyph->bitmap.width),
                SkIntToScalar(fFTFace->glyph->bitmap.rows));
            SkRect destRect;
            fShapeMatrix.mapRect(&destRect, srcRect);
            SkIRect glyphRect = destRect.roundOut();
            bounds = SkIRect::MakeXYWH(SkScalarRoundToInt(destRect.fLeft),
                                       SkScalarRoundToInt(destRect.fTop),
                                       glyphRect.width(),
                                       glyphRect.height());
        } else {
            bounds = SkIRect::MakeXYWH(fFTFace->glyph->bitmap_left,
                                       -fFTFace->glyph->bitmap_top,
                                       fFTFace->glyph->bitmap.width,
                                       fFTFace->glyph->bitmap.rows);
        }
        break;
    case FT_GLYPH_FORMAT_SVG:
        // We don't support getting glyph bounds for SVG, but at least the advance
        // should be correctly returned, and we don't want to fire an assertion.
        break;
    default:
        SkDEBUGFAIL("unknown glyph format");
        return mx;
    }

    if (SkIRect::MakeXYWH(SHRT_MIN, SHRT_MIN, USHRT_MAX, USHRT_MAX).contains(bounds)) {
      mx.bounds = SkRect::Make(bounds);
    }

    return mx;
}

void SkScalerContext_CairoFT::generateImage(const SkGlyph& glyph, void* imageBuffer)
{
    AutoLockFTFace faceLock(this);

    FT_Error err = mozilla_LoadFTGlyph(fFTFace, glyph.getGlyphID(), fLoadGlyphFlags);

    if (err != 0) {
        sk_bzero(imageBuffer, glyph.imageSize());
        return;
    }

    prepareGlyph(fFTFace->glyph);

    bool useLcdFilter =
        fFTFace->glyph->format == FT_GLYPH_FORMAT_OUTLINE &&
        glyph.maskFormat() == SkMask::kLCD16_Format &&
        gSetLcdFilter;
    if (useLcdFilter) {
        mozilla_LockFTLibrary(fFTFace->glyph->library);
        gSetLcdFilter(fFTFace->glyph->library, fLcdFilter);
    }

    SkMatrix matrix;
    if (fFTFace->glyph->format == FT_GLYPH_FORMAT_BITMAP &&
        fHaveShape) {
        matrix = fShapeMatrix;
    } else {
        matrix.setIdentity();
    }
    fUtils.generateGlyphImage(fFTFace, glyph, imageBuffer, matrix, fPreBlend);

    if (useLcdFilter) {
        gSetLcdFilter(fFTFace->glyph->library, FT_LCD_FILTER_NONE);
        mozilla_UnlockFTLibrary(fFTFace->glyph->library);
    }
}

bool SkScalerContext_CairoFT::generatePath(const SkGlyph& glyph, SkPath* path, bool* modified)
{
    AutoLockFTFace faceLock(this);

    SkASSERT(path);

    SkGlyphID glyphID = glyph.getGlyphID();

    uint32_t flags = fLoadGlyphFlags;
    flags |= FT_LOAD_NO_BITMAP; // ignore embedded bitmaps so we're sure to get the outline
    flags &= ~FT_LOAD_RENDER;   // don't scan convert (we just want the outline)

    FT_Error err = mozilla_LoadFTGlyph(fFTFace, glyphID, flags);

    if (err != 0) {
        path->reset();
        return false;
    }

    *modified |= prepareGlyph(fFTFace->glyph);

    return fUtils.generateGlyphPath(fFTFace, path);
}

void SkScalerContext_CairoFT::generateFontMetrics(SkFontMetrics* metrics)
{
    if (metrics) {
        sk_bzero(metrics, sizeof(SkFontMetrics));
    }
}

Messung V0.5
C=91 H=96 G=93

¤ Dauer der Verarbeitung: 0.3 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.