Exemplo n.º 1
0
void SkScalerContext_CairoFT::generateImage(const SkGlyph& glyph)
{
    SkASSERT(fScaledFont != nullptr);
    CairoLockedFTFace faceLock(fScaledFont);
    FT_Face face = faceLock.getFace();

    FT_Error err = FT_Load_Glyph(face, glyph.getGlyphID(), fLoadGlyphFlags);

    if (err != 0) {
        memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
        return;
    }

    prepareGlyph(face->glyph);

    bool useLcdFilter =
        face->glyph->format == FT_GLYPH_FORMAT_OUTLINE &&
        isLCD(glyph) &&
        gSetLcdFilter;
    if (useLcdFilter) {
        gSetLcdFilter(face->glyph->library, fLcdFilter);
    }

    generateGlyphImage(face, glyph);

    if (useLcdFilter) {
        gSetLcdFilter(face->glyph->library, FT_LCD_FILTER_NONE);
    }
}
Exemplo n.º 2
0
    virtual void onFilterRec(SkScalerContextRec* rec) const override
    {
        // No subpixel AA unless enabled in Fontconfig.
        if (!fPattern && isLCD(*rec)) {
            rec->fMaskFormat = SkMask::kA8_Format;
        }

        // rotated text looks bad with hinting, so we disable it as needed
        if (!gFontHintingEnabled || !isAxisAligned(*rec)) {
            rec->setHinting(SkPaint::kNo_Hinting);
        }
    }
Exemplo n.º 3
0
SkScalerContext_CairoFT::SkScalerContext_CairoFT(SkTypeface* typeface, const SkDescriptor* desc)
    : SkScalerContext_FreeType_Base(typeface, desc)
{
    SkMatrix matrix;
    fRec.getSingleMatrix(&matrix);

    cairo_font_face_t* fontFace = static_cast<SkCairoFTTypeface*>(typeface)->getFontFace();

    cairo_matrix_t fontMatrix, ctMatrix;
    cairo_matrix_init(&fontMatrix, matrix.getScaleX(), matrix.getSkewY(), matrix.getSkewX(), matrix.getScaleY(), 0.0, 0.0);
    cairo_matrix_init_scale(&ctMatrix, 1.0, 1.0);

    // We need to ensure that the font options match for hinting, as generateMetrics()
    // uses the fScaledFont which uses these font options
    cairo_font_options_t *fontOptions = cairo_font_options_create();

    FT_Int32 loadFlags = FT_LOAD_DEFAULT;

    if (SkMask::kBW_Format == fRec.fMaskFormat) {
        // See http://code.google.com/p/chromium/issues/detail?id=43252#c24
        loadFlags = FT_LOAD_TARGET_MONO;
        if (fRec.getHinting() == SkPaint::kNo_Hinting) {
            cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_NONE);
            loadFlags = FT_LOAD_NO_HINTING;
        }
    } else {
        switch (fRec.getHinting()) {
        case SkPaint::kNo_Hinting:
            loadFlags = FT_LOAD_NO_HINTING;
            cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_NONE);
            break;
        case SkPaint::kSlight_Hinting:
            loadFlags = FT_LOAD_TARGET_LIGHT;  // This implies FORCE_AUTOHINT
            cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_SLIGHT);
            break;
        case SkPaint::kNormal_Hinting:
            cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_MEDIUM);
            if (fRec.fFlags & SkScalerContext::kForceAutohinting_Flag) {
                loadFlags = FT_LOAD_FORCE_AUTOHINT;
            }
            break;
        case SkPaint::kFull_Hinting:
            cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_FULL);
            if (fRec.fFlags & SkScalerContext::kForceAutohinting_Flag) {
                loadFlags = FT_LOAD_FORCE_AUTOHINT;
            }
            if (isLCD(fRec)) {
                if (SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag)) {
                    loadFlags = FT_LOAD_TARGET_LCD_V;
                } else {
                    loadFlags = FT_LOAD_TARGET_LCD;
                }
            }
            break;
        default:
            SkDebugf("---------- UNKNOWN hinting %d\n", fRec.getHinting());
            break;
        }
    }

    fScaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctMatrix, fontOptions);
    cairo_font_options_destroy(fontOptions);

    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;

#ifdef FT_LOAD_COLOR
    loadFlags |= FT_LOAD_COLOR;
#endif

    fLoadGlyphFlags = loadFlags;
}
Exemplo n.º 4
0
void SkScalerContext_CairoFT::generateMetrics(SkGlyph* glyph)
{
    SkASSERT(fScaledFont != nullptr);

    glyph->zeroMetrics();

    CairoLockedFTFace faceLock(fScaledFont);
    FT_Face face = faceLock.getFace();

    FT_Error err = FT_Load_Glyph( face, glyph->getGlyphID(), fLoadGlyphFlags );
    if (err != 0) {
        return;
    }

    prepareGlyph(face->glyph);

    switch (face->glyph->format) {
    case FT_GLYPH_FORMAT_OUTLINE:
        if (!face->glyph->outline.n_contours) {
            break;
        }

        FT_BBox bbox;
        FT_Outline_Get_CBox(&face->glyph->outline, &bbox);
        bbox.xMin &= ~63;
        bbox.yMin &= ~63;
        bbox.xMax = (bbox.xMax + 63) & ~63;
        bbox.yMax = (bbox.yMax + 63) & ~63;
        glyph->fWidth  = SkToU16(SkFDot6Floor(bbox.xMax - bbox.xMin));
        glyph->fHeight = SkToU16(SkFDot6Floor(bbox.yMax - bbox.yMin));
        glyph->fTop    = -SkToS16(SkFDot6Floor(bbox.yMax));
        glyph->fLeft   = SkToS16(SkFDot6Floor(bbox.xMin));

        if (isLCD(fRec) &&
            gSetLcdFilter &&
            (fLcdFilter == FT_LCD_FILTER_DEFAULT ||
             fLcdFilter == FT_LCD_FILTER_LIGHT)) {
            if (fRec.fFlags & kLCD_Vertical_Flag) {
                glyph->fTop -= 1;
                glyph->fHeight += 2;
            } else {
                glyph->fLeft -= 1;
                glyph->fWidth += 2;
            }
        }
        break;
    case FT_GLYPH_FORMAT_BITMAP:
#ifdef FT_LOAD_COLOR
        if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) {
            glyph->fMaskFormat = SkMask::kARGB32_Format;
        }
#endif

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

        if (fHaveShape) {
            // Apply the shape matrix to the glyph's bounding box.
            SkMatrix matrix;
            fRec.getSingleMatrix(&matrix);
            matrix.preScale(SkScalarInvert(fScaleX), SkScalarInvert(fScaleY));
            SkRect srcRect = SkRect::MakeXYWH(
                SkIntToScalar(face->glyph->bitmap_left),
                -SkIntToScalar(face->glyph->bitmap_top),
                SkIntToScalar(face->glyph->bitmap.width),
                SkIntToScalar(face->glyph->bitmap.rows));
            SkRect destRect;
            matrix.mapRect(&destRect, srcRect);
            SkIRect glyphRect = destRect.roundOut();
            glyph->fWidth  = SkToU16(glyphRect.width());
            glyph->fHeight = SkToU16(glyphRect.height());
            glyph->fTop    = SkToS16(SkScalarRoundToInt(destRect.fTop));
            glyph->fLeft   = SkToS16(SkScalarRoundToInt(destRect.fLeft));
        } else {
            glyph->fWidth  = SkToU16(face->glyph->bitmap.width);
            glyph->fHeight = SkToU16(face->glyph->bitmap.rows);
            glyph->fTop    = -SkToS16(face->glyph->bitmap_top);
            glyph->fLeft   = SkToS16(face->glyph->bitmap_left);
        }
        break;
    default:
        SkDEBUGFAIL("unknown glyph format");
        return;
    }

    if (fRec.fFlags & SkScalerContext::kVertical_Flag) {
        glyph->fAdvanceX = -SkFDot6ToFloat(face->glyph->advance.x);
        glyph->fAdvanceY = SkFDot6ToFloat(face->glyph->advance.y);
    } else {
        glyph->fAdvanceX = SkFDot6ToFloat(face->glyph->advance.x);
        glyph->fAdvanceY = -SkFDot6ToFloat(face->glyph->advance.y);
    }
}
Exemplo n.º 5
0
void SkScalerContext_CairoFT::parsePattern(FcPattern* pattern)
{
    FcBool antialias, autohint, bitmap, embolden, hinting, vertical;

    if (FcPatternGetBool(pattern, FC_AUTOHINT, 0, &autohint) == FcResultMatch && autohint) {
        fRec.fFlags |= SkScalerContext::kForceAutohinting_Flag;
    }
    if (FcPatternGetBool(pattern, FC_EMBEDDED_BITMAP, 0, &bitmap) == FcResultMatch && bitmap) {
        fRec.fFlags |= SkScalerContext::kEmbeddedBitmapText_Flag;
    }
    if (FcPatternGetBool(pattern, FC_EMBOLDEN, 0, &embolden) == FcResultMatch && embolden) {
        fRec.fFlags |= SkScalerContext::kEmbolden_Flag;
    }
    if (FcPatternGetBool(pattern, FC_VERTICAL_LAYOUT, 0, &vertical) == FcResultMatch && vertical) {
        fRec.fFlags |= SkScalerContext::kVertical_Flag;
    }

    if (fRec.fMaskFormat != SkMask::kBW_Format &&
        (FcPatternGetBool(pattern, FC_ANTIALIAS, 0, &antialias) != FcResultMatch || antialias)) {
        int rgba;
        if (!isLCD(fRec) ||
            FcPatternGetInteger(pattern, FC_RGBA, 0, &rgba) != FcResultMatch) {
            rgba = FC_RGBA_UNKNOWN;
        }
        switch (rgba) {
        case FC_RGBA_RGB:
            break;
        case FC_RGBA_BGR:
            fRec.fFlags |= SkScalerContext::kLCD_BGROrder_Flag;
            break;
        case FC_RGBA_VRGB:
            fRec.fFlags |= SkScalerContext::kLCD_Vertical_Flag;
            break;
        case FC_RGBA_VBGR:
            fRec.fFlags |= SkScalerContext::kLCD_Vertical_Flag |
                           SkScalerContext::kLCD_BGROrder_Flag;
            break;
        default:
            fRec.fMaskFormat = SkMask::kA8_Format;
            break;
        }

        int filter;
        if (isLCD(fRec)) {
            if (FcPatternGetInteger(pattern, FC_LCD_FILTER, 0, &filter) != FcResultMatch) {
                filter = FC_LCD_LEGACY;
            }
            switch (filter) {
            case FC_LCD_NONE:
                fLcdFilter = FT_LCD_FILTER_NONE;
                break;
            case FC_LCD_DEFAULT:
                fLcdFilter = FT_LCD_FILTER_DEFAULT;
                break;
            case FC_LCD_LIGHT:
                fLcdFilter = FT_LCD_FILTER_LIGHT;
                break;
            case FC_LCD_LEGACY:
            default:
                fLcdFilter = FT_LCD_FILTER_LEGACY;
                break;
            }
        }
    } else {
        fRec.fMaskFormat = SkMask::kBW_Format;
    }

    if (fRec.getHinting() != SkPaint::kNo_Hinting &&
        (FcPatternGetBool(pattern, FC_HINTING, 0, &hinting) != FcResultMatch || hinting)) {
        int hintstyle;
        if (FcPatternGetInteger(pattern, FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch) {
            hintstyle = FC_HINT_FULL;
        }
        switch (hintstyle) {
        case FC_HINT_NONE:
            fRec.setHinting(SkPaint::kNo_Hinting);
            break;
        case FC_HINT_SLIGHT:
            fRec.setHinting(SkPaint::kSlight_Hinting);
            break;
        case FC_HINT_MEDIUM:
        default:
            fRec.setHinting(SkPaint::kNormal_Hinting);
            break;
        case FC_HINT_FULL:
            fRec.setHinting(SkPaint::kFull_Hinting);
            break;
        }
    }
}
Exemplo n.º 6
0
SkScalerContext_CairoFT::SkScalerContext_CairoFT(SkTypeface* typeface, const SkDescriptor* desc,
                                                 cairo_font_face_t* fontFace, FcPattern* pattern)
    : SkScalerContext_FreeType_Base(typeface, desc)
    , fLcdFilter(FT_LCD_FILTER_NONE)
{
    SkMatrix matrix;
    fRec.getSingleMatrix(&matrix);

    cairo_matrix_t fontMatrix, ctMatrix;
    cairo_matrix_init(&fontMatrix, matrix.getScaleX(), matrix.getSkewY(), matrix.getSkewX(), matrix.getScaleY(), 0.0, 0.0);
    cairo_matrix_init_identity(&ctMatrix);

    cairo_font_options_t *fontOptions = cairo_font_options_create();
    fScaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctMatrix, fontOptions);
    cairo_font_options_destroy(fontOptions);

    computeShapeMatrix(matrix);

#ifdef CAIRO_HAS_FC_FONT
    resolvePattern(pattern);
#endif

    FT_Int32 loadFlags = FT_LOAD_DEFAULT;

    if (SkMask::kBW_Format == fRec.fMaskFormat) {
        if (fRec.getHinting() == SkPaint::kNo_Hinting) {
            loadFlags |= FT_LOAD_NO_HINTING;
        } else {
            loadFlags = FT_LOAD_TARGET_MONO;
        }
        loadFlags |= FT_LOAD_MONOCHROME;
    } else {
        switch (fRec.getHinting()) {
        case SkPaint::kNo_Hinting:
            loadFlags |= FT_LOAD_NO_HINTING;
            break;
        case SkPaint::kSlight_Hinting:
            loadFlags = FT_LOAD_TARGET_LIGHT;  // This implies FORCE_AUTOHINT
            break;
        case SkPaint::kNormal_Hinting:
            if (fRec.fFlags & SkScalerContext::kForceAutohinting_Flag) {
                loadFlags |= FT_LOAD_FORCE_AUTOHINT;
            }
            break;
        case SkPaint::kFull_Hinting:
            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", fRec.getHinting());
            break;
        }
    }

    // Disable autohinting to disable hinting even for "tricky" fonts.
    if (!gFontHintingEnabled) {
        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;

    if (fRec.fFlags & SkScalerContext::kVertical_Flag) {
        loadFlags |= FT_LOAD_VERTICAL_LAYOUT;
    }

#ifdef FT_LOAD_COLOR
    loadFlags |= FT_LOAD_COLOR;
#endif

    fLoadGlyphFlags = loadFlags;
}