aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/atlastext
diff options
context:
space:
mode:
Diffstat (limited to 'src/atlastext')
-rw-r--r--src/atlastext/SkAtlasTextContext.cpp17
-rw-r--r--src/atlastext/SkAtlasTextTarget.cpp143
-rw-r--r--src/atlastext/SkInternalAtlasTextContext.cpp117
-rw-r--r--src/atlastext/SkInternalAtlasTextContext.h80
4 files changed, 357 insertions, 0 deletions
diff --git a/src/atlastext/SkAtlasTextContext.cpp b/src/atlastext/SkAtlasTextContext.cpp
new file mode 100644
index 0000000000..85e79118ee
--- /dev/null
+++ b/src/atlastext/SkAtlasTextContext.cpp
@@ -0,0 +1,17 @@
+/*
+ * 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 "SkAtlasTextContext.h"
+#include "SkAtlasTextRenderer.h"
+#include "SkInternalAtlasTextContext.h"
+
+sk_sp<SkAtlasTextContext> SkAtlasTextContext::Make(sk_sp<SkAtlasTextRenderer> renderer) {
+ return sk_sp<SkAtlasTextContext>(new SkAtlasTextContext(std::move(renderer)));
+}
+
+SkAtlasTextContext::SkAtlasTextContext(sk_sp<SkAtlasTextRenderer> renderer)
+ : fInternalContext(SkInternalAtlasTextContext::Make(std::move(renderer))) {}
diff --git a/src/atlastext/SkAtlasTextTarget.cpp b/src/atlastext/SkAtlasTextTarget.cpp
new file mode 100644
index 0000000000..57ece37b4f
--- /dev/null
+++ b/src/atlastext/SkAtlasTextTarget.cpp
@@ -0,0 +1,143 @@
+/*
+ * 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 "SkAtlasTextTarget.h"
+#include "GrClip.h"
+#include "SkAtlasTextContext.h"
+#include "SkAtlasTextFont.h"
+#include "SkAtlasTextRenderer.h"
+#include "SkGr.h"
+#include "SkInternalAtlasTextContext.h"
+#include "ops/GrAtlasTextOp.h"
+#include "text/GrAtlasTextContext.h"
+
+SkAtlasTextTarget::SkAtlasTextTarget(sk_sp<SkAtlasTextContext> context, int width, int height,
+ void* handle)
+ : fHandle(handle), fContext(std::move(context)), fWidth(width), fHeight(height) {}
+
+SkAtlasTextTarget::~SkAtlasTextTarget() { fContext->renderer()->targetDeleted(fHandle); }
+
+//////////////////////////////////////////////////////////////////////////////
+
+static const GrColorSpaceInfo kColorSpaceInfo(nullptr, kRGBA_8888_GrPixelConfig);
+
+//////////////////////////////////////////////////////////////////////////////
+
+class SkInternalAtlasTextTarget : public GrTextUtils::Target, public SkAtlasTextTarget {
+public:
+ SkInternalAtlasTextTarget(sk_sp<SkAtlasTextContext> context, int width, int height,
+ void* handle)
+ : GrTextUtils::Target(width, height, kColorSpaceInfo)
+ , SkAtlasTextTarget(std::move(context), width, height, handle) {}
+
+ /** GrTextUtils::Target overrides */
+
+ void addDrawOp(const GrClip&, std::unique_ptr<GrAtlasTextOp> op) override;
+
+ void drawPath(const GrClip&, const SkPath&, const SkPaint&, const SkMatrix& viewMatrix,
+ const SkMatrix* pathMatrix, const SkIRect& clipBounds) override {
+ SkDebugf("Path glyph??");
+ }
+
+ void makeGrPaint(GrMaskFormat, const SkPaint& skPaint, const SkMatrix&,
+ GrPaint* grPaint) override {
+ grPaint->setColor4f(SkColorToPremulGrColor4fLegacy(skPaint.getColor()));
+ }
+
+ /** SkAtlasTextTarget overrides */
+
+ void drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, uint32_t color,
+ const SkAtlasTextFont&) override;
+ void flush() override;
+
+private:
+ uint32_t fColor;
+ using SkAtlasTextTarget::fWidth;
+ using SkAtlasTextTarget::fHeight;
+ struct RecordedOp {
+ std::unique_ptr<GrAtlasTextOp> fOp;
+ uint32_t fColor;
+ };
+ SkTArray<RecordedOp, true> fOps;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+std::unique_ptr<SkAtlasTextTarget> SkAtlasTextTarget::Make(sk_sp<SkAtlasTextContext> context,
+ int width, int height, void* handle) {
+ return std::unique_ptr<SkAtlasTextTarget>(
+ new SkInternalAtlasTextTarget(std::move(context), width, height, handle));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+#include "GrContextPriv.h"
+#include "GrDrawingManager.h"
+
+void SkInternalAtlasTextTarget::drawText(const void* text, size_t byteLength, SkScalar x,
+ SkScalar y, uint32_t color, const SkAtlasTextFont& font) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setTypeface(font.refTypeface());
+ paint.setTextSize(font.size());
+ paint.setStyle(SkPaint::kFill_Style);
+
+ // TODO: Figure out what if anything to do with these:
+ // Paint setTextEncoding? Font isEnableByteCodeHints()? Font isUseNonLinearMetrics()?
+
+ // The atlas text context does munging of the paint color. We store the client's color here
+ // and the context will write it into the final vertices given to the client's renderer.
+ fColor = color;
+
+ // The pixel geometry here is arbitrary. We don't draw LCD text.
+ SkSurfaceProps props(SkSurfaceProps::kUseDistanceFieldFonts_Flag, kUnknown_SkPixelGeometry);
+ auto* grContext = this->context()->internal().grContext();
+ auto bounds = SkIRect::MakeWH(fWidth, fHeight);
+ auto atlasTextContext = grContext->contextPriv().drawingManager()->getAtlasTextContext();
+ atlasTextContext->drawText(grContext, this, GrNoClip(), paint, SkMatrix::I(), props,
+ (const char*)text, byteLength, x, y, bounds);
+}
+
+void SkInternalAtlasTextTarget::addDrawOp(const GrClip& clip, std::unique_ptr<GrAtlasTextOp> op) {
+ SkASSERT(clip.quickContains(SkRect::MakeIWH(fWidth, fHeight)));
+ // The SkAtlasTextRenderer currently only handles grayscale SDF glyphs.
+ if (op->maskType() != GrAtlasTextOp::kGrayscaleDistanceField_MaskType) {
+ return;
+ }
+ // TODO: batch ops here.
+ op->visitProxies([](GrSurfaceProxy*) {});
+ fOps.emplace_back(RecordedOp{std::move(op), fColor});
+}
+
+void SkInternalAtlasTextTarget::flush() {
+ for (int i = 0; i < fOps.count(); ++i) {
+ fOps[i].fOp->executeForTextTarget(this, fOps[i].fColor);
+ }
+ this->context()->internal().flush();
+ fOps.reset();
+}
+
+void GrAtlasTextOp::executeForTextTarget(SkAtlasTextTarget* target, uint32_t color) {
+ FlushInfo flushInfo;
+ SkAutoGlyphCache glyphCache;
+ auto& context = target->context()->internal();
+ auto* atlasGlyphCache = context.grContext()->getAtlasGlyphCache();
+ for (int i = 0; i < fGeoCount; ++i) {
+ GrAtlasTextBlob::VertexRegenerator regenerator(
+ fGeoData[i].fBlob, fGeoData[i].fRun, fGeoData[i].fSubRun, fGeoData[i].fViewMatrix,
+ fGeoData[i].fX, fGeoData[i].fY, color, &context, atlasGlyphCache, &glyphCache);
+ GrAtlasTextBlob::VertexRegenerator::Result result;
+ do {
+ result = regenerator.regenerate();
+ context.recordDraw(result.fFirstVertex, result.fGlyphsRegenerated, target->handle());
+ if (!result.fFinished) {
+ // Make space in the atlas so we can continue generating vertices.
+ context.flush();
+ }
+ } while (!result.fFinished);
+ }
+}
diff --git a/src/atlastext/SkInternalAtlasTextContext.cpp b/src/atlastext/SkInternalAtlasTextContext.cpp
new file mode 100644
index 0000000000..8be7e1fb67
--- /dev/null
+++ b/src/atlastext/SkInternalAtlasTextContext.cpp
@@ -0,0 +1,117 @@
+/*
+ * 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 "SkAtlasTextContext.h"
+#include "SkAtlasTextRenderer.h"
+#include "text/GrAtlasGlyphCache.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;
+ fGrContext = GrContext::MakeMock(nullptr, options);
+}
+
+SkInternalAtlasTextContext::~SkInternalAtlasTextContext() {
+ if (fDistanceFieldAtlas.fProxy) {
+ SkASSERT(1 == fGrContext->getAtlasGlyphCache()->getAtlasPageCount(kA8_GrMaskFormat));
+ fRenderer->deleteTexture(fDistanceFieldAtlas.fTextureHandle);
+ }
+}
+
+GrAtlasGlyphCache* SkInternalAtlasTextContext::atlasGlyphCache() {
+ return fGrContext->getAtlasGlyphCache();
+}
+
+GrTextBlobCache* SkInternalAtlasTextContext::textBlobCache() {
+ return fGrContext->getTextBlobCache();
+}
+
+GrDeferredUploadToken SkInternalAtlasTextContext::addInlineUpload(
+ GrDeferredTextureUploadFn&& upload) {
+ auto token = this->nextDrawToken();
+ fInlineUploads.append(&fArena, InlineUpload{std::move(upload), token});
+ return token;
+}
+
+GrDeferredUploadToken SkInternalAtlasTextContext::addASAPUpload(
+ GrDeferredTextureUploadFn&& upload) {
+ fASAPUploads.append(&fArena, std::move(upload));
+ return this->nextTokenToFlush();
+}
+
+void SkInternalAtlasTextContext::recordDraw(const void* srcVertexData, int glyphCnt,
+ 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;
+ // GrAtlasTextContext encodes a texture index into the lower bit of each texture coord.
+ // This isn't expected by SkAtlasTextRenderer subclasses.
+ vertex->fTextureCoord.fX /= 2;
+ vertex->fTextureCoord.fY /= 2;
+ }
+ fDraws.append(&fArena, Draw{glyphCnt, this->issueDrawToken(), targetHandle, vertexData});
+}
+
+void SkInternalAtlasTextContext::flush() {
+ auto* atlasGlyphCache = fGrContext->getAtlasGlyphCache();
+ if (!fDistanceFieldAtlas.fProxy) {
+ SkASSERT(1 == atlasGlyphCache->getAtlasPageCount(kA8_GrMaskFormat));
+ fDistanceFieldAtlas.fProxy = atlasGlyphCache->getProxies(kA8_GrMaskFormat)->get();
+ 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,
+ GrPixelConfig config, const void* data, size_t rowBytes) -> bool {
+ SkASSERT(kAlpha_8_GrPixelConfig == config);
+ 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 draw = fDraws.begin();
+ auto inlineUpload = fInlineUploads.begin();
+ while (draw != fDraws.end()) {
+ 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);
+ ++draw;
+ }
+ fASAPUploads.reset();
+ fInlineUploads.reset();
+ fDraws.reset();
+ fArena.reset();
+}
diff --git a/src/atlastext/SkInternalAtlasTextContext.h b/src/atlastext/SkInternalAtlasTextContext.h
new file mode 100644
index 0000000000..1bb12cee5a
--- /dev/null
+++ b/src/atlastext/SkInternalAtlasTextContext.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkInternalAtlasTextContext_DEFINED
+#define SkInternalAtlasTextContext_DEFINED
+
+#include "GrDeferredUpload.h"
+#include "SkArenaAlloc.h"
+#include "SkArenaAllocList.h"
+#include "SkRefCnt.h"
+
+class SkAtlasTextRenderer;
+class GrContext;
+class GrAtlasGlyphCache;
+class GrTextBlobCache;
+
+/**
+ * The implementation of SkAtlasTextContext. This exists to hide the details from the public class.
+ * and to be able to use other private types.
+ */
+class SkInternalAtlasTextContext : public GrDeferredUploadTarget {
+public:
+ static std::unique_ptr<SkInternalAtlasTextContext> Make(sk_sp<SkAtlasTextRenderer>);
+
+ ~SkInternalAtlasTextContext() override;
+
+ SkAtlasTextRenderer* renderer() const { return fRenderer.get(); }
+
+ GrContext* grContext() const { return fGrContext.get(); }
+ GrAtlasGlyphCache* atlasGlyphCache();
+ GrTextBlobCache* textBlobCache();
+
+ GrDeferredUploadToken addInlineUpload(GrDeferredTextureUploadFn&&) override;
+
+ GrDeferredUploadToken addASAPUpload(GrDeferredTextureUploadFn&&) override;
+
+ void recordDraw(const void* vertexData, int glyphCnt, void* targetHandle);
+
+ void flush();
+
+private:
+ class DeferredUploader;
+ SkInternalAtlasTextContext() = delete;
+ SkInternalAtlasTextContext(const SkInternalAtlasTextContext&) = delete;
+ SkInternalAtlasTextContext& operator=(const SkInternalAtlasTextContext&) = delete;
+
+ SkInternalAtlasTextContext(sk_sp<SkAtlasTextRenderer>);
+
+ sk_sp<SkAtlasTextRenderer> fRenderer;
+
+ struct AtlasTexture {
+ void* fTextureHandle = nullptr;
+ GrTextureProxy* fProxy = nullptr;
+ };
+
+ struct Draw {
+ int fGlyphCnt;
+ GrDeferredUploadToken fToken;
+ void* fTargetHandle;
+ const void* fVertexData;
+ };
+
+ struct InlineUpload {
+ GrDeferredTextureUploadFn fUpload;
+ GrDeferredUploadToken fToken;
+ };
+
+ SkArenaAllocList<InlineUpload> fInlineUploads;
+ SkArenaAllocList<Draw> fDraws;
+ SkArenaAllocList<GrDeferredTextureUploadFn> fASAPUploads;
+ SkArenaAlloc fArena{1024 * 40};
+ sk_sp<GrContext> fGrContext;
+ AtlasTexture fDistanceFieldAtlas;
+};
+
+#endif