void
ScaledFontBase::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, const Matrix *aTransformHint)
{
#ifdef USE_CAIRO
  PathBuilderCairo* builder = static_cast<PathBuilderCairo*>(aBuilder);

  
  cairo_t *ctx = cairo_create(DrawTargetCairo::GetDummySurface());

  if (aTransformHint) {
    cairo_matrix_t mat;
    GfxMatrixToCairoMatrix(*aTransformHint, mat);
    cairo_set_matrix(ctx, &mat);
  }

  // Convert our GlyphBuffer into an array of Cairo glyphs.
  std::vector<cairo_glyph_t> glyphs(aBuffer.mNumGlyphs);
  for (uint32_t i = 0; i < aBuffer.mNumGlyphs; ++i) {
    glyphs[i].index = aBuffer.mGlyphs[i].mIndex;
    glyphs[i].x = aBuffer.mGlyphs[i].mPosition.x;
    glyphs[i].y = aBuffer.mGlyphs[i].mPosition.y;
  }

  cairo_set_scaled_font(ctx, mScaledFont);
  cairo_glyph_path(ctx, &glyphs[0], aBuffer.mNumGlyphs);

  RefPtr<PathCairo> cairoPath = new PathCairo(ctx);
  cairo_destroy(ctx);

  cairoPath->AppendPathToBuilder(builder);
#endif
}
Exemple #2
0
int w_newRasterizer(lua_State *L)
{
	Rasterizer *t = NULL;
	try
	{
		if (luax_istype(L, 1, IMAGE_IMAGE_DATA_T))
		{
			love::image::ImageData *d = luax_checktype<love::image::ImageData>(L, 1, "ImageData", IMAGE_IMAGE_DATA_T);
			const char *g = luaL_checkstring(L, 2);
			std::string glyphs(g);
			t = instance->newRasterizer(d, glyphs);
		}
		else if (luax_istype(L, 1, DATA_T))
		{
			Data *d = luax_checkdata(L, 1);
			int size = luaL_checkint(L, 2);
			t = instance->newRasterizer(d, size);
		}
	}
	catch (love::Exception &e)
	{
		return luaL_error(L, "%s", e.what());
	}

	luax_newtype(L, "Rasterizer", FONT_RASTERIZER_T, t);
	return 1;
}
void Canvas::drawText(const uint16_t* text, int start, int count, int contextCount,
        float x, float y, int bidiFlags, const Paint& origPaint, Typeface* typeface) {
    // minikin may modify the original paint
    Paint paint(origPaint);

    Layout layout;
    MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, start, count, contextCount);

    size_t nGlyphs = layout.nGlyphs();
    std::unique_ptr<uint16_t[]> glyphs(new uint16_t[nGlyphs]);
    std::unique_ptr<float[]> pos(new float[nGlyphs * 2]);

    x += MinikinUtils::xOffsetForTextAlign(&paint, layout);

    MinikinRect bounds;
    layout.getBounds(&bounds);
    if (!drawTextAbsolutePos()) {
        bounds.offset(x, y);
    }

    // Set align to left for drawing, as we don't want individual
    // glyphs centered or right-aligned; the offset above takes
    // care of all alignment.
    paint.setTextAlign(Paint::kLeft_Align);

    DrawTextFunctor f(layout, this, glyphs.get(), pos.get(),
            paint, x, y, bounds, layout.getAdvance());
    MinikinUtils::forFontRun(layout, &paint, f);
}
GrPathRange* GrStencilAndCoverTextContext::TextRun::createGlyphs(GrContext* ctx,
                                                                 SkGlyphCache* glyphCache) {
    SkTypeface* typeface = fUsingRawGlyphPaths ? fFont.getTypeface()
                                               : glyphCache->getScalerContext()->getTypeface();
    const SkDescriptor* desc = fUsingRawGlyphPaths ? nullptr : &glyphCache->getDescriptor();

    static const GrUniqueKey::Domain kPathGlyphDomain = GrUniqueKey::GenerateDomain();
    int strokeDataCount = fStroke.computeUniqueKeyFragmentData32Cnt();
    GrUniqueKey glyphKey;
    GrUniqueKey::Builder builder(&glyphKey, kPathGlyphDomain, 2 + strokeDataCount);
    reinterpret_cast<uint32_t&>(builder[0]) = desc ? desc->getChecksum() : 0;
    reinterpret_cast<uint32_t&>(builder[1]) = typeface ? typeface->uniqueID() : 0;
    if (strokeDataCount > 0) {
        fStroke.asUniqueKeyFragment(&builder[2]);
    }
    builder.finish();

    SkAutoTUnref<GrPathRange> glyphs(
        static_cast<GrPathRange*>(
            ctx->resourceProvider()->findAndRefResourceByUniqueKey(glyphKey)));
    if (nullptr == glyphs) {
        glyphs.reset(ctx->resourceProvider()->createGlyphs(typeface, desc, fStroke));
        ctx->resourceProvider()->assignUniqueKeyToResource(glyphKey, glyphs);
    } else {
        SkASSERT(nullptr == desc || glyphs->isEqualTo(*desc));
    }

    return glyphs.detach();
}
Exemple #5
0
DEF_TEST(TextBlob_extended, reporter) {
    SkTextBlobBuilder textBlobBuilder;
    SkFont font;
    const char text1[] = "Foo";
    const char text2[] = "Bar";

    int glyphCount = font.countText(text1, strlen(text1), SkTextEncoding::kUTF8);
    SkAutoTMalloc<uint16_t> glyphs(glyphCount);
    (void)font.textToGlyphs(text1, strlen(text1), SkTextEncoding::kUTF8, glyphs.get(), glyphCount);

    auto run = SkTextBlobBuilderPriv::AllocRunText(&textBlobBuilder,
            font, glyphCount, 0, 0, SkToInt(strlen(text2)), SkString(), nullptr);
    memcpy(run.glyphs, glyphs.get(), sizeof(uint16_t) * glyphCount);
    memcpy(run.utf8text, text2, strlen(text2));
    for (int i = 0; i < glyphCount; ++i) {
        run.clusters[i] = SkTMin(SkToU32(i), SkToU32(strlen(text2)));
    }
    sk_sp<SkTextBlob> blob(textBlobBuilder.make());
    REPORTER_ASSERT(reporter, blob);

    for (SkTextBlobRunIterator it(blob.get()); !it.done(); it.next()) {
        REPORTER_ASSERT(reporter, it.glyphCount() == (uint32_t)glyphCount);
        for (uint32_t i = 0; i < it.glyphCount(); ++i) {
            REPORTER_ASSERT(reporter, it.glyphs()[i] == glyphs[i]);
        }
        REPORTER_ASSERT(reporter, SkTextBlobRunIterator::kDefault_Positioning == it.positioning());
        REPORTER_ASSERT(reporter, (SkPoint{0.0f, 0.0f}) == it.offset());
        REPORTER_ASSERT(reporter, it.textSize() > 0);
        REPORTER_ASSERT(reporter, it.clusters());
        for (uint32_t i = 0; i < it.glyphCount(); ++i) {
            REPORTER_ASSERT(reporter, i == it.clusters()[i]);
        }
        REPORTER_ASSERT(reporter, 0 == strncmp(text2, it.text(), it.textSize()));
    }
}
static GrPathRange* get_gr_glyphs(GrContext* ctx,
                                  const SkTypeface* typeface,
                                  const SkDescriptor* desc,
                                  const GrStrokeInfo& stroke) {

    static const GrUniqueKey::Domain kPathGlyphDomain = GrUniqueKey::GenerateDomain();
    int strokeDataCount = stroke.computeUniqueKeyFragmentData32Cnt();
    GrUniqueKey glyphKey;
    GrUniqueKey::Builder builder(&glyphKey, kPathGlyphDomain, 2 + strokeDataCount);
    reinterpret_cast<uint32_t&>(builder[0]) = desc ? desc->getChecksum() : 0;
    reinterpret_cast<uint32_t&>(builder[1]) = typeface ? typeface->uniqueID() : 0;
    if (strokeDataCount > 0) {
        stroke.asUniqueKeyFragment(&builder[2]);
    }
    builder.finish();

    SkAutoTUnref<GrPathRange> glyphs(
        static_cast<GrPathRange*>(
            ctx->resourceProvider()->findAndRefResourceByUniqueKey(glyphKey)));
    if (NULL == glyphs) {
        glyphs.reset(ctx->resourceProvider()->createGlyphs(typeface, desc, stroke));
        ctx->resourceProvider()->assignUniqueKeyToResource(glyphKey, glyphs);
    } else {
        SkASSERT(NULL == desc || glyphs->isEqualTo(*desc));
    }

    return glyphs.detach();
}
Exemple #7
0
gcn::Font *Engine::LoadFont(const char *infofile, const char *gfxfile)
{
    memblock *fontinfo = resMgr.LoadTextFile((char*)infofile);
    if(!fontinfo)
    {
        logerror("EditorEngine::Setup: Can't load font infos (%s)", infofile);
        return false;
    }
    std::string glyphs((char*)(fontinfo->ptr));
    logdetail("Using font glyphs for '%s':", gfxfile);
    logdetail("%s", glyphs.c_str());

    gcn::Font *font = NULL;
    try
    {
        font = new gcn::ImageFont(gfxfile, glyphs);
    }
    catch(gcn::Exception ex)
    {
        delete font;
        font = NULL;
    }
    resMgr.Drop(fontinfo);

    return font;
}
static GrPathRange* get_gr_glyphs(GrContext* ctx,
                                  const SkTypeface* typeface,
                                  const SkDescriptor* desc,
                                  const SkStrokeRec& stroke) {
    static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
    GrUniqueKey key;
    GrUniqueKey::Builder builder(&key, kDomain, 4);
    struct GlyphKey {
        uint32_t fChecksum;
        uint32_t fTypeface;
        uint64_t fStroke;
    };
    GlyphKey* glyphKey = reinterpret_cast<GlyphKey*>(&builder[0]);
    glyphKey->fChecksum = desc ? desc->getChecksum() : 0;
    glyphKey->fTypeface = typeface ? typeface->uniqueID() : 0;
    glyphKey->fStroke = GrPath::ComputeStrokeKey(stroke);
    builder.finish();

    SkAutoTUnref<GrPathRange> glyphs(
        static_cast<GrPathRange*>(ctx->resourceProvider()->findAndRefResourceByUniqueKey(key)));
    if (NULL == glyphs || (NULL != desc && !glyphs->isEqualTo(*desc))) {
        glyphs.reset(ctx->getGpu()->pathRendering()->createGlyphs(typeface, desc, stroke));
        ctx->resourceProvider()->assignUniqueKeyToResource(key, glyphs);
    }

    return glyphs.detach();
}
Exemple #9
0
void GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx,
                                                 GrDrawContext* dc,
                                                 GrPipelineBuilder* pipelineBuilder,
                                                 GrColor color,
                                                 const SkMatrix& viewMatrix,
                                                 SkScalar x, SkScalar y,
                                                 const SkIRect& clipBounds,
                                                 GrTextContext* fallbackTextContext,
                                                 const SkPaint& originalSkPaint) const {
    SkASSERT(fDraw);
    SkASSERT(pipelineBuilder->getRenderTarget()->isStencilBufferMultisampled() ||
             !fFont.isAntiAlias());

    if (fDraw->count()) {
        pipelineBuilder->setState(GrPipelineBuilder::kHWAntialias_Flag, fFont.isAntiAlias());

        GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
                                     kZero_StencilOp,
                                     kKeep_StencilOp,
                                     kNotEqual_StencilFunc,
                                     0xffff,
                                     0x0000,
                                     0xffff);

        *pipelineBuilder->stencil() = kStencilPass;

        SkAutoTUnref<GrPathRange> glyphs(this->createGlyphs(ctx));
        if (fLastDrawnGlyphsID != glyphs->getUniqueID()) {
            // Either this is the first draw or the glyphs object was purged since last draw.
            glyphs->loadPathsIfNeeded(fDraw->indices(), fDraw->count());
            fLastDrawnGlyphsID = glyphs->getUniqueID();
        }

        SkMatrix drawMatrix(viewMatrix);
        drawMatrix.preTranslate(x, y);
        drawMatrix.preScale(fTextRatio, fTextRatio);

        SkMatrix& localMatrix = fLocalMatrixTemplate;
        localMatrix.setTranslateX(x);
        localMatrix.setTranslateY(y);

        dc->drawPathsFromRange(pipelineBuilder, drawMatrix, localMatrix, color, glyphs, fDraw,
                               GrPathRendering::kWinding_FillType);
    }

    if (fFallbackTextBlob) {
        SkPaint fallbackSkPaint(originalSkPaint);
        fStroke.applyToPaint(&fallbackSkPaint);
        if (!fStroke.isFillStyle()) {
            fallbackSkPaint.setStrokeWidth(fStroke.getWidth() * fTextRatio);
        }

        fallbackTextContext->drawTextBlob(dc, pipelineBuilder->getRenderTarget(),
                                          pipelineBuilder->clip(), fallbackSkPaint, viewMatrix,
                                          fFallbackTextBlob, x, y, nullptr, clipBounds);
    }
}
void QTextEngine::shape( int item ) const
{
    assert( item < items.size() );
    QScriptItem &si = items[item];

    if ( si.num_glyphs )
	return;

    QFont::Script script = (QFont::Script)si.analysis.script;
    si.glyph_data_offset = used;

    if ( !si.fontEngine )
	si.fontEngine = fnt->engineForScript( script );
    si.fontEngine->ref();

	si.ascent = si.fontEngine->ascent();
	si.descent = si.fontEngine->descent();
    si.num_glyphs = 0;

    if ( si.fontEngine && si.fontEngine != (QFontEngine*)-1 ) {
        QShaperItem shaper_item;
        shaper_item.script = si.analysis.script;
        shaper_item.string = &string;
        shaper_item.from = si.position;
        shaper_item.length = length(item);
        shaper_item.font = si.fontEngine;
        shaper_item.num_glyphs = QMAX(int(num_glyphs - used), shaper_item.length);
        shaper_item.flags = si.analysis.bidiLevel % 2 ? RightToLeft : 0;

        while (1) {
//         qDebug("    . num_glyphs=%d, used=%d, item.num_glyphs=%d", num_glyphs, used, shaper_item.num_glyphs);
            ensureSpace(shaper_item.num_glyphs);
            shaper_item.num_glyphs = num_glyphs - used;
//          qDebug("    .. num_glyphs=%d, used=%d, item.num_glyphs=%d", num_glyphs, used, shaper_item.num_glyphs);
            shaper_item.glyphs = glyphs(&si);
            shaper_item.advances = advances(&si);
            shaper_item.offsets = offsets(&si);
            shaper_item.attributes = glyphAttributes(&si);
            shaper_item.log_clusters = logClusters(&si);
            if (scriptEngines[shaper_item.script].shape(&shaper_item))
                break;
        }

        si.num_glyphs = shaper_item.num_glyphs;
    }
    ((QTextEngine *)this)->used += si.num_glyphs;

    si.width = 0;
    advance_t *advances = this->advances( &si );
    advance_t *end = advances + si.num_glyphs;
    while ( advances < end )
	si.width += *(advances++);

    return;
}
TemporaryRef<Path>
ScaledFontBase::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget)
{
#ifdef USE_SKIA
  if (aTarget->GetType() == BACKEND_SKIA) {
    SkPaint paint;
    paint.setTypeface(GetSkTypeface());
    paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
    paint.setTextSize(SkFloatToScalar(mSize));

    std::vector<uint16_t> indices;
    std::vector<SkPoint> offsets;
    indices.resize(aBuffer.mNumGlyphs);
    offsets.resize(aBuffer.mNumGlyphs);

    for (unsigned int i = 0; i < aBuffer.mNumGlyphs; i++) {
      indices[i] = aBuffer.mGlyphs[i].mIndex;
      offsets[i].fX = SkFloatToScalar(aBuffer.mGlyphs[i].mPosition.x);
      offsets[i].fY = SkFloatToScalar(aBuffer.mGlyphs[i].mPosition.y);
    }

    SkPath path;
    paint.getPosTextPath(&indices.front(), aBuffer.mNumGlyphs*2, &offsets.front(), &path);
    return new PathSkia(path, FILL_WINDING);
  }
#endif
#ifdef USE_CAIRO
  if (aTarget->GetType() == BACKEND_CAIRO) {
    MOZ_ASSERT(mScaledFont);

    RefPtr<PathBuilder> builder_iface = aTarget->CreatePathBuilder();
    PathBuilderCairo* builder = static_cast<PathBuilderCairo*>(builder_iface.get());

    // Manually build the path for the PathBuilder.
    RefPtr<CairoPathContext> context = builder->GetPathContext();

    cairo_set_scaled_font(*context, mScaledFont);

    // Convert our GlyphBuffer into an array of Cairo glyphs.
    std::vector<cairo_glyph_t> glyphs(aBuffer.mNumGlyphs);
    for (uint32_t i = 0; i < aBuffer.mNumGlyphs; ++i) {
      glyphs[i].index = aBuffer.mGlyphs[i].mIndex;
      glyphs[i].x = aBuffer.mGlyphs[i].mPosition.x;
      glyphs[i].y = aBuffer.mGlyphs[i].mPosition.y;
    }

    cairo_glyph_path(*context, &glyphs[0], aBuffer.mNumGlyphs);

    return builder->Finish();
  }
#endif
  return NULL;
}
bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
{
    bool haveGlyphs = false;

#ifndef BUILDING_ON_TIGER
    Vector<CGGlyph, 512> glyphs(bufferLength);
    wkGetGlyphsForCharacters(fontData->platformData().cgFont(), buffer, glyphs.data(), bufferLength);

    for (unsigned i = 0; i < length; ++i) {
        if (!glyphs[i])
            setGlyphDataForIndex(offset + i, 0, 0);
        else {
            setGlyphDataForIndex(offset + i, glyphs[i], fontData);
            haveGlyphs = true;
        }
    }
#else
    // Use an array of long so we get good enough alignment.
    long glyphVector[(GLYPH_VECTOR_SIZE + sizeof(long) - 1) / sizeof(long)];
    
    OSStatus status = wkInitializeGlyphVector(GlyphPage::size, &glyphVector);
    if (status != noErr)
        // This should never happen, perhaps indicates a bad font!  If it does the
        // font substitution code will find an alternate font.
        return false;

    wkConvertCharToGlyphs(fontData->m_styleGroup, buffer, bufferLength, &glyphVector);

    unsigned numGlyphs = wkGetGlyphVectorNumGlyphs(&glyphVector);
    if (numGlyphs != length) {
        // This should never happen, perhaps indicates a bad font?
        // If it does happen, the font substitution code will find an alternate font.
        wkClearGlyphVector(&glyphVector);
        return false;
    }

    ATSLayoutRecord* glyphRecord = (ATSLayoutRecord*)wkGetGlyphVectorFirstRecord(glyphVector);
    for (unsigned i = 0; i < length; i++) {
        Glyph glyph = glyphRecord->glyphID;
        if (!glyph)
            setGlyphDataForIndex(offset + i, 0, 0);
        else {
            setGlyphDataForIndex(offset + i, glyph, fontData);
            haveGlyphs = true;
        }
        glyphRecord = (ATSLayoutRecord *)((char *)glyphRecord + wkGetGlyphVectorRecordSize(glyphVector));
    }
    wkClearGlyphVector(&glyphVector);
#endif

    return haveGlyphs;
}
void
ScaledFontBase::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, const Matrix *aTransformHint)
{
  BackendType backendType = aBuilder->GetBackendType();
#ifdef USE_SKIA
  if (backendType == BackendType::SKIA) {
    PathBuilderSkia *builder = static_cast<PathBuilderSkia*>(aBuilder);
    builder->AppendPath(GetSkiaPathForGlyphs(aBuffer));
    return;
  }
#endif
#ifdef USE_CAIRO
  if (backendType == BackendType::CAIRO) {
    MOZ_ASSERT(mScaledFont);

    PathBuilderCairo* builder = static_cast<PathBuilderCairo*>(aBuilder);
    cairo_t *ctx = cairo_create(DrawTargetCairo::GetDummySurface());

    if (aTransformHint) {
      cairo_matrix_t mat;
      GfxMatrixToCairoMatrix(*aTransformHint, mat);
      cairo_set_matrix(ctx, &mat);
    }

    // Convert our GlyphBuffer into an array of Cairo glyphs.
    std::vector<cairo_glyph_t> glyphs(aBuffer.mNumGlyphs);
    for (uint32_t i = 0; i < aBuffer.mNumGlyphs; ++i) {
      glyphs[i].index = aBuffer.mGlyphs[i].mIndex;
      glyphs[i].x = aBuffer.mGlyphs[i].mPosition.x;
      glyphs[i].y = aBuffer.mGlyphs[i].mPosition.y;
    }

    cairo_set_scaled_font(ctx, mScaledFont);
    cairo_glyph_path(ctx, &glyphs[0], aBuffer.mNumGlyphs);

    RefPtr<PathCairo> cairoPath = new PathCairo(ctx);
    cairo_destroy(ctx);

    cairoPath->AppendPathToBuilder(builder);
    return;
  }
  if (backendType == BackendType::RECORDING) {
    SkPath skPath = GetSkiaPathForGlyphs(aBuffer);
    RefPtr<Path> path = MakeAndAddRef<PathSkia>(skPath, FillRule::FILL_WINDING);
    path->StreamToSink(aBuilder);
    return;
  }
  MOZ_ASSERT(false, "Path not being copied");
#endif
}
already_AddRefed<Path>
ScaledFontBase::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget)
{
#ifdef USE_SKIA
  if (aTarget->GetBackendType() == BackendType::SKIA) {
    SkPath path = GetSkiaPathForGlyphs(aBuffer);
    return MakeAndAddRef<PathSkia>(path, FillRule::FILL_WINDING);
  }
#endif
#ifdef USE_CAIRO
  if (aTarget->GetBackendType() == BackendType::CAIRO) {
    MOZ_ASSERT(mScaledFont);

    DrawTarget *dt = const_cast<DrawTarget*>(aTarget);
    cairo_t *ctx = static_cast<cairo_t*>(dt->GetNativeSurface(NativeSurfaceType::CAIRO_CONTEXT));

    bool isNewContext = !ctx;
    if (!ctx) {
      ctx = cairo_create(DrawTargetCairo::GetDummySurface());
      cairo_matrix_t mat;
      GfxMatrixToCairoMatrix(aTarget->GetTransform(), mat);
      cairo_set_matrix(ctx, &mat);
    }

    cairo_set_scaled_font(ctx, mScaledFont);

    // Convert our GlyphBuffer into an array of Cairo glyphs.
    std::vector<cairo_glyph_t> glyphs(aBuffer.mNumGlyphs);
    for (uint32_t i = 0; i < aBuffer.mNumGlyphs; ++i) {
      glyphs[i].index = aBuffer.mGlyphs[i].mIndex;
      glyphs[i].x = aBuffer.mGlyphs[i].mPosition.x;
      glyphs[i].y = aBuffer.mGlyphs[i].mPosition.y;
    }

    cairo_new_path(ctx);

    cairo_glyph_path(ctx, &glyphs[0], aBuffer.mNumGlyphs);

    RefPtr<PathCairo> newPath = new PathCairo(ctx);
    if (isNewContext) {
      cairo_destroy(ctx);
    }

    return newPath.forget();
  }
#endif
  return nullptr;
}
	void compile(CompileOptions& opts)
	{
		Buffer buf = opts.read();

		TempAllocator4096 ta;
		JsonObject object(ta);
		JsonArray glyphs(ta);

		sjson::parse(buf, object);
		sjson::parse_array(object["glyphs"], glyphs);

		const u32 texture_size = sjson::parse_int(object["size"]);
		const u32 font_size    = sjson::parse_int(object["font_size"]);
		const u32 num_glyphs   = array::size(glyphs);

		Array<GlyphInfo> _glyphs(default_allocator());
		array::resize(_glyphs, num_glyphs);

		for (u32 i = 0; i < num_glyphs; ++i)
		{
			parse_glyph(glyphs[i], _glyphs[i]);
		}

		std::sort(array::begin(_glyphs), array::end(_glyphs));

		opts.write(RESOURCE_VERSION_FONT);
		opts.write(num_glyphs);
		opts.write(texture_size);
		opts.write(font_size);

		for (u32 i = 0; i < array::size(_glyphs); ++i)
		{
			opts.write(_glyphs[i].cp);
		}

		for (u32 i = 0; i < array::size(_glyphs); ++i)
		{
			opts.write(_glyphs[i].gd.x);
			opts.write(_glyphs[i].gd.y);
			opts.write(_glyphs[i].gd.width);
			opts.write(_glyphs[i].gd.height);
			opts.write(_glyphs[i].gd.x_offset);
			opts.write(_glyphs[i].gd.y_offset);
			opts.write(_glyphs[i].gd.x_advance);
		}
	}
void
ScaledFontBase::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, BackendType aBackendType, const Matrix *aTransformHint)
{
#ifdef USE_SKIA
  if (aBackendType == BackendType::SKIA) {
    PathBuilderSkia *builder = static_cast<PathBuilderSkia*>(aBuilder);
    builder->AppendPath(GetSkiaPathForGlyphs(aBuffer));
    return;
  }
#endif
#ifdef USE_CAIRO
  if (aBackendType == BackendType::CAIRO) {
    MOZ_ASSERT(mScaledFont);

    PathBuilderCairo* builder = static_cast<PathBuilderCairo*>(aBuilder);
    cairo_t *ctx = cairo_create(DrawTargetCairo::GetDummySurface());

    if (aTransformHint) {
      cairo_matrix_t mat;
      GfxMatrixToCairoMatrix(*aTransformHint, mat);
      cairo_set_matrix(ctx, &mat);
    }

    // Convert our GlyphBuffer into an array of Cairo glyphs.
    std::vector<cairo_glyph_t> glyphs(aBuffer.mNumGlyphs);
    for (uint32_t i = 0; i < aBuffer.mNumGlyphs; ++i) {
      glyphs[i].index = aBuffer.mGlyphs[i].mIndex;
      glyphs[i].x = aBuffer.mGlyphs[i].mPosition.x;
      glyphs[i].y = aBuffer.mGlyphs[i].mPosition.y;
    }

    cairo_set_scaled_font(ctx, mScaledFont);
    cairo_glyph_path(ctx, &glyphs[0], aBuffer.mNumGlyphs);

    RefPtr<PathCairo> cairoPath = new PathCairo(ctx);
    cairo_destroy(ctx);

    cairoPath->AppendPathToBuilder(builder);
    return;
  }
#endif

  MOZ_CRASH("The specified backend type is not supported by CopyGlyphsToBuilder");
}
Exemple #17
0
bool GlyphPage::fill(UChar* buffer, unsigned bufferLength, const Font* fontData)
{
    bool haveGlyphs = false;

    Vector<CGGlyph, 512> glyphs(bufferLength);
    if (!shouldUseCoreText(buffer, bufferLength, fontData)) {
        // We pass in either 256 or 512 UTF-16 characters: 256 for U+FFFF and less, 512 (double character surrogates)
        // for U+10000 and above. It is indeed possible to get back 512 glyphs back from the API, so the glyph buffer
        // we pass in must be 512. If we get back more than 256 glyphs though we'll ignore all the ones after 256,
        // this should not happen as the only time we pass in 512 characters is when they are surrogates.
        CGFontGetGlyphsForUnichars(fontData->platformData().cgFont(), buffer, glyphs.data(), bufferLength);
        for (unsigned i = 0; i < GlyphPage::size; ++i) {
            if (!glyphs[i])
                setGlyphDataForIndex(i, 0, 0);
            else {
                setGlyphDataForIndex(i, glyphs[i], fontData);
                haveGlyphs = true;
            }
        }
    } else {
        // Because we know the implementation of shouldUseCoreText(), if the font isn't for text combine and it isn't a system font,
        // we know it must have vertical glyphs.
        if (fontData->platformData().isForTextCombine() || fontData->isSystemFont())
            CTFontGetGlyphsForCharacters(fontData->platformData().ctFont(), buffer, glyphs.data(), bufferLength);
        else
            CTFontGetVerticalGlyphsForCharacters(fontData->platformData().ctFont(), buffer, glyphs.data(), bufferLength);
        // When buffer consists of surrogate pairs, CTFontGetVerticalGlyphsForCharacters and CTFontGetGlyphsForCharacters
        // place the glyphs at indices corresponding to the first character of each pair.
        ASSERT(bufferLength == GlyphPage::size || bufferLength == 2 * GlyphPage::size);
        unsigned glyphStep = bufferLength / GlyphPage::size;
        for (unsigned i = 0; i < GlyphPage::size; ++i) {
            if (!glyphs[i * glyphStep])
                setGlyphDataForIndex(i, 0, 0);
            else {
                setGlyphDataForIndex(i, glyphs[i * glyphStep], fontData);
                haveGlyphs = true;
            }
        }
    }

    return haveGlyphs;
}
static GrPathRange* get_gr_glyphs(GrContext* ctx,
                                  const SkTypeface* typeface,
                                  const SkDescriptor* desc,
                                  const SkStrokeRec& stroke) {
    static const GrCacheID::Domain gGlyphsDomain = GrCacheID::GenerateDomain();

    GrCacheID::Key key;
    uint64_t* keyData = key.fData64;
    keyData[0] = desc ? desc->getChecksum() : 0;
    keyData[0] = (keyData[0] << 32) | (typeface ? typeface->uniqueID() : 0);
    keyData[1] = GrPath::ComputeStrokeKey(stroke);
    GrResourceKey resourceKey = GrResourceKey(GrCacheID(gGlyphsDomain, key),
                                              GrPathRange::resourceType(), 0);

    SkAutoTUnref<GrPathRange> glyphs(
        static_cast<GrPathRange*>(ctx->findAndRefCachedResource(resourceKey)));
    if (NULL == glyphs || (NULL != desc && !glyphs->isEqualTo(*desc))) {
        glyphs.reset(ctx->getGpu()->pathRendering()->createGlyphs(typeface, desc, stroke));
        ctx->addResourceToCache(resourceKey, glyphs);
    }

    return glyphs.detach();
}
void GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx,
                                                 GrRenderTargetContext* renderTargetContext,
                                                 const GrClip& clip, const SkMatrix& viewMatrix,
                                                 const SkSurfaceProps& props, SkScalar x,
                                                 SkScalar y, const SkIRect& clipBounds,
                                                 GrAtlasTextContext* fallbackTextContext,
                                                 const SkPaint& originalSkPaint) const {
    SkASSERT(fInstanceData);

    if (fInstanceData->count()) {
        static constexpr GrUserStencilSettings kCoverPass(
            GrUserStencilSettings::StaticInit<
                0x0000,
                GrUserStencilTest::kNotEqual, // Stencil pass accounts for clip.
                0xffff,
                GrUserStencilOp::kZero,
                GrUserStencilOp::kKeep,
                0xffff>()
        );

        sk_sp<GrPathRange> glyphs(this->createGlyphs(ctx->resourceProvider()));
        if (fLastDrawnGlyphsID != glyphs->uniqueID()) {
            // Either this is the first draw or the glyphs object was purged since last draw.
            glyphs->loadPathsIfNeeded(fInstanceData->indices(), fInstanceData->count());
            fLastDrawnGlyphsID = glyphs->uniqueID();
        }

        GrPaint grPaint;
        if (!SkPaintToGrPaint(ctx, renderTargetContext, originalSkPaint, viewMatrix, &grPaint)) {
            return;
        }

        // Don't compute a bounding box. For dst copy texture, we'll opt instead for it to just copy
        // the entire dst. Realistically this is a moot point, because any context that supports
        // NV_path_rendering will also support NV_blend_equation_advanced.
        // For clipping we'll just skip any optimizations based on the bounds. This does, however,
        // hurt GrOp combining.
        const SkRect bounds = SkRect::MakeIWH(renderTargetContext->width(),
                                              renderTargetContext->height());

        // The run's "font" overrides the anti-aliasing of the passed in SkPaint!
        GrAAType aaType;
        if (this->aa() == GrAA::kYes) {
            SkASSERT(renderTargetContext->isStencilBufferMultisampled());
            aaType = renderTargetContext->isUnifiedMultisampled() ? GrAAType::kMSAA
                                                                  : GrAAType::kMixedSamples;
        } else {
            aaType = GrAAType::kNone;
        }

        std::unique_ptr<GrDrawOp> op = GrDrawPathRangeOp::Make(
                viewMatrix, fTextRatio, fTextInverseRatio * x, fTextInverseRatio * y,
                std::move(grPaint), GrPathRendering::kWinding_FillType, aaType, glyphs.get(),
                fInstanceData.get(), bounds);

        renderTargetContext->addDrawOp(clip, std::move(op));
    }

    if (fFallbackTextBlob) {
        SkPaint fallbackSkPaint(originalSkPaint);
        fStyle.strokeRec().applyToPaint(&fallbackSkPaint);
        if (!fStyle.isSimpleFill()) {
            fallbackSkPaint.setStrokeWidth(fStyle.strokeRec().getWidth() * fTextRatio);
        }

        fallbackTextContext->drawTextBlob(ctx, renderTargetContext, clip, fallbackSkPaint,
                                          viewMatrix, props, fFallbackTextBlob.get(), x, y, nullptr,
                                          clipBounds);
    }
}
Exemple #20
0
    virtual void onDraw(SkCanvas* inputCanvas) override {
        SkScalar textSizes[] = { 9.0f, 9.0f*2.0f, 9.0f*5.0f, 9.0f*2.0f*5.0f };
        SkScalar scales[] = { 2.0f*5.0f, 5.0f, 2.0f, 1.0f };

        // set up offscreen rendering with distance field text
        GrContext* ctx = inputCanvas->getGrContext();
        SkISize size = onISize();
        SkImageInfo info = SkImageInfo::MakeN32(size.width(), size.height(), kPremul_SkAlphaType,
                                                inputCanvas->imageInfo().refColorSpace());
        SkSurfaceProps props(SkSurfaceProps::kUseDeviceIndependentFonts_Flag,
                             SkSurfaceProps::kLegacyFontHost_InitType);
        auto surface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info, 0, &props));
        SkCanvas* canvas = surface ? surface->getCanvas() : inputCanvas;
        // init our new canvas with the old canvas's matrix
        canvas->setMatrix(inputCanvas->getTotalMatrix());
        // apply global scale to test glyph positioning
        canvas->scale(1.05f, 1.05f);
        canvas->clear(0xffffffff);

        SkPaint paint;
        paint.setAntiAlias(true);

        SkFont font(ToolUtils::create_portable_typeface("serif", SkFontStyle()));
        font.setSubpixel(true);

        const char* text = "Hamburgefons";
        const size_t textLen = strlen(text);

        // check scaling up
        SkScalar x = SkIntToScalar(0);
        SkScalar y = SkIntToScalar(78);
        for (size_t i = 0; i < SK_ARRAY_COUNT(textSizes); ++i) {
            SkAutoCanvasRestore acr(canvas, true);
            canvas->translate(x, y);
            canvas->scale(scales[i], scales[i]);
            font.setSize(textSizes[i]);
            canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, 0, 0, font, paint);
            y += font.getMetrics(nullptr)*scales[i];
        }

        // check rotation
        for (size_t i = 0; i < 5; ++i) {
            SkScalar rotX = SkIntToScalar(10);
            SkScalar rotY = y;

            SkAutoCanvasRestore acr(canvas, true);
            canvas->translate(SkIntToScalar(10 + i * 200), -80);
            canvas->rotate(SkIntToScalar(i * 5), rotX, rotY);
            for (int ps = 6; ps <= 32; ps += 3) {
                font.setSize(SkIntToScalar(ps));
                canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, rotX, rotY, font, paint);
                rotY += font.getMetrics(nullptr);
            }
        }

        // check scaling down
        font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
        x = SkIntToScalar(680);
        y = SkIntToScalar(20);
        size_t arraySize = SK_ARRAY_COUNT(textSizes);
        for (size_t i = 0; i < arraySize; ++i) {
            SkAutoCanvasRestore acr(canvas, true);
            canvas->translate(x, y);
            SkScalar scaleFactor = SkScalarInvert(scales[arraySize - i - 1]);
            canvas->scale(scaleFactor, scaleFactor);
            font.setSize(textSizes[i]);
            canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, 0, 0, font, paint);
            y += font.getMetrics(nullptr)*scaleFactor;
        }

        // check pos text
        {
            SkAutoCanvasRestore acr(canvas, true);

            canvas->scale(2.0f, 2.0f);

            SkAutoTArray<SkGlyphID> glyphs(SkToInt(textLen));
            int count = font.textToGlyphs(text, textLen, SkTextEncoding::kUTF8, glyphs.get(), textLen);
            SkAutoTArray<SkPoint>  pos(count);
            font.setSize(textSizes[0]);
            font.getPos(glyphs.get(), count, pos.get(), {340, 75});

            auto blob = SkTextBlob::MakeFromPosText(glyphs.get(), count * sizeof(SkGlyphID),
                                                    pos.get(), font, SkTextEncoding::kGlyphID);
            canvas->drawTextBlob(blob, 0, 0, paint);
        }


        // check gamma-corrected blending
        const SkColor fg[] = {
            0xFFFFFFFF,
            0xFFFFFF00, 0xFFFF00FF, 0xFF00FFFF,
            0xFFFF0000, 0xFF00FF00, 0xFF0000FF,
            0xFF000000,
        };

        paint.setColor(0xFFF7F3F7);
        SkRect r = SkRect::MakeLTRB(670, 215, 820, 397);
        canvas->drawRect(r, paint);

        x = SkIntToScalar(680);
        y = SkIntToScalar(235);
        font.setSize(SkIntToScalar(19));
        for (size_t i = 0; i < SK_ARRAY_COUNT(fg); ++i) {
            paint.setColor(fg[i]);

            canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, x, y, font, paint);
            y += font.getMetrics(nullptr);
        }

        paint.setColor(0xFF181C18);
        r = SkRect::MakeLTRB(820, 215, 970, 397);
        canvas->drawRect(r, paint);

        x = SkIntToScalar(830);
        y = SkIntToScalar(235);
        font.setSize(SkIntToScalar(19));
        for (size_t i = 0; i < SK_ARRAY_COUNT(fg); ++i) {
            paint.setColor(fg[i]);

            canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, x, y, font, paint);
            y += font.getMetrics(nullptr);
        }

        // check skew
        {
            font.setEdging(SkFont::Edging::kAntiAlias);
            SkAutoCanvasRestore acr(canvas, true);
            canvas->skew(0.0f, 0.151515f);
            font.setSize(SkIntToScalar(32));
            canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, 745, 70, font, paint);
        }
        {
            font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
            SkAutoCanvasRestore acr(canvas, true);
            canvas->skew(0.5f, 0.0f);
            font.setSize(SkIntToScalar(32));
            canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, 580, 125, font, paint);
        }

        // check perspective
        {
            font.setEdging(SkFont::Edging::kAntiAlias);
            SkAutoCanvasRestore acr(canvas, true);
            SkMatrix persp;
            persp.setAll(0.9839f, 0, 0,
                         0.2246f, 0.6829f, 0,
                         0.0002352f, -0.0003844f, 1);
            canvas->concat(persp);
            canvas->translate(1100, -295);
            font.setSize(37.5f);
            canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, 0, 0, font, paint);
        }
        {
            font.setSubpixel(false);
            font.setEdging(SkFont::Edging::kAlias);
            SkAutoCanvasRestore acr(canvas, true);
            SkMatrix persp;
            persp.setAll(0.9839f, 0, 0,
                         0.2246f, 0.6829f, 0,
                         0.0002352f, -0.0003844f, 1);
            canvas->concat(persp);
            canvas->translate(1075, -245);
            canvas->scale(375, 375);
            font.setSize(0.1f);
            canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, 0, 0, font, paint);
        }

        // check color emoji
        if (fEmojiTypeface) {
            SkFont emoiFont;
            emoiFont.setSubpixel(true);
            emoiFont.setTypeface(fEmojiTypeface);
            emoiFont.setSize(SkIntToScalar(19));
            canvas->drawSimpleText(fEmojiText, strlen(fEmojiText), SkTextEncoding::kUTF8, 670, 90, emoiFont, paint);
        }

        // render offscreen buffer
        if (surface) {
            SkAutoCanvasRestore acr(inputCanvas, true);
            // since we prepended this matrix already, we blit using identity
            inputCanvas->resetMatrix();
            inputCanvas->drawImage(surface->makeImageSnapshot().get(), 0, 0, nullptr);
        }
    }
bool SimpleFontData::fillGlyphPage(GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength) const
{
    bool haveGlyphs = false;

    Vector<CGGlyph, 512> glyphs(bufferLength);
    if (!shouldUseCoreText(buffer, bufferLength, this)) {
        CGFontGetGlyphsForUnichars(platformData().cgFont(), buffer, glyphs.data(), bufferLength);
        for (unsigned i = 0; i < length; ++i) {
            if (glyphs[i]) {
                pageToFill->setGlyphDataForIndex(offset + i, glyphs[i], this);
                haveGlyphs = true;
            }
        }
    } else if (!platformData().isCompositeFontReference() && platformData().widthVariant() != RegularWidth
        && CTFontGetGlyphsForCharacters(platformData().ctFont(), buffer, glyphs.data(), bufferLength)) {
        // When buffer consists of surrogate pairs, CTFontGetGlyphsForCharacters
        // places the glyphs at indices corresponding to the first character of each pair.
        unsigned glyphStep = bufferLength / length;
        for (unsigned i = 0; i < length; ++i) {
            if (glyphs[i * glyphStep]) {
                pageToFill->setGlyphDataForIndex(offset + i, glyphs[i * glyphStep], this);
                haveGlyphs = true;
            }
        }
    } else {
        // We ask CoreText for possible vertical variant glyphs
        RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, buffer, bufferLength, kCFAllocatorNull));
        RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(kCFAllocatorDefault, string.get(), getCFStringAttributes(0, hasVerticalGlyphs() ? Vertical : Horizontal)));
        RetainPtr<CTLineRef> line(AdoptCF, CTLineCreateWithAttributedString(attributedString.get()));

        CFArrayRef runArray = CTLineGetGlyphRuns(line.get());
        CFIndex runCount = CFArrayGetCount(runArray);

        Vector<CGGlyph, 512> glyphVector;
        Vector<CFIndex, 512> indexVector;
        bool done = false;

        // For the CGFont comparison in the loop, use the CGFont that Core Text assigns to the CTFont. This may
        // be non-CFEqual to platformData().cgFont().
        RetainPtr<CGFontRef> cgFont(AdoptCF, CTFontCopyGraphicsFont(platformData().ctFont(), 0));

        for (CFIndex r = 0; r < runCount && !done ; ++r) {
            // CTLine could map characters over multiple fonts using its own font fallback list.
            // We need to pick runs that use the exact font we need, i.e., platformData().ctFont().
            CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r));
            ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID());

            CFDictionaryRef attributes = CTRunGetAttributes(ctRun);
            CTFontRef runFont = static_cast<CTFontRef>(CFDictionaryGetValue(attributes, kCTFontAttributeName));
            RetainPtr<CGFontRef> runCGFont(AdoptCF, CTFontCopyGraphicsFont(runFont, 0));
            // Use CGFont here as CFEqual for CTFont counts all attributes for font.
            bool gotBaseFont = CFEqual(cgFont.get(), runCGFont.get());
            if (gotBaseFont || platformData().isCompositeFontReference()) {
                // This run uses the font we want. Extract glyphs.
                CFIndex glyphCount = CTRunGetGlyphCount(ctRun);
                const CGGlyph* glyphs = CTRunGetGlyphsPtr(ctRun);
                if (!glyphs) {
                    glyphVector.resize(glyphCount);
                    CTRunGetGlyphs(ctRun, CFRangeMake(0, 0), glyphVector.data());
                    glyphs = glyphVector.data();
                }
                const CFIndex* stringIndices = CTRunGetStringIndicesPtr(ctRun);
                if (!stringIndices) {
                    indexVector.resize(glyphCount);
                    CTRunGetStringIndices(ctRun, CFRangeMake(0, 0), indexVector.data());
                    stringIndices = indexVector.data();
                }

                if (gotBaseFont) {
                    for (CFIndex i = 0; i < glyphCount; ++i) {
                        if (stringIndices[i] >= static_cast<CFIndex>(length)) {
                            done = true;
                            break;
                        }
                        if (glyphs[i]) {
                            pageToFill->setGlyphDataForIndex(offset + stringIndices[i], glyphs[i], this);
                            haveGlyphs = true;
                        }
                    }
                } else {
                    const SimpleFontData* runSimple = getCompositeFontReferenceFontData((NSFont *)runFont);
                    if (runSimple) {
                        for (CFIndex i = 0; i < glyphCount; ++i) {
                            if (stringIndices[i] >= static_cast<CFIndex>(length)) {
                                done = true;
                                break;
                            }
                            if (glyphs[i]) {
                                pageToFill->setGlyphDataForIndex(offset + stringIndices[i], glyphs[i], runSimple);
                                haveGlyphs = true;
                            }
                        }
                    }
                }
            }
        }
    }

    return haveGlyphs;
}
Exemple #22
0
template <typename T> EXPORTGTPLPLOT
bool plotCurves(const std::vector<hoNDArray<T> >& x, const std::vector<hoNDArray<T> >& y, 
                const std::string& xlabel, const std::string& ylabel, 
                const std::string& title, const std::vector<std::string>& legend, 
                const std::vector<std::string>& symbols, 
                size_t xsize, size_t ysize, 
                T xlim[2], T ylim[2], 
                bool trueColor, bool drawLine, 
                hoNDArray<float>& plotIm)
{
    try
    {
        GADGET_CHECK_RETURN_FALSE(x.size()>0);
        GADGET_CHECK_RETURN_FALSE(y.size()>0);
        GADGET_CHECK_RETURN_FALSE(x.size() == y.size());

        T minX = xlim[0];
        T maxX = xlim[1];
        T minY = ylim[0];
        T maxY = ylim[1];

        plsdev("mem");

        hoNDArray<unsigned char> im;
        im.create(3, xsize, ysize);
        Gadgetron::clear(im);

        plsmem(im.get_size(1), im.get_size(2), im.begin());

        plinit();
        plfont(2);

        pladv(0);

        if (legend.size() == x.size())
        {
            plvpor(0.11, 0.75, 0.1, 0.9);
        }
        else
        {
            plvpor(0.15, 0.85, 0.1, 0.9);
        }

        T spaceX = 0.01*(maxX - minX);
        T spaceY = 0.05*(maxY - minY);

        plwind(minX - spaceX, maxX + spaceX, minY - spaceY, maxY + spaceY);

        plcol0(15);
        plbox("bgcnst", 0.0, 0, "bgcnstv", 0.0, 0);

        // int mark[2], space[2];

        //mark[0] = 4000;
        //space[0] = 2500;
        //plstyl(1, mark, space);

        size_t num = x.size();

        size_t n;

        hoNDArray<double> xd, yd;

        // draw lines
        for (n = 0; n < num; n++)
        {
            size_t N = y[n].get_size(0);

            xd.copyFrom(x[n]);
            yd.copyFrom(y[n]);

            if (drawLine)
            {
                int c;
                getPlotColor(n, c);
                plcol0(c);
                pllsty(n % 8 + 1);
                plline(N, xd.begin(), yd.begin());
            }

            std::string gly;
            if(symbols.size()>n)
            {
                gly = symbols[n];
            }
            else
                getPlotGlyph(n, gly);

            plstring(N, xd.begin(), yd.begin(), gly.c_str());
        }

        plcol0(15);
        plmtex("b", 3.2, 0.5, 0.5, xlabel.c_str());
        plmtex("t", 2.0, 0.5, 0.5, title.c_str());
        plmtex("l", 5.0, 0.5, 0.5, ylabel.c_str());

        // draw the legend
        if (legend.size() == x.size())
        {
            std::vector<PLINT> opt_array(num), text_colors(num), line_colors(num), line_styles(num), symbol_numbers(num), symbol_colors(num);
            std::vector<PLFLT> symbol_scales(num), line_widths(num), box_scales(num, 1);

            std::vector<std::string> glyphs(num);
            std::vector<const char*> symbols(num);
            PLFLT legend_width, legend_height;

            std::vector<const char*> legend_text(num);

            for (n = 0; n < num; n++)
            {
                int c;
                getPlotColor(n, c);
                getPlotGlyph(n, glyphs[n]);

                opt_array[n] = PL_LEGEND_SYMBOL | PL_LEGEND_LINE;
                text_colors[n] = 15;
                line_colors[n] = c;
                line_styles[n] = (n%8+1);
                line_widths[n] = 0.2;
                symbol_colors[n] = c;
                symbol_scales[n] = 0.75;
                symbol_numbers[n] = 1;
                symbols[n] = glyphs[n].c_str();
                legend_text[n] = legend[n].c_str();
            }

            pllegend(&legend_width, 
                    &legend_height,
                    PL_LEGEND_BACKGROUND,
                    PL_POSITION_OUTSIDE | PL_POSITION_RIGHT | PL_POSITION_TOP,
                    0.02,                                       // x
                    0.0,                                        // y
                    0.05,                                       // plot_width
                    0,                                          // bg_color
                    15,                                         // bb_color
                    1,                                          // bb_style
                    0,                                          // nrow
                    0,                                          // ncolumn
                    num,                                        // nlegend
                    &opt_array[0], 
                    0.05,                                       // text_offset
                    0.35,                                       // text_scale
                    1.0,                                        // text_spacing
                    0.5,                                        // text_justification
                    &text_colors[0], 
                    (const char **)(&legend_text[0]), 
                    NULL,                                       // box_colors
                    NULL,                                       // box_patterns
                    &box_scales[0],                             // box_scales
                    NULL,                                       // box_line_widths
                    &line_colors[0], 
                    &line_styles[0], 
                    &line_widths[0],
                    &symbol_colors[0], 
                    &symbol_scales[0], 
                    &symbol_numbers[0], 
                    (const char **)(&symbols[0])
                    );
        }

        plend();

        outputPlotIm(im, trueColor, plotIm);
    }
    catch (...)
    {
        GERROR_STREAM("Errors happened in plotCurves(xlim, ylim) ... ");
        return false;
    }

    return true;
}
void GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx,
        GrDrawContext* dc,
        GrPipelineBuilder* pipelineBuilder,
        GrColor color,
        const SkMatrix& viewMatrix,
        const SkSurfaceProps& props,
        SkScalar x, SkScalar y,
        const SkIRect& clipBounds,
        GrTextContext* fallbackTextContext,
        const SkPaint& originalSkPaint) const {
    SkASSERT(fInstanceData);
    SkASSERT(dc->accessRenderTarget()->isStencilBufferMultisampled() || !fFont.isAntiAlias());

    if (fInstanceData->count()) {
        pipelineBuilder->setState(GrPipelineBuilder::kHWAntialias_Flag, fFont.isAntiAlias());

        GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
                                     kZero_StencilOp,
                                     kKeep_StencilOp,
                                     kNotEqual_StencilFunc,
                                     0xffff,
                                     0x0000,
                                     0xffff);

        *pipelineBuilder->stencil() = kStencilPass;

        SkAutoTUnref<GrPathRange> glyphs(this->createGlyphs(ctx));
        if (fLastDrawnGlyphsID != glyphs->getUniqueID()) {
            // Either this is the first draw or the glyphs object was purged since last draw.
            glyphs->loadPathsIfNeeded(fInstanceData->indices(), fInstanceData->count());
            fLastDrawnGlyphsID = glyphs->getUniqueID();
        }

        // Don't compute a bounding box. For dst copy texture, we'll opt instead for it to just copy
        // the entire dst. Realistically this is a moot point, because any context that supports
        // NV_path_rendering will also support NV_blend_equation_advanced.
        // For clipping we'll just skip any optimizations based on the bounds. This does, however,
        // hurt batching.
        SkRect bounds = SkRect::MakeIWH(pipelineBuilder->getRenderTarget()->width(),
                                        pipelineBuilder->getRenderTarget()->height());

        SkAutoTUnref<GrDrawPathBatchBase> batch(
            GrDrawPathRangeBatch::Create(viewMatrix, fTextRatio, fTextInverseRatio * x,
                                         fTextInverseRatio * y, color,
                                         GrPathRendering::kWinding_FillType, glyphs, fInstanceData,
                                         bounds));

        dc->drawPathBatch(*pipelineBuilder, batch);
    }

    if (fFallbackTextBlob) {
        SkPaint fallbackSkPaint(originalSkPaint);
        fStroke.applyToPaint(&fallbackSkPaint);
        if (!fStroke.isFillStyle()) {
            fallbackSkPaint.setStrokeWidth(fStroke.getWidth() * fTextRatio);
        }

        fallbackTextContext->drawTextBlob(ctx, dc, pipelineBuilder->clip(), fallbackSkPaint,
                                          viewMatrix, props, fFallbackTextBlob, x, y, nullptr,
                                          clipBounds);
    }
}
bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
{
    bool haveGlyphs = false;

    Vector<CGGlyph, 512> glyphs(bufferLength);
    if (!shouldUseCoreText(buffer, bufferLength, fontData)) {
        // We pass in either 256 or 512 UTF-16 characters: 256 for U+FFFF and less, 512 (double character surrogates)
        // for U+10000 and above. It is indeed possible to get back 512 glyphs back from the API, so the glyph buffer
        // we pass in must be 512. If we get back more than 256 glyphs though we'll ignore all the ones after 256,
        // this should not happen as the only time we pass in 512 characters is when they are surrogates.
        CGFontGetGlyphsForUnichars(fontData->platformData().cgFont(), buffer, glyphs.data(), bufferLength);
        for (unsigned i = 0; i < length; ++i) {
            if (!glyphs[i])
                setGlyphDataForIndex(offset + i, 0, 0);
            else {
                setGlyphDataForIndex(offset + i, glyphs[i], fontData);
                haveGlyphs = true;
            }
        }
    } else if (!fontData->platformData().isCompositeFontReference() && ((fontData->platformData().widthVariant() == RegularWidth) ? wkGetVerticalGlyphsForCharacters(fontData->platformData().ctFont(), buffer, glyphs.data(), bufferLength)
               : CTFontGetGlyphsForCharacters(fontData->platformData().ctFont(), buffer, glyphs.data(), bufferLength))) {
        // When buffer consists of surrogate pairs, wkGetVerticalGlyphsForCharacters and CTFontGetGlyphsForCharacters
        // place the glyphs at indices corresponding to the first character of each pair.
        unsigned glyphStep = bufferLength / length;
        for (unsigned i = 0; i < length; ++i) {
            if (!glyphs[i * glyphStep])
                setGlyphDataForIndex(offset + i, 0, 0);
            else {
                setGlyphDataForIndex(offset + i, glyphs[i * glyphStep], fontData);
                haveGlyphs = true;
            }
        }
    } else {
        // We ask CoreText for possible vertical variant glyphs
        RetainPtr<CFStringRef> string = adoptCF(CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, buffer, bufferLength, kCFAllocatorNull));
        RetainPtr<CFAttributedStringRef> attributedString = adoptCF(CFAttributedStringCreate(kCFAllocatorDefault, string.get(), fontData->getCFStringAttributes(0, fontData->hasVerticalGlyphs() ? Vertical : Horizontal)));
        RetainPtr<CTLineRef> line = adoptCF(CTLineCreateWithAttributedString(attributedString.get()));

        CFArrayRef runArray = CTLineGetGlyphRuns(line.get());
        CFIndex runCount = CFArrayGetCount(runArray);

        // Initialize glyph entries
        for (unsigned index = 0; index < length; ++index)
            setGlyphDataForIndex(offset + index, 0, 0);

        Vector<CGGlyph, 512> glyphVector;
        Vector<CFIndex, 512> indexVector;
        bool done = false;

        // For the CGFont comparison in the loop, use the CGFont that Core Text assigns to the CTFont. This may
        // be non-CFEqual to fontData->platformData().cgFont().
        RetainPtr<CGFontRef> cgFont = adoptCF(CTFontCopyGraphicsFont(fontData->platformData().ctFont(), 0));

        for (CFIndex r = 0; r < runCount && !done ; ++r) {
            // CTLine could map characters over multiple fonts using its own font fallback list.
            // We need to pick runs that use the exact font we need, i.e., fontData->platformData().ctFont().
            CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r));
            ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID());

            CFDictionaryRef attributes = CTRunGetAttributes(ctRun);
            CTFontRef runFont = static_cast<CTFontRef>(CFDictionaryGetValue(attributes, kCTFontAttributeName));
            RetainPtr<CGFontRef> runCGFont = adoptCF(CTFontCopyGraphicsFont(runFont, 0));
            // Use CGFont here as CFEqual for CTFont counts all attributes for font.
            bool gotBaseFont = CFEqual(cgFont.get(), runCGFont.get());
            if (gotBaseFont || fontData->platformData().isCompositeFontReference()) {
                // This run uses the font we want. Extract glyphs.
                CFIndex glyphCount = CTRunGetGlyphCount(ctRun);
                const CGGlyph* glyphs = CTRunGetGlyphsPtr(ctRun);
                if (!glyphs) {
                    glyphVector.resize(glyphCount);
                    CTRunGetGlyphs(ctRun, CFRangeMake(0, 0), glyphVector.data());
                    glyphs = glyphVector.data();
                }
                const CFIndex* stringIndices = CTRunGetStringIndicesPtr(ctRun);
                if (!stringIndices) {
                    indexVector.resize(glyphCount);
                    CTRunGetStringIndices(ctRun, CFRangeMake(0, 0), indexVector.data());
                    stringIndices = indexVector.data();
                }

                if (gotBaseFont) {
                    for (CFIndex i = 0; i < glyphCount; ++i) {
                        if (stringIndices[i] >= static_cast<CFIndex>(length)) {
                            done = true;
                            break;
                        }
                        if (glyphs[i]) {
                            setGlyphDataForIndex(offset + stringIndices[i], glyphs[i], fontData);
                            haveGlyphs = true;
                        }
                    }
#if !PLATFORM(IOS)
                } else {
                    const SimpleFontData* runSimple = fontData->getCompositeFontReferenceFontData((NSFont *)runFont);
                    if (runSimple) {
                        for (CFIndex i = 0; i < glyphCount; ++i) {
                            if (stringIndices[i] >= static_cast<CFIndex>(length)) {
                                done = true;
                                break;
                            }
                            if (glyphs[i]) {
                                setGlyphDataForIndex(offset + stringIndices[i], glyphs[i], runSimple);
                                haveGlyphs = true;
                            }
                        }
                    }
#endif // !PLATFORM(IOS)
                }
            }
        }
    }

    return haveGlyphs;
}
bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
{
    bool haveGlyphs = false;

#ifndef BUILDING_ON_TIGER
    if (fontData->orientation() == Horizontal || fontData->isBrokenIdeographFont()) {
        Vector<CGGlyph, 512> glyphs(bufferLength);
        wkGetGlyphsForCharacters(fontData->platformData().cgFont(), buffer, glyphs.data(), bufferLength);
        for (unsigned i = 0; i < length; ++i) {
            if (!glyphs[i])
                setGlyphDataForIndex(offset + i, 0, 0);
            else {
                setGlyphDataForIndex(offset + i, glyphs[i], fontData);
                haveGlyphs = true;
            }
        }
    } else {
        // We ask CoreText for possible vertical variant glyphs
        RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, buffer, bufferLength, kCFAllocatorNull));
        RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(kCFAllocatorDefault, string.get(), fontData->getCFStringAttributes(0)));
        RetainPtr<CTLineRef> line(AdoptCF, CTLineCreateWithAttributedString(attributedString.get()));

        CFArrayRef runArray = CTLineGetGlyphRuns(line.get());
        CFIndex runCount = CFArrayGetCount(runArray);

        // Initialize glyph entries
        for (unsigned index = 0; index < length; ++index)
            setGlyphDataForIndex(offset + index, 0, 0);

        Vector<CGGlyph, 512> glyphVector;
        Vector<CFIndex, 512> indexVector;
        bool done = false;
        for (CFIndex r = 0; r < runCount && !done ; ++r) {
            // CTLine could map characters over multiple fonts using its own font fallback list.
            // We need to pick runs that use the exact font we need, i.e., fontData->platformData().ctFont().
            CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r));
            ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID());

            CFDictionaryRef attributes = CTRunGetAttributes(ctRun);
            CTFontRef runFont = static_cast<CTFontRef>(CFDictionaryGetValue(attributes, kCTFontAttributeName));
            RetainPtr<CGFontRef> runCGFont(AdoptCF, CTFontCopyGraphicsFont(runFont, 0));
            // Use CGFont here as CFEqual for CTFont counts all attributes for font.
            if (CFEqual(fontData->platformData().cgFont(), runCGFont.get())) {
                // This run uses the font we want. Extract glyphs.
                CFIndex glyphCount = CTRunGetGlyphCount(ctRun);
                const CGGlyph* glyphs = CTRunGetGlyphsPtr(ctRun);
                if (!glyphs) {
                    glyphVector.resize(glyphCount);
                    CTRunGetGlyphs(ctRun, CFRangeMake(0, 0), glyphVector.data());
                    glyphs = glyphVector.data();
                }
                const CFIndex* stringIndices = CTRunGetStringIndicesPtr(ctRun);
                if (!stringIndices) {
                    indexVector.resize(glyphCount);
                    CTRunGetStringIndices(ctRun, CFRangeMake(0, 0), indexVector.data());
                    stringIndices = indexVector.data();
                }

                for (CFIndex i = 0; i < glyphCount; ++i) {
                    if (stringIndices[i] >= static_cast<CFIndex>(length)) {
                        done = true;
                        break;
                    }
                    if (glyphs[i]) {
                        setGlyphDataForIndex(offset + stringIndices[i], glyphs[i], fontData);
                        haveGlyphs = true;
                    }
                }
            }
        }
    }
#else
    // Use an array of long so we get good enough alignment.
    long glyphVector[(GLYPH_VECTOR_SIZE + sizeof(long) - 1) / sizeof(long)];
    
    OSStatus status = wkInitializeGlyphVector(GlyphPage::size, &glyphVector);
    if (status != noErr)
        // This should never happen, perhaps indicates a bad font!  If it does the
        // font substitution code will find an alternate font.
        return false;

    wkConvertCharToGlyphs(fontData->m_styleGroup, buffer, bufferLength, &glyphVector);

    unsigned numGlyphs = wkGetGlyphVectorNumGlyphs(&glyphVector);
    if (numGlyphs != length) {
        // This should never happen, perhaps indicates a bad font?
        // If it does happen, the font substitution code will find an alternate font.
        wkClearGlyphVector(&glyphVector);
        return false;
    }

    ATSLayoutRecord* glyphRecord = (ATSLayoutRecord*)wkGetGlyphVectorFirstRecord(glyphVector);
    for (unsigned i = 0; i < length; i++) {
        Glyph glyph = glyphRecord->glyphID;
        if (!glyph)
            setGlyphDataForIndex(offset + i, 0, 0);
        else {
            setGlyphDataForIndex(offset + i, glyph, fontData);
            haveGlyphs = true;
        }
        glyphRecord = (ATSLayoutRecord *)((char *)glyphRecord + wkGetGlyphVectorRecordSize(glyphVector));
    }
    wkClearGlyphVector(&glyphVector);
#endif

    return haveGlyphs;
}
bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
{
    bool haveGlyphs = false;

    if (!shouldUseCoreText(buffer, bufferLength, fontData)) {
        Vector<CGGlyph, 512> glyphs(bufferLength);

        CMFontGetGlyphsForUnichars(fontData->platformData().cgFont(), buffer, glyphs.data(), bufferLength);
//        wkGetGlyphsForCharacters(fontData->platformData().cgFont(), buffer, glyphs.data(), bufferLength);

        for (unsigned i = 0; i < length; ++i) {
            if (!glyphs[i])
                setGlyphDataForIndex(offset + i, 0, 0);
            else {
                setGlyphDataForIndex(offset + i, glyphs[i], fontData);
                haveGlyphs = true;
            }
        }
    } else {
        // We ask CoreText for possible vertical variant glyphs
        RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, buffer, bufferLength, kCFAllocatorNull));
        RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(kCFAllocatorDefault, string.get(), fontData->getCFStringAttributes(0, fontData->hasVerticalGlyphs() ? Vertical : Horizontal)));
        RetainPtr<CTLineRef> line(AdoptCF, CTLineCreateWithAttributedString(attributedString.get()));

        CFArrayRef runArray = CTLineGetGlyphRuns(line.get());
        CFIndex runCount = CFArrayGetCount(runArray);

        // Initialize glyph entries
        for (unsigned index = 0; index < length; ++index)
            setGlyphDataForIndex(offset + index, 0, 0);

        Vector<CGGlyph, 512> glyphVector;
        Vector<CFIndex, 512> indexVector;
        bool done = false;

        // For the CGFont comparison in the loop, use the CGFont that Core Text assigns to the CTFont. This may
        // be non-CFEqual to fontData->platformData().cgFont().
        RetainPtr<CGFontRef> cgFont(AdoptCF, CTFontCopyGraphicsFont(fontData->platformData().ctFont(), 0));

        for (CFIndex r = 0; r < runCount && !done ; ++r) {
            // CTLine could map characters over multiple fonts using its own font fallback list.
            // We need to pick runs that use the exact font we need, i.e., fontData->platformData().ctFont().
            CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r));
            ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID());

            CFDictionaryRef attributes = CTRunGetAttributes(ctRun);
            CTFontRef runFont = static_cast<CTFontRef>(CFDictionaryGetValue(attributes, kCTFontAttributeName));
            RetainPtr<CGFontRef> runCGFont(AdoptCF, CTFontCopyGraphicsFont(runFont, 0));
            // Use CGFont here as CFEqual for CTFont counts all attributes for font.
            if (CFEqual(cgFont.get(), runCGFont.get())) {
                // This run uses the font we want. Extract glyphs.
                CFIndex glyphCount = CTRunGetGlyphCount(ctRun);
                const CGGlyph* glyphs = CTRunGetGlyphsPtr(ctRun);
                if (!glyphs) {
                    glyphVector.resize(glyphCount);
                    CTRunGetGlyphs(ctRun, CFRangeMake(0, 0), glyphVector.data());
                    glyphs = glyphVector.data();
                }
                const CFIndex* stringIndices = CTRunGetStringIndicesPtr(ctRun);
                if (!stringIndices) {
                    indexVector.resize(glyphCount);
                    CTRunGetStringIndices(ctRun, CFRangeMake(0, 0), indexVector.data());
                    stringIndices = indexVector.data();
                }

                for (CFIndex i = 0; i < glyphCount; ++i) {
                    if (stringIndices[i] >= static_cast<CFIndex>(length)) {
                        done = true;
                        break;
                    }
                    if (glyphs[i]) {
                        setGlyphDataForIndex(offset + stringIndices[i], glyphs[i], fontData);
                        haveGlyphs = true;
                    }
                }
            }
        }
    }

    return haveGlyphs;
}
Exemple #27
0
void tool_fontextract(const vdfastvector<const char *>& args, const vdfastvector<const char *>& switches) {
	if (args.size() < 6)
		help_fontextract();

	printf("Asuka: Extracting font: %s -> %s.\n", args[0], args[4]);
	
	int startChar;
	int endChar;

	if (1 != sscanf(args[2], "%d", &startChar) || 1 != sscanf(args[3], "%d", &endChar))
		help_fontextract();

	if (startChar < 0 || endChar > 0xFFFF || endChar <= startChar) {
		printf("Asuka: Invalid character range %d-%d\n", startChar, endChar);
		exit(10);
	}

	int fontsAdded = AddFontResourceEx(args[0], FR_NOT_ENUM | FR_PRIVATE, 0);

	if (!fontsAdded) {
		printf("Asuka: Unable to load font file: %s\n", args[0]);
		exit(10);
	}

	HFONT hfont = CreateFontA(10, 0, 0, 0, 0, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, args[1]);
	if (!hfont) {
		printf("Asuka: Unable to instantiate font: %s\n", args[1]);
		exit(10);
	}

	HDC hdc = CreateDC("DISPLAY", 0, 0, 0);
	HGDIOBJ hfontOld = SelectObject(hdc, hfont);
	MAT2 m = { {0,1},{0,0},{0,0},{0,1} };

	union {
		OUTLINETEXTMETRICW m;
		char buf[2048];
	} metrics;

	if (!GetOutlineTextMetricsW(hdc, sizeof metrics, &metrics.m)) {
		printf("Asuka: Unable to retrieve outline text metrics.\n");
		exit(10);
	}

	SelectObject(hdc, hfontOld);
	DeleteObject(hfont);
	
	hfont = CreateFontA(metrics.m.otmEMSquare, 0, 0, 0, 0, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, args[1]);
	if (!hfont) {
		printf("Asuka: Unable to instantiate font: %s\n", args[1]);
		exit(10);
	}

	hfontOld = SelectObject(hdc, hfont);

	if (!GetOutlineTextMetricsW(hdc, sizeof metrics, &metrics.m)) {
		printf("Asuka: Unable to retrieve outline text metrics.\n");
		exit(10);
	}

	FILE *f = fopen(args[4], "w");
	if (!f) {
		printf("Asuka: Unable to open output file: %s\n", args[4]);
		exit(10);
	}

	std::vector<GlyphInfo> glyphs(endChar - startChar + 1);

	sint32 minX = 0x7FFFFFFF;
	sint32 minY = 0x7FFFFFFF;
	sint32 maxX = -0x7FFFFFFF - 1;
	sint32 maxY = -0x7FFFFFFF - 1;

	vdfastvector<sint32> points;
	vdfastvector<uint8> commands;

	for(int c=startChar; c<endChar; ++c) {
		GlyphInfo& info = glyphs[c - startChar];
		info.mPointStart = points.size() >> 1;
		info.mCommandStart = commands.size();

		GetCharABCWidthsFloatW(hdc, c, c, &info.mWidths);

		// encode glyph outline
		GLYPHMETRICS gm;

		if (GDI_ERROR == GetGlyphOutlineW(hdc, c, GGO_METRICS, &gm, 0, NULL, &m)) {
			printf("Asuka: Unable to obtain glyph metrics for char %d.\n", c);
			exit(20);
		}

		DWORD dwBytes = GetGlyphOutlineW(hdc, c, GGO_NATIVE | GGO_UNHINTED, &gm, 0, NULL, &m);
		if (dwBytes == 0xFFFFFFFF) {
			printf("Asuka: Unable to obtain glyph outline for char %d.\n", c);
			exit(20);
		}

		// GetGlyphOutline() doesn't like providing results for spaces.
		if (gm.gmBlackBoxX <= 0 || gm.gmBlackBoxY <= 0)
			continue;

		void *buf = malloc(dwBytes);
		GetGlyphOutlineW(hdc, c, GGO_NATIVE | GGO_UNHINTED, &gm, dwBytes, buf, &m);

		void *limit = (char *)buf + dwBytes;
		TTPOLYGONHEADER *pHdr = (TTPOLYGONHEADER *)buf;

		sint32 lastCode = 0;

		while(pHdr != limit) {
			VDASSERT(pHdr->dwType == TT_POLYGON_TYPE);

			sint32 x = *(const sint32 *)&pHdr->pfxStart.x;
			sint32 y = *(const sint32 *)&pHdr->pfxStart.y;

			if (minX > x)
				minX = x;
			if (minY > y)
				minY = y;
			if (maxX < x)
				maxX = x;
			if (maxY < y)
				maxY = y;

			points.push_back(x);
			points.push_back(y);

			TTPOLYCURVE *pCurve = (TTPOLYCURVE *)(pHdr + 1);
			TTPOLYCURVE *pCurveEnd = (TTPOLYCURVE *)((char *)pHdr + pHdr->cb);

			while(pCurve != pCurveEnd) {
				VDASSERT(pCurve->wType == TT_PRIM_QSPLINE || pCurve->wType == TT_PRIM_LINE);

				POINTFX *ppfx = pCurve->apfx;

				for(int i=0; i<pCurve->cpfx; ++i) {
					sint32 x = *(const sint32 *)&ppfx->x;
					sint32 y = *(const sint32 *)&ppfx->y;

					if (minX > x)
						minX = x;
					if (minY > y)
						minY = y;
					if (maxX < x)
						maxX = x;
					if (maxY < y)
						maxY = y;

					points.push_back(x);
					points.push_back(y);
					++ppfx;
				}

				if (pCurve->wType == TT_PRIM_LINE) {
					if ((lastCode & 3) != 2) {
						if (lastCode)
							commands.push_back(lastCode);

						lastCode = 2 - 4;
					}

					for(int i=0; i<pCurve->cpfx; ++i) {
						if (lastCode >= 0x7C) {
							commands.push_back(lastCode);
							lastCode = 2 - 4;
						}

						lastCode += 4;
					}
				} else {
					VDASSERT(pCurve->wType == TT_PRIM_QSPLINE);
					VDASSERT(!(pCurve->cpfx % 2));

					if ((lastCode & 3) != 3) {
						if (lastCode)
							commands.push_back(lastCode);

						lastCode = 3 - 4;
					}

					for(int i=0; i<pCurve->cpfx; i+=2) {
						if (lastCode >= 0x7C) {
							commands.push_back(lastCode);
							lastCode = 3 - 4;
						}

						lastCode += 4;
					}
				}

				pCurve = (TTPOLYCURVE *)ppfx;
			}

			if (lastCode) {
				commands.push_back(lastCode | 0x80);
				lastCode = 0;
			}

			vdptrstep(pHdr, pHdr->cb);
		}

		free(buf);
	}

	GlyphInfo& lastInfo = glyphs.back();

	lastInfo.mPointStart = points.size() >> 1;
	lastInfo.mCommandStart = commands.size();

	// write points
	fprintf(f, "// Created by Asuka from %s.  DO NOT EDIT!\n\n", VDFileSplitPath(args[0]));
	fprintf(f, "const uint16 %s_FontPointArray[]={\n", args[5]);

	float scaleX = (maxX > minX) ? 1.0f / (maxX - minX) : 0.0f;
	float scaleY = (maxY > minY) ? 1.0f / (maxY - minY) : 0.0f;

	int pointElementCount = points.size();

	for(int i=0; i<pointElementCount; i+=2) {
		uint8 x = VDClampedRoundFixedToUint8Fast((float)(points[i+0] - minX) * scaleX);
		uint8 y = VDClampedRoundFixedToUint8Fast((float)(points[i+1] - minY) * scaleY);
		uint16 pt = ((uint16)y << 8) + x;

		fprintf(f, "0x%04x,", pt);

		if ((i & 30) == 30)
			putc('\n', f);
	}

	if (pointElementCount & 30)
		putc('\n', f);

	fprintf(f, "};\n\n");

	// write commands
	fprintf(f, "const uint8 %s_FontCommandArray[]={\n", args[5]);

	int commandElementCount = commands.size();

	for(int i=0; i<commandElementCount; ++i) {
		fprintf(f, "0x%02x,", commands[i]);

		if ((i & 15) == 15)
			putc('\n', f);
	}

	if (commandElementCount & 15)
		putc('\n', f);

	fprintf(f, "};\n\n");

	// glyph data structures
	fprintf(f, "const VDOutlineFontGlyphInfo %s_FontGlyphArray[]={\n", args[5]);
	for(int i=startChar; i<=endChar; ++i) {
		const GlyphInfo& info = glyphs[i - startChar];
		fprintf(f, "{ %d, %d, %d, %d, %d },\n", info.mPointStart, info.mCommandStart, VDRoundToInt(info.mWidths.abcfA), VDRoundToInt(info.mWidths.abcfB), VDRoundToInt(info.mWidths.abcfC));
	}
	fprintf(f, "};\n\n");

	// top-level data structure
	fprintf(f, "const VDOutlineFontInfo %s_FontInfo={\n", args[5]);
	fprintf(f, "\t%s_FontPointArray,\n", args[5]);
	fprintf(f, "\t%s_FontCommandArray,\n", args[5]);
	fprintf(f, "\t%s_FontGlyphArray,\n", args[5]);
	fprintf(f, "\t%d, %d,\n", startChar, endChar);
	fprintf(f, "\t%d, %d, %d, %d,\t// bounds (16:16)\n", minX, minY, maxX, maxY);
	fprintf(f, "\t%d,\t// em square\n", metrics.m.otmEMSquare);
	fprintf(f, "\t%d,\t// ascent\n", metrics.m.otmAscent);
	fprintf(f, "\t%d,\t// descent\n", metrics.m.otmDescent);
	fprintf(f, "\t%d,\t// line gap\n", metrics.m.otmLineGap);
	fprintf(f, "};\n");

	printf("Asuka: %d point bytes, %d command bytes, %d glyph info bytes.\n", (int)points.size(), (int)commands.size(), (endChar - startChar + 1) * 10);

	SelectObject(hdc, hfontOld);
	DeleteDC(hdc);

	DeleteObject(hfont);
}
void GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx,
                                                 GrDrawContext* drawContext,
                                                 const GrPaint& grPaint,
                                                 const GrClip& clip,
                                                 const SkMatrix& viewMatrix,
                                                 const SkSurfaceProps& props,
                                                 SkScalar x, SkScalar y,
                                                 const SkIRect& clipBounds,
                                                 GrAtlasTextContext* fallbackTextContext,
                                                 const SkPaint& originalSkPaint) const {
    SkASSERT(fInstanceData);
    SkASSERT(drawContext->isStencilBufferMultisampled() || !grPaint.isAntiAlias());

    if (fInstanceData->count()) {
        static constexpr GrUserStencilSettings kCoverPass(
            GrUserStencilSettings::StaticInit<
                0x0000,
                GrUserStencilTest::kNotEqual, // Stencil pass accounts for clip.
                0xffff,
                GrUserStencilOp::kZero,
                GrUserStencilOp::kKeep,
                0xffff>()
        );

        SkAutoTUnref<GrPathRange> glyphs(this->createGlyphs(ctx));
        if (fLastDrawnGlyphsID != glyphs->uniqueID()) {
            // Either this is the first draw or the glyphs object was purged since last draw.
            glyphs->loadPathsIfNeeded(fInstanceData->indices(), fInstanceData->count());
            fLastDrawnGlyphsID = glyphs->uniqueID();
        }

        // Don't compute a bounding box. For dst copy texture, we'll opt instead for it to just copy
        // the entire dst. Realistically this is a moot point, because any context that supports
        // NV_path_rendering will also support NV_blend_equation_advanced.
        // For clipping we'll just skip any optimizations based on the bounds. This does, however,
        // hurt batching.
        const SkRect bounds = SkRect::MakeIWH(drawContext->width(), drawContext->height());

        SkAutoTUnref<GrDrawBatch> batch(
            GrDrawPathRangeBatch::Create(viewMatrix, fTextRatio, fTextInverseRatio * x,
                                         fTextInverseRatio * y, grPaint.getColor(),
                                         GrPathRendering::kWinding_FillType, glyphs, fInstanceData,
                                         bounds));

        GrPipelineBuilder pipelineBuilder(grPaint);
        pipelineBuilder.setState(GrPipelineBuilder::kHWAntialias_Flag, grPaint.isAntiAlias());
        pipelineBuilder.setUserStencil(&kCoverPass);

        drawContext->drawBatch(pipelineBuilder, clip, batch);
    }

    if (fFallbackTextBlob) {
        SkPaint fallbackSkPaint(originalSkPaint);
        fStyle.strokeRec().applyToPaint(&fallbackSkPaint);
        if (!fStyle.isSimpleFill()) {
            fallbackSkPaint.setStrokeWidth(fStyle.strokeRec().getWidth() * fTextRatio);
        }

        fallbackTextContext->drawTextBlob(ctx, drawContext, clip, fallbackSkPaint, viewMatrix,
                                          props, fFallbackTextBlob.get(), x, y, nullptr,
                                          clipBounds);
    }
}
TemporaryRef<Path>
ScaledFontBase::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget)
{
#ifdef USE_SKIA
  if (aTarget->GetType() == BACKEND_SKIA) {
    SkPaint paint;
    paint.setTypeface(GetSkTypeface());
    paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
    paint.setTextSize(SkFloatToScalar(mSize));

    std::vector<uint16_t> indices;
    std::vector<SkPoint> offsets;
    indices.resize(aBuffer.mNumGlyphs);
    offsets.resize(aBuffer.mNumGlyphs);

    for (unsigned int i = 0; i < aBuffer.mNumGlyphs; i++) {
      indices[i] = aBuffer.mGlyphs[i].mIndex;
      offsets[i].fX = SkFloatToScalar(aBuffer.mGlyphs[i].mPosition.x);
      offsets[i].fY = SkFloatToScalar(aBuffer.mGlyphs[i].mPosition.y);
    }

    SkPath path;
    paint.getPosTextPath(&indices.front(), aBuffer.mNumGlyphs*2, &offsets.front(), &path);
    return new PathSkia(path, FILL_WINDING);
  }
#endif
#ifdef USE_CAIRO
  if (aTarget->GetType() == BACKEND_CAIRO) {
    MOZ_ASSERT(mScaledFont);

    DrawTarget *dt = const_cast<DrawTarget*>(aTarget);
    cairo_t *ctx = static_cast<cairo_t*>(dt->GetNativeSurface(NATIVE_SURFACE_CAIRO_CONTEXT));

    bool isNewContext = !ctx;
    if (!ctx) {
      ctx = cairo_create(DrawTargetCairo::GetDummySurface());
      cairo_matrix_t mat;
      GfxMatrixToCairoMatrix(aTarget->GetTransform(), mat);
      cairo_set_matrix(ctx, &mat);
    }

    cairo_set_scaled_font(ctx, mScaledFont);

    // Convert our GlyphBuffer into an array of Cairo glyphs.
    std::vector<cairo_glyph_t> glyphs(aBuffer.mNumGlyphs);
    for (uint32_t i = 0; i < aBuffer.mNumGlyphs; ++i) {
      glyphs[i].index = aBuffer.mGlyphs[i].mIndex;
      glyphs[i].x = aBuffer.mGlyphs[i].mPosition.x;
      glyphs[i].y = aBuffer.mGlyphs[i].mPosition.y;
    }

    cairo_glyph_path(ctx, &glyphs[0], aBuffer.mNumGlyphs);

    RefPtr<PathCairo> newPath = new PathCairo(ctx);
    if (isNewContext) {
      cairo_destroy(ctx);
    }

    return newPath;
  }
#endif
  return nullptr;
}
/*************************************************************************
SAX2 Handler methods
*************************************************************************/
void Font_xmlHandler::elementStart(const String& element, const XMLAttributes& attributes)
{
    // handle a Mapping element
    if (element == MappingElement)
    {
        if (!d_font->d_freetype)
        {
            String	image_name(attributes.getValueAsString(MappingImageAttribute));
            utf32 codepoint = (utf32)attributes.getValueAsInteger(MappingCodepointAttribute);
            int horzAdvance = attributes.getValueAsInteger(MappingHorzAdvanceAttribute, -1);

            Font::glyphDat	mapDat;
            mapDat.d_image = &d_font->d_glyph_images->getImage(image_name);

            // calculate advance width if it was not specified
            if (horzAdvance == AutoGenerateHorzAdvance)
            {
                horzAdvance = (int)(mapDat.d_image->getWidth() + mapDat.d_image->getOffsetX());
            }

            mapDat.d_horz_advance_unscaled = horzAdvance;
            mapDat.d_horz_advance = (uint)(((float)horzAdvance) * (d_font->d_autoScale ? d_font->d_horzScaling : 1.0f));
            d_font->d_cp_map[codepoint] = mapDat;
        }
        else
        {
            Logger::getSingleton().logEvent((utf8*)"Mapping element encountered.  This element is invalid for dynamic fonts.", Informative);
        }
    }
    // handle root Font element
    else if (element == FontElement)
    {
        // get name of font we are creating
        String font_name(attributes.getValueAsString(FontNameAttribute));

        // get filename for the font
        String filename(attributes.getValueAsString(FontFilenameAttribute));
        // get resource group for font file.
        String resourceGroup(attributes.getValueAsString(FontResourceGroupAttribute));

        Logger::getSingleton().logEvent("Started creation of Font '" + font_name + "' via XML file.", Informative);

        //
        // load auto-scaling configuration
        //
        float hres, vres;
        bool auto_scale;

        // get native horizontal resolution
        hres = (float)attributes.getValueAsInteger(FontNativeHorzResAttribute, 640);

        // get native vertical resolution
        vres = (float)attributes.getValueAsInteger(FontNativeVertResAttribute, 480);

        // get auto-scaling setting
        auto_scale = attributes.getValueAsBool(FontAutoScaledAttribute, false);

        //
        // get type of font
        //
        String	font_type(attributes.getValueAsString(FontTypeAttribute));

        // dynamic (ttf) font
        if (font_type == FontTypeDynamic)
        {
            // get size of font
            uint size = (uint)attributes.getValueAsInteger(FontSizeAttribute, 12);

            // extract codepoint range
            utf32 first_codepoint = (utf32)attributes.getValueAsInteger(FontFirstCodepointAttribute, 32);
            utf32 last_codepoint = (utf32)attributes.getValueAsInteger(FontLastCodepointAttribute, 127);

            // build string containing the required code-points.
            for (; first_codepoint <= last_codepoint; ++first_codepoint)
            {
                d_glyphSet += first_codepoint;
            }

            uint flags = attributes.getValueAsBool(FontAntiAliasedAttribute, true) ? 0 : NoAntiAlias;

            // perform pre-initialisation
            d_font->setNativeResolution(Size(hres, vres));
            d_font->setAutoScalingEnabled(auto_scale);

            // Finalise construction of font without glyphs.
            // Glyphs will defined after we know which ones we need.
            d_font->constructor_impl(font_name, filename, resourceGroup, size, flags, String(""));
        }
        // static (Imageset based) font
        else if (font_type == FontTypeStatic)
        {
            d_font->d_name = font_name;
            d_font->d_freetype = false;

            // load the Imageset
            d_font->d_glyph_images = ImagesetManager::getSingleton().createImageset(filename, resourceGroup);

            d_font->setNativeResolution(Size(hres, vres));
            d_font->setAutoScalingEnabled(auto_scale);
        }
        // error (should never happen)
        else
        {
            throw FileIOException("Font::xmlHandler::startElement - The unknown Font:Type attribute value '" + font_type + "' was encountered while processing the Font file.");
        }

        d_font->d_sourceFilename = filename;
    }
    // Glyph element
    else if (element == GlyphElement)
    {
        if (d_font->d_freetype)
        {
            utf32 codepoint = (utf32)attributes.getValueAsInteger(GlyphCodepointAttribute);

            if (d_glyphSet.find(codepoint) == String::npos)
            {
                d_glyphSet.append(1, codepoint);
            }
        }
        else
        {
            Logger::getSingleton().logEvent((utf8*)"Glyph element encountered.  This element is invalid for static fonts.", Informative);
        }
    }
    // GlyphRange element
    else if (element == GlyphRangeElement)
    {
        if (d_font->d_freetype)
        {
            utf32 start = (utf32)attributes.getValueAsInteger(GlyphRangeStartCodepointAttribute);
            utf32 end	= (utf32)attributes.getValueAsInteger(GlyphRangeEndCodepointAttribute);

            for (utf32 codepoint = start; codepoint <= end; ++codepoint)
            {
                if (d_glyphSet.find(codepoint) == String::npos)
                {
                    d_glyphSet.append(1, codepoint);
                }
            }

        }
        else
        {
            Logger::getSingleton().logEvent((utf8*)"GlyphRange element encountered.  This element is invalid for static fonts.", Informative);
        }
    }
    // GlyphSet element
    else if (element == GlyphSetElement)
    {
        if (d_font->d_freetype)
        {
            String glyphs(attributes.getValueAsString(GlyphSetGlyphsAttribute));

            for (String::size_type i = 0; i < glyphs.length(); ++i)
            {
                utf32 codepoint = glyphs[i];

                if (d_glyphSet.find(codepoint) == String::npos)
                {
                    d_glyphSet.append(1, codepoint);
                }

            }

        }
        else
        {
            Logger::getSingleton().logEvent((utf8*)"GlyphSet element encountered.  This element is invalid for static fonts.", Informative);
        }
    }
    // anything else is an error which *should* have already been caught by XML validation
    else
    {
        throw FileIOException("Font::xmlHandler::startElement - Unexpected data was found while parsing the Font file: '" + element + "' is unknown.");
    }

}