static bool get_packed_glyph_image(SkGlyphCache* cache, const SkGlyph& glyph, int width,
                                   int height, int dstRB, GrMaskFormat expectedMaskFormat,
                                   void* dst) {
    SkASSERT(glyph.fWidth == width);
    SkASSERT(glyph.fHeight == height);
    const void* src = cache->findImage(glyph);
    if (nullptr == src) {
        return false;
    }

    // crbug:510931
    // Retrieving the image from the cache can actually change the mask format.  This case is very
    // uncommon so for now we just draw a clear box for these glyphs.
    if (get_packed_glyph_mask_format(glyph) != expectedMaskFormat) {
        const int bpp = GrMaskFormatBytesPerPixel(expectedMaskFormat);
        for (int y = 0; y < height; y++) {
            sk_bzero(dst, width * bpp);
            dst = (char*)dst + dstRB;
        }
        return true;
    }

    int srcRB = glyph.rowBytes();
    // The windows font host sometimes has BW glyphs in a non-BW strike. So it is important here to
    // check the glyph's format, not the strike's format, and to be able to convert to any of the
    // GrMaskFormats.
    if (SkMask::kBW_Format == glyph.fMaskFormat) {
        // expand bits to our mask type
        const uint8_t* bits = reinterpret_cast<const uint8_t*>(src);
        switch (expectedMaskFormat) {
            case kA8_GrMaskFormat:{
                uint8_t* bytes = reinterpret_cast<uint8_t*>(dst);
                expand_bits(bytes, bits, width, height, dstRB, srcRB);
                break;
            }
            case kA565_GrMaskFormat: {
                uint16_t* rgb565 = reinterpret_cast<uint16_t*>(dst);
                expand_bits(rgb565, bits, width, height, dstRB, srcRB);
                break;
            }
            default:
                SkFAIL("Invalid GrMaskFormat");
        }
    } else if (srcRB == dstRB) {
        memcpy(dst, src, dstRB * height);
    } else {
        const int bbp = GrMaskFormatBytesPerPixel(expectedMaskFormat);
        for (int y = 0; y < height; y++) {
            memcpy(dst, src, width * bbp);
            src = (const char*)src + srcRB;
            dst = (char*)dst + dstRB;
        }
    }
    return true;
}
Example #2
0
bool GrAtlas::addSubImage(int width, int height, const void* image,
                          GrIPoint16* loc) {
    if (!fRects->addRect(width + BORDER, height + BORDER, loc)) {
        return false;
    }

    GrAutoSMalloc<1024> storage;
    int dstW = width + 2*BORDER;
    int dstH = height + 2*BORDER;
    if (BORDER) {
        const int bpp = GrMaskFormatBytesPerPixel(fMaskFormat);
        const size_t dstRB = dstW * bpp;
        uint8_t* dst = (uint8_t*)storage.realloc(dstH * dstRB);
        Gr_bzero(dst, dstRB);                // zero top row
        dst += dstRB;
        for (int y = 0; y < height; y++) {
            dst = zerofill(dst, bpp);   // zero left edge
            memcpy(dst, image, width * bpp);
            dst += width * bpp;
            dst = zerofill(dst, bpp);   // zero right edge
            image = (const void*)((const char*)image + width * bpp);
        }
        Gr_bzero(dst, dstRB);                // zero bottom row
        image = storage.get();
    }
    adjustForPlot(loc, fPlot);
    fTexture->uploadTextureData(loc->fX, loc->fY, dstW, dstH, image);

    // now tell the caller to skip the top/left BORDER
    loc->fX += BORDER;
    loc->fY += BORDER;
    return true;
}
Example #3
0
bool SkGrFontScaler::getPackedGlyphImage(GrGlyph::PackedID packed,
                                         int width, int height,
                                         int dstRB, void* dst) {
    const SkGlyph& glyph = fStrike->getGlyphIDMetrics(GrGlyph::UnpackID(packed),
                                              GrGlyph::UnpackFixedX(packed),
                                              GrGlyph::UnpackFixedY(packed));
    GrAssert(glyph.fWidth == width);
    GrAssert(glyph.fHeight == height);
    const void* src = fStrike->findImage(glyph);
    if (NULL == src) {
        return false;
    }

    int srcRB = glyph.rowBytes();
    if (SkMask::kBW_Format == fStrike->getMaskFormat()) {
        // expand bits to bytes
        const uint8_t* bits = reinterpret_cast<const uint8_t*>(src);
        uint8_t* bytes = reinterpret_cast<uint8_t*>(dst);
        for (int y = 0; y < height; y++) {
            bits_to_bytes(bits, bytes, width);
            bits += srcRB;
            bytes += dstRB;
        }
    } else if (srcRB == dstRB) {
        memcpy(dst, src, dstRB * height);
    } else {
        const int bbp = GrMaskFormatBytesPerPixel(this->getMaskFormat());
        for (int y = 0; y < height; y++) {
            memcpy(dst, src, width * bbp);
            src = (const char*)src + srcRB;
            dst = (char*)dst + dstRB;
        }
    }
    return true;
}
Example #4
0
bool SkGrFontScaler::getPackedGlyphImage(GrGlyph::PackedID packed,
        int width, int height,
        int dstRB, void* dst) {
    const SkGlyph& glyph = fStrike->getGlyphIDMetrics(GrGlyph::UnpackID(packed),
                           GrGlyph::UnpackFixedX(packed),
                           GrGlyph::UnpackFixedY(packed));
    SkASSERT(glyph.fWidth == width);
    SkASSERT(glyph.fHeight == height);
    const void* src = fStrike->findImage(glyph);
    if (NULL == src) {
        return false;
    }

    int srcRB = glyph.rowBytes();
    // The windows font host sometimes has BW glyphs in a non-BW strike. So it is important here to
    // check the glyph's format, not the strike's format, and to be able to convert to any of the
    // GrMaskFormats.
    if (SkMask::kBW_Format == glyph.fMaskFormat) {
        // expand bits to our mask type
        const uint8_t* bits = reinterpret_cast<const uint8_t*>(src);
        switch (this->getMaskFormat()) {
        case kA8_GrMaskFormat: {
            uint8_t* bytes = reinterpret_cast<uint8_t*>(dst);
            expand_bits(bytes, bits, width, height, dstRB, srcRB);
            break;
        }
        case kA565_GrMaskFormat: {
            uint16_t* rgb565 = reinterpret_cast<uint16_t*>(dst);
            expand_bits(rgb565, bits, width, height, dstRB, srcRB);
            break;
        }
        case kA888_GrMaskFormat: {
            uint32_t* rgba8888 = reinterpret_cast<uint32_t*>(dst);
            expand_bits(rgba8888, bits, width, height, dstRB, srcRB);
            break;
        }
        default:
            GrCrash("Invalid GrMaskFormat");
        }
    } else if (srcRB == dstRB) {
        memcpy(dst, src, dstRB * height);
    } else {
        const int bbp = GrMaskFormatBytesPerPixel(this->getMaskFormat());
        for (int y = 0; y < height; y++) {
            memcpy(dst, src, width * bbp);
            src = (const char*)src + srcRB;
            dst = (char*)dst + dstRB;
        }
    }
    return true;
}
Example #5
0
bool GrAtlas::addSubImage(int width, int height, const void* image,
                          GrIPoint16* loc) {
    if (!fRects->addRect(width + BORDER, height + BORDER, loc)) {
        return false;
    }

    SkAutoSMalloc<1024> storage;
    int dstW = width + 2*BORDER;
    int dstH = height + 2*BORDER;
    if (BORDER) {
        const int bpp = GrMaskFormatBytesPerPixel(fMaskFormat);
        const size_t dstRB = dstW * bpp;
        uint8_t* dst = (uint8_t*)storage.reset(dstH * dstRB);
        Gr_bzero(dst, dstRB);                // zero top row
        dst += dstRB;
        for (int y = 0; y < height; y++) {
            dst = zerofill(dst, bpp);   // zero left edge
            memcpy(dst, image, width * bpp);
            dst += width * bpp;
            dst = zerofill(dst, bpp);   // zero right edge
            image = (const void*)((const char*)image + width * bpp);
        }
        Gr_bzero(dst, dstRB);                // zero bottom row
        image = storage.get();
    }
    adjustForPlot(loc, fPlot);
    GrContext* context = fTexture->getContext();
    // We pass the flag that does not force a flush. We assume our caller is
    // smart and hasn't referenced the part of the texture we're about to update
    // since the last flush.
    context->writeTexturePixels(fTexture,
                                loc->fX, loc->fY, dstW, dstH,
                                fTexture->config(), image, 0,
                                GrContext::kDontFlush_PixelOpsFlag);

    // now tell the caller to skip the top/left BORDER
    loc->fX += BORDER;
    loc->fY += BORDER;

#if FONT_CACHE_STATS
    ++g_UploadCount;
#endif

    return true;
}
Example #6
0
bool GrTextStrike::addGlyphToAtlas(GrGlyph* glyph, GrFontScaler* scaler) {
#if 0   // testing hack to force us to flush our cache often
    static int gCounter;
    if ((++gCounter % 10) == 0) return false;
#endif

    SkASSERT(glyph);
    SkASSERT(scaler);
    SkASSERT(fCache.find(glyph->fPackedID));
    SkASSERT(NULL == glyph->fPlot);

    SkAutoUnref ar(SkSafeRef(scaler));

    int bytesPerPixel = GrMaskFormatBytesPerPixel(glyph->fMaskFormat);

    size_t size = glyph->fBounds.area() * bytesPerPixel;
    GrAutoMalloc<1024> storage(size);

    if (fUseDistanceField) {
        if (!scaler->getPackedGlyphDFImage(glyph->fPackedID, glyph->width(),
                                           glyph->height(),
                                           storage.get())) {
            return false;
        }
    } else {
        if (!scaler->getPackedGlyphImage(glyph->fPackedID, glyph->width(),
                                         glyph->height(),
                                         glyph->width() * bytesPerPixel,
                                         storage.get())) {
            return false;
        }
    }

    GrPlot* plot = fFontCache->addToAtlas(glyph->fMaskFormat, &fPlotUsage,
                                          glyph->width(), glyph->height(),
                                          storage.get(), &glyph->fAtlasLocation);

    if (NULL == plot) {
        return false;
    }

    glyph->fPlot = plot;
    return true;
}
bool GrBatchTextStrike::addGlyphToAtlas(GrDrawBatch::Target* target,
                                        GrGlyph* glyph,
                                        GrFontScaler* scaler,
                                        GrMaskFormat expectedMaskFormat) {
    SkASSERT(glyph);
    SkASSERT(scaler);
    SkASSERT(fCache.find(glyph->fPackedID));

    SkAutoUnref ar(SkSafeRef(scaler));

    int bytesPerPixel = GrMaskFormatBytesPerPixel(expectedMaskFormat);

    size_t size = glyph->fBounds.area() * bytesPerPixel;
    SkAutoSMalloc<1024> storage(size);

    const SkGlyph& skGlyph = scaler->grToSkGlyph(glyph->fPackedID);
    if (GrGlyph::kDistance_MaskStyle == GrGlyph::UnpackMaskStyle(glyph->fPackedID)) {
        if (!scaler->getPackedGlyphDFImage(skGlyph, glyph->width(), glyph->height(),
                                           storage.get())) {
            return false;
        }
    } else {
        if (!scaler->getPackedGlyphImage(skGlyph, glyph->width(), glyph->height(),
                                         glyph->width() * bytesPerPixel, expectedMaskFormat,
                                         storage.get())) {
            return false;
        }
    }

    bool success = fBatchFontCache->addToAtlas(this, &glyph->fID, target, expectedMaskFormat,
                                               glyph->width(), glyph->height(),
                                               storage.get(), &glyph->fAtlasLocation);
    if (success) {
        SkASSERT(GrBatchAtlas::kInvalidAtlasID != glyph->fID);
        fAtlasedGlyphs++;
    }
    return success;
}
bool GrBatchTextStrike::addGlyphToAtlas(GrBatchTarget* batchTarget, GrGlyph* glyph,
                                        GrFontScaler* scaler) {
    SkASSERT(glyph);
    SkASSERT(scaler);
    SkASSERT(fCache.find(glyph->fPackedID));
    SkASSERT(NULL == glyph->fPlot);

    SkAutoUnref ar(SkSafeRef(scaler));

    int bytesPerPixel = GrMaskFormatBytesPerPixel(glyph->fMaskFormat);

    size_t size = glyph->fBounds.area() * bytesPerPixel;
    GrAutoMalloc<1024> storage(size);

    if (GrGlyph::kDistance_MaskStyle == GrGlyph::UnpackMaskStyle(glyph->fPackedID)) {
        if (!scaler->getPackedGlyphDFImage(glyph->fPackedID, glyph->width(),
                                           glyph->height(),
                                           storage.get())) {
            return false;
        }
    } else {
        if (!scaler->getPackedGlyphImage(glyph->fPackedID, glyph->width(),
                                         glyph->height(),
                                         glyph->width() * bytesPerPixel,
                                         storage.get())) {
            return false;
        }
    }

    bool success = fBatchFontCache->addToAtlas(this, &glyph->fID, batchTarget, glyph->fMaskFormat,
                                               glyph->width(), glyph->height(),
                                               storage.get(), &glyph->fAtlasLocation);
    if (success) {
        fAtlasedGlyphs++;
    }
    return success;
}
bool GrAtlasTextStrike::addGlyphToAtlas(GrDrawOp::Target* target,
                                        GrGlyph* glyph,
                                        SkGlyphCache* cache,
                                        GrMaskFormat expectedMaskFormat) {
    SkASSERT(glyph);
    SkASSERT(cache);
    SkASSERT(fCache.find(glyph->fPackedID));

    int bytesPerPixel = GrMaskFormatBytesPerPixel(expectedMaskFormat);

    size_t size = glyph->fBounds.area() * bytesPerPixel;
    SkAutoSMalloc<1024> storage(size);

    const SkGlyph& skGlyph = GrToSkGlyph(cache, glyph->fPackedID);
    if (GrGlyph::kDistance_MaskStyle == GrGlyph::UnpackMaskStyle(glyph->fPackedID)) {
        if (!get_packed_glyph_df_image(cache, skGlyph, glyph->width(), glyph->height(),
                                       storage.get())) {
            return false;
        }
    } else {
        if (!get_packed_glyph_image(cache, skGlyph, glyph->width(), glyph->height(),
                                    glyph->width() * bytesPerPixel, expectedMaskFormat,
                                    storage.get())) {
            return false;
        }
    }

    bool success = fAtlasGlyphCache->addToAtlas(this, &glyph->fID, target, expectedMaskFormat,
                                               glyph->width(), glyph->height(),
                                               storage.get(), &glyph->fAtlasLocation);
    if (success) {
        SkASSERT(GrDrawOpAtlas::kInvalidAtlasID != glyph->fID);
        fAtlasedGlyphs++;
    }
    return success;
}