/* * Copyright 2017 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "SkInternalAtlasTextContext.h" #include "GrContext.h" #include "GrContextPriv.h" #include "SkAtlasTextContext.h" #include "SkAtlasTextRenderer.h" #include "text/GrStrikeCache.h" SkAtlasTextRenderer* SkGetAtlasTextRendererFromInternalContext( class SkInternalAtlasTextContext& internal) { return internal.renderer(); } ////////////////////////////////////////////////////////////////////////////// std::unique_ptr<SkInternalAtlasTextContext> SkInternalAtlasTextContext::Make( sk_sp<SkAtlasTextRenderer> renderer) { return std::unique_ptr<SkInternalAtlasTextContext>( new SkInternalAtlasTextContext(std::move(renderer))); } SkInternalAtlasTextContext::SkInternalAtlasTextContext(sk_sp<SkAtlasTextRenderer> renderer) : fRenderer(std::move(renderer)) { GrContextOptions options; options.fAllowMultipleGlyphCacheTextures = GrContextOptions::Enable::kNo; options.fMinDistanceFieldFontSize = 0.f; options.fGlyphsAsPathsFontSize = SK_ScalarInfinity; options.fDistanceFieldGlyphVerticesAlwaysHaveW = GrContextOptions::Enable::kYes; fGrContext = GrContext::MakeMock(nullptr, options); } SkInternalAtlasTextContext::~SkInternalAtlasTextContext() { if (fDistanceFieldAtlas.fProxy) { #ifdef SK_DEBUG auto atlasManager = fGrContext->contextPriv().getAtlasManager(); if (atlasManager) { unsigned int numProxies; atlasManager->getProxies(kA8_GrMaskFormat, &numProxies); SkASSERT(1 == numProxies); } #endif fRenderer->deleteTexture(fDistanceFieldAtlas.fTextureHandle); } } GrStrikeCache* SkInternalAtlasTextContext::glyphCache() { return fGrContext->contextPriv().getGlyphCache(); } GrTextBlobCache* SkInternalAtlasTextContext::textBlobCache() { return fGrContext->contextPriv().getTextBlobCache(); } GrDeferredUploadToken SkInternalAtlasTextContext::addInlineUpload( GrDeferredTextureUploadFn&& upload) { auto token = fTokenTracker.nextDrawToken(); fInlineUploads.append(&fArena, InlineUpload{std::move(upload), token}); return token; } GrDeferredUploadToken SkInternalAtlasTextContext::addASAPUpload( GrDeferredTextureUploadFn&& upload) { fASAPUploads.append(&fArena, std::move(upload)); return fTokenTracker.nextTokenToFlush(); } void SkInternalAtlasTextContext::recordDraw(const void* srcVertexData, int glyphCnt, const SkMatrix& matrix, void* targetHandle) { auto vertexDataSize = sizeof(SkAtlasTextRenderer::SDFVertex) * 4 * glyphCnt; auto vertexData = fArena.makeArrayDefault<char>(vertexDataSize); memcpy(vertexData, srcVertexData, vertexDataSize); for (int i = 0; i < 4 * glyphCnt; ++i) { auto* vertex = reinterpret_cast<SkAtlasTextRenderer::SDFVertex*>(vertexData) + i; // GrTextContext encodes a texture index into the lower bit of each texture coord. // This isn't expected by SkAtlasTextRenderer subclasses. vertex->fTextureCoordX /= 2; vertex->fTextureCoordY /= 2; matrix.mapHomogeneousPoints(&vertex->fPosition, &vertex->fPosition, 1); } fDraws.append(&fArena, Draw{glyphCnt, fTokenTracker.issueDrawToken(), targetHandle, vertexData}); } void SkInternalAtlasTextContext::flush() { auto* atlasManager = fGrContext->contextPriv().getAtlasManager(); if (!fDistanceFieldAtlas.fProxy) { unsigned int numProxies; fDistanceFieldAtlas.fProxy = atlasManager->getProxies(kA8_GrMaskFormat, &numProxies)->get(); SkASSERT(1 == numProxies); fDistanceFieldAtlas.fTextureHandle = fRenderer->createTexture(SkAtlasTextRenderer::AtlasFormat::kA8, fDistanceFieldAtlas.fProxy->width(), fDistanceFieldAtlas.fProxy->height()); } GrDeferredTextureUploadWritePixelsFn writePixelsFn = [this](GrTextureProxy* proxy, int left, int top, int width, int height, GrColorType colorType, const void* data, size_t rowBytes) -> bool { SkASSERT(GrColorType::kAlpha_8 == colorType); SkASSERT(proxy == this->fDistanceFieldAtlas.fProxy); void* handle = fDistanceFieldAtlas.fTextureHandle; this->fRenderer->setTextureData(handle, data, left, top, width, height, rowBytes); return true; }; for (const auto& upload : fASAPUploads) { upload(writePixelsFn); } auto inlineUpload = fInlineUploads.begin(); for (const auto& draw : fDraws) { while (inlineUpload != fInlineUploads.end() && inlineUpload->fToken == draw.fToken) { inlineUpload->fUpload(writePixelsFn); ++inlineUpload; } auto vertices = reinterpret_cast<const SkAtlasTextRenderer::SDFVertex*>(draw.fVertexData); fRenderer->drawSDFGlyphs(draw.fTargetHandle, fDistanceFieldAtlas.fTextureHandle, vertices, draw.fGlyphCnt); fTokenTracker.flushToken(); } fASAPUploads.reset(); fInlineUploads.reset(); fDraws.reset(); fArena.reset(); }