aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gm/atlastext.cpp31
-rw-r--r--include/atlastext/SkAtlasTextRenderer.h6
-rw-r--r--include/atlastext/SkAtlasTextTarget.h34
-rw-r--r--include/gpu/GrContextOptions.h8
-rw-r--r--src/atlastext/SkAtlasTextTarget.cpp50
-rw-r--r--src/atlastext/SkInternalAtlasTextContext.cpp4
-rw-r--r--src/atlastext/SkInternalAtlasTextContext.h3
-rw-r--r--src/gpu/GrContext.cpp6
-rw-r--r--src/gpu/text/GrAtlasTextContext.cpp4
-rw-r--r--src/gpu/text/GrAtlasTextContext.h3
-rw-r--r--tools/gpu/atlastext/GLTestAtlasTextRenderer.cpp8
11 files changed, 138 insertions, 19 deletions
diff --git a/gm/atlastext.cpp b/gm/atlastext.cpp
index 832a604e6e..ac5b3e4582 100644
--- a/gm/atlastext.cpp
+++ b/gm/atlastext.cpp
@@ -49,7 +49,8 @@ static SkScalar draw_string(SkAtlasTextTarget* target, const SkString& text, SkS
target->drawText(glyphs.get(), positions.get(), cnt, color, *font);
- return positions[cnt - 1].fX + widths[cnt - 1];
+ // Return the width of the of draw.
+ return positions[cnt - 1].fX + widths[cnt - 1] - positions[0].fX;
}
class AtlasTextGM : public skiagm::GM {
@@ -109,12 +110,30 @@ private:
auto size = 2 * s;
for (const auto& typeface : fTypefaces) {
for (const auto& text : kTexts) {
- uint32_t color = random.nextU();
- x = size + draw_string(fTarget.get(), text, x, y, color, typeface, size);
+ // Choose a random color but don't let alpha be too small to see.
+ uint32_t color = random.nextU() | 0x40000000;
+ fTarget->save();
+ // Randomly add a little bit of perspective
+ if (random.nextBool()) {
+ SkMatrix persp;
+ persp.reset();
+ persp.setPerspY(0.0005f);
+ persp.preTranslate(-x, -y + s);
+ persp.postTranslate(x, y - s);
+ fTarget->concat(persp);
+ }
+ // Randomly switch between positioning with a matrix vs x, y passed to draw.
+ SkScalar drawX = x, drawY = y;
+ if (random.nextBool()) {
+ fTarget->translate(x, y);
+ drawX = drawY = 0;
+ }
+ x += size +
+ draw_string(fTarget.get(), text, drawX, drawY, color, typeface, size);
x = SkScalarCeilToScalar(x);
- // Flush periodically to test continued drawing after a flush. Using color
- // to avoid churning the RNG and having to rebaseline images.
- if (!(color & 0xf)) {
+ fTarget->restore();
+ // Flush periodically to test continued drawing after a flush.
+ if ((random.nextU() % 8) == 0) {
fTarget->flush();
}
if (x + 100 > kSize) {
diff --git a/include/atlastext/SkAtlasTextRenderer.h b/include/atlastext/SkAtlasTextRenderer.h
index a78e270edb..f5eb5240c9 100644
--- a/include/atlastext/SkAtlasTextRenderer.h
+++ b/include/atlastext/SkAtlasTextRenderer.h
@@ -5,7 +5,7 @@
* found in the LICENSE file.
*/
-#include "SkPoint.h"
+#include "SkPoint3.h"
#include "SkRefCnt.h"
#ifndef SkAtlasTextRenderer_DEFINED
@@ -25,8 +25,8 @@ public:
};
struct SDFVertex {
- /** Position in device space (not normalized). */
- SkPoint fPosition;
+ /** Position in device space (not normalized). The third component is w (not z). */
+ SkPoint3 fPosition;
/** Color, same value for all four corners of a glyph quad. */
uint32_t fColor;
/** Texture coordinate (in texel units, not normalized). */
diff --git a/include/atlastext/SkAtlasTextTarget.h b/include/atlastext/SkAtlasTextTarget.h
index ff879617d8..c29f381dc8 100644
--- a/include/atlastext/SkAtlasTextTarget.h
+++ b/include/atlastext/SkAtlasTextTarget.h
@@ -9,11 +9,13 @@
#define SkAtlasTextTarget_DEFINED
#include <memory>
+#include "SkDeque.h"
#include "SkRefCnt.h"
#include "SkScalar.h"
class SkAtlasTextContext;
class SkAtlasTextFont;
+class SkMatrix;
struct SkPoint;
/** Represents a client-created renderable surface and is used to draw text into the surface. */
@@ -46,15 +48,47 @@ public:
SkAtlasTextContext* context() const { return fContext.get(); }
+ /** Saves the current matrix in a stack. Returns the prior depth of the saved matrix stack. */
+ int save();
+ /** Pops the top matrix on the stack if the stack is not empty. */
+ void restore();
+ /**
+ * Pops the matrix stack until the stack depth is count. Does nothing if the depth is already
+ * less than count.
+ */
+ void restoreToCount(int count);
+
+ /** Pre-translates the current CTM. */
+ void translate(SkScalar dx, SkScalar dy);
+ /** Pre-scales the current CTM. */
+ void scale(SkScalar sx, SkScalar sy);
+ /** Pre-rotates the current CTM about the origin. */
+ void rotate(SkScalar degrees);
+ /** Pre-rotates the current CTM about the (px, py). */
+ void rotate(SkScalar degrees, SkScalar px, SkScalar py);
+ /** Pre-skews the current CTM. */
+ void skew(SkScalar sx, SkScalar sy);
+ /** Pre-concats the current CTM. */
+ void concat(const SkMatrix& matrix);
+
protected:
SkAtlasTextTarget(sk_sp<SkAtlasTextContext>, int width, int height, void* handle);
+ const SkMatrix& ctm() const { return *static_cast<const SkMatrix*>(fMatrixStack.back()); }
+
void* const fHandle;
const sk_sp<SkAtlasTextContext> fContext;
const int fWidth;
const int fHeight;
private:
+ SkDeque fMatrixStack;
+ int fSaveCnt;
+
+ SkMatrix* accessCTM() const {
+ return static_cast<SkMatrix*>(const_cast<void*>(fMatrixStack.back()));
+ }
+
SkAtlasTextTarget() = delete;
SkAtlasTextTarget(const SkAtlasTextContext&) = delete;
SkAtlasTextTarget& operator=(const SkAtlasTextContext&) = delete;
diff --git a/include/gpu/GrContextOptions.h b/include/gpu/GrContextOptions.h
index 41872be78a..2640d51e1b 100644
--- a/include/gpu/GrContextOptions.h
+++ b/include/gpu/GrContextOptions.h
@@ -187,6 +187,14 @@ struct GrContextOptions {
*/
bool fDisableImageMultitexturing = false;
#endif
+
+#if SK_SUPPORT_ATLAS_TEXT
+ /**
+ * Controls whether distance field glyph vertices always have 3 components even when the view
+ * matrix does not have perspective.
+ */
+ Enable fDistanceFieldGlyphVerticesAlwaysHaveW = Enable::kDefault;
+#endif
};
#endif
diff --git a/src/atlastext/SkAtlasTextTarget.cpp b/src/atlastext/SkAtlasTextTarget.cpp
index 81dbb07a16..0a318e0c8e 100644
--- a/src/atlastext/SkAtlasTextTarget.cpp
+++ b/src/atlastext/SkAtlasTextTarget.cpp
@@ -21,10 +21,53 @@ static constexpr int kMaxBatchLookBack = 10;
SkAtlasTextTarget::SkAtlasTextTarget(sk_sp<SkAtlasTextContext> context, int width, int height,
void* handle)
- : fHandle(handle), fContext(std::move(context)), fWidth(width), fHeight(height) {}
+ : fHandle(handle)
+ , fContext(std::move(context))
+ , fWidth(width)
+ , fHeight(height)
+ , fMatrixStack(sizeof(SkMatrix), 4)
+ , fSaveCnt(0) {
+ fMatrixStack.push_back();
+ this->accessCTM()->reset();
+}
SkAtlasTextTarget::~SkAtlasTextTarget() { fContext->renderer()->targetDeleted(fHandle); }
+int SkAtlasTextTarget::save() {
+ const auto& currCTM = this->ctm();
+ *static_cast<SkMatrix*>(fMatrixStack.push_back()) = currCTM;
+ return fSaveCnt++;
+}
+
+void SkAtlasTextTarget::restore() {
+ if (fSaveCnt) {
+ fMatrixStack.pop_back();
+ fSaveCnt--;
+ }
+}
+
+void SkAtlasTextTarget::restoreToCount(int count) {
+ while (fSaveCnt > count) {
+ this->restore();
+ }
+}
+
+void SkAtlasTextTarget::translate(SkScalar dx, SkScalar dy) {
+ this->accessCTM()->preTranslate(dx, dy);
+}
+
+void SkAtlasTextTarget::scale(SkScalar sx, SkScalar sy) { this->accessCTM()->preScale(sx, sy); }
+
+void SkAtlasTextTarget::rotate(SkScalar degrees) { this->accessCTM()->preRotate(degrees); }
+
+void SkAtlasTextTarget::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
+ this->accessCTM()->preRotate(degrees, px, py);
+}
+
+void SkAtlasTextTarget::skew(SkScalar sx, SkScalar sy) { this->accessCTM()->preSkew(sx, sy); }
+
+void SkAtlasTextTarget::concat(const SkMatrix& matrix) { this->accessCTM()->preConcat(matrix); }
+
//////////////////////////////////////////////////////////////////////////////
static const GrColorSpaceInfo kColorSpaceInfo(nullptr, kRGBA_8888_GrPixelConfig);
@@ -95,7 +138,7 @@ void SkInternalAtlasTextTarget::drawText(const SkGlyphID glyphs[], const SkPoint
auto atlasTextContext = grContext->contextPriv().drawingManager()->getAtlasTextContext();
size_t byteLength = sizeof(SkGlyphID) * glyphCnt;
const SkScalar* pos = &positions->fX;
- atlasTextContext->drawPosText(grContext, this, GrNoClip(), paint, SkMatrix::I(), props,
+ atlasTextContext->drawPosText(grContext, this, GrNoClip(), paint, this->ctm(), props,
(const char*)glyphs, byteLength, pos, 2, {0, 0}, bounds);
}
@@ -149,7 +192,8 @@ void GrAtlasTextOp::executeForTextTarget(SkAtlasTextTarget* target) {
GrAtlasTextBlob::VertexRegenerator::Result result;
do {
result = regenerator.regenerate();
- context.recordDraw(result.fFirstVertex, result.fGlyphsRegenerated, target->handle());
+ context.recordDraw(result.fFirstVertex, result.fGlyphsRegenerated,
+ fGeoData[i].fViewMatrix, target->handle());
if (!result.fFinished) {
// Make space in the atlas so we can continue generating vertices.
context.flush();
diff --git a/src/atlastext/SkInternalAtlasTextContext.cpp b/src/atlastext/SkInternalAtlasTextContext.cpp
index 858ae4da01..6dde9ae096 100644
--- a/src/atlastext/SkInternalAtlasTextContext.cpp
+++ b/src/atlastext/SkInternalAtlasTextContext.cpp
@@ -30,6 +30,7 @@ SkInternalAtlasTextContext::SkInternalAtlasTextContext(sk_sp<SkAtlasTextRenderer
options.fAllowMultipleGlyphCacheTextures = GrContextOptions::Enable::kNo;
options.fMinDistanceFieldFontSize = 0.f;
options.fGlyphsAsPathsFontSize = SK_ScalarInfinity;
+ options.fDistanceFieldGlyphVerticesAlwaysHaveW = GrContextOptions::Enable::kYes;
fGrContext = GrContext::MakeMock(nullptr, options);
}
@@ -62,7 +63,7 @@ GrDeferredUploadToken SkInternalAtlasTextContext::addASAPUpload(
}
void SkInternalAtlasTextContext::recordDraw(const void* srcVertexData, int glyphCnt,
- void* targetHandle) {
+ const SkMatrix& matrix, void* targetHandle) {
auto vertexDataSize = sizeof(SkAtlasTextRenderer::SDFVertex) * 4 * glyphCnt;
auto vertexData = fArena.makeArrayDefault<char>(vertexDataSize);
memcpy(vertexData, srcVertexData, vertexDataSize);
@@ -72,6 +73,7 @@ void SkInternalAtlasTextContext::recordDraw(const void* srcVertexData, int glyph
// This isn't expected by SkAtlasTextRenderer subclasses.
vertex->fTextureCoord.fX /= 2;
vertex->fTextureCoord.fY /= 2;
+ matrix.mapHomogeneousPoints(&vertex->fPosition, &vertex->fPosition, 1);
}
fDraws.append(&fArena, Draw{glyphCnt, this->issueDrawToken(), targetHandle, vertexData});
}
diff --git a/src/atlastext/SkInternalAtlasTextContext.h b/src/atlastext/SkInternalAtlasTextContext.h
index 1bb12cee5a..ea89435580 100644
--- a/src/atlastext/SkInternalAtlasTextContext.h
+++ b/src/atlastext/SkInternalAtlasTextContext.h
@@ -14,6 +14,7 @@
#include "SkRefCnt.h"
class SkAtlasTextRenderer;
+class SkMatrix;
class GrContext;
class GrAtlasGlyphCache;
class GrTextBlobCache;
@@ -38,7 +39,7 @@ public:
GrDeferredUploadToken addASAPUpload(GrDeferredTextureUploadFn&&) override;
- void recordDraw(const void* vertexData, int glyphCnt, void* targetHandle);
+ void recordDraw(const void* vertexData, int glyphCnt, const SkMatrix&, void* targetHandle);
void flush();
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index c410874fd9..9240d63b4a 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -234,6 +234,12 @@ bool GrContext::init(const GrContextOptions& options) {
GrAtlasTextContext::Options atlasTextContextOptions;
atlasTextContextOptions.fMaxDistanceFieldFontSize = options.fGlyphsAsPathsFontSize;
atlasTextContextOptions.fMinDistanceFieldFontSize = options.fMinDistanceFieldFontSize;
+ atlasTextContextOptions.fDistanceFieldVerticesAlwaysHaveW = false;
+#if SK_SUPPORT_ATLAS_TEXT
+ if (GrContextOptions::Enable::kYes == options.fDistanceFieldGlyphVerticesAlwaysHaveW) {
+ atlasTextContextOptions.fDistanceFieldVerticesAlwaysHaveW = true;
+ }
+#endif
fDrawingManager.reset(
new GrDrawingManager(this, prcOptions, atlasTextContextOptions, &fSingleOwner));
diff --git a/src/gpu/text/GrAtlasTextContext.cpp b/src/gpu/text/GrAtlasTextContext.cpp
index 3faa0f7b87..73a27100d3 100644
--- a/src/gpu/text/GrAtlasTextContext.cpp
+++ b/src/gpu/text/GrAtlasTextContext.cpp
@@ -39,6 +39,7 @@ GrAtlasTextContext::GrAtlasTextContext(const Options& options)
fMinDistanceFieldFontSize = options.fMinDistanceFieldFontSize < 0.f
? kDefaultMinDistanceFieldFontSize
: options.fMinDistanceFieldFontSize;
+ fDistanceFieldVerticesAlwaysHaveW = options.fDistanceFieldVerticesAlwaysHaveW;
}
std::unique_ptr<GrAtlasTextContext> GrAtlasTextContext::Make(const Options& options) {
@@ -646,7 +647,8 @@ void GrAtlasTextContext::drawDFPosText(GrAtlasTextBlob* blob, int runIndex,
SkTDArray<char> fallbackTxt;
SkTDArray<SkScalar> fallbackPos;
- bool hasWCoord = viewMatrix.hasPerspective();
+ bool hasWCoord = viewMatrix.hasPerspective() || fDistanceFieldVerticesAlwaysHaveW;
+
// Setup distance field paint and text ratio
SkScalar textRatio;
SkPaint dfPaint(paint);
diff --git a/src/gpu/text/GrAtlasTextContext.h b/src/gpu/text/GrAtlasTextContext.h
index 8db0d7e050..52c8dfcb87 100644
--- a/src/gpu/text/GrAtlasTextContext.h
+++ b/src/gpu/text/GrAtlasTextContext.h
@@ -38,6 +38,8 @@ public:
* be rendered from outline as individual paths. Negative means use a default value.
*/
SkScalar fMaxDistanceFieldFontSize = -1.f;
+ /** Forces all distance field vertices to use 3 components, not just when in perspective. */
+ bool fDistanceFieldVerticesAlwaysHaveW = false;
};
static std::unique_ptr<GrAtlasTextContext> Make(const Options& options);
@@ -142,6 +144,7 @@ private:
SkScalar fMinDistanceFieldFontSize;
SkScalar fMaxDistanceFieldFontSize;
+ bool fDistanceFieldVerticesAlwaysHaveW;
#if GR_TEST_UTILS
static const uint32_t kTextBlobOpScalerContextFlags =
diff --git a/tools/gpu/atlastext/GLTestAtlasTextRenderer.cpp b/tools/gpu/atlastext/GLTestAtlasTextRenderer.cpp
index ef416b2e39..677ce5a924 100644
--- a/tools/gpu/atlastext/GLTestAtlasTextRenderer.cpp
+++ b/tools/gpu/atlastext/GLTestAtlasTextRenderer.cpp
@@ -125,7 +125,7 @@ GLTestAtlasTextRenderer::GLTestAtlasTextRenderer(std::unique_ptr<GLTestContext>
uniform vec4 uDstScaleAndTranslate;
uniform vec2 uAtlasInvSize;
- layout (location = 0) in vec2 inPosition;
+ layout (location = 0) in vec3 inPosition;
layout (location = 1) in vec4 inColor;
layout (location = 2) in uvec2 inTextureCoords;
@@ -143,7 +143,7 @@ GLTestAtlasTextRenderer::GLTestAtlasTextRenderer(std::unique_ptr<GLTestContext>
vColor = inColor;
gl_Position = vec4(inPosition.x * uDstScaleAndTranslate.x + uDstScaleAndTranslate.y,
inPosition.y * uDstScaleAndTranslate.z + uDstScaleAndTranslate.w,
- 0.0, 1.0);
+ 0.0, inPosition.z);
}
)";
strings[1] = kVS;
@@ -360,8 +360,8 @@ void GLTestAtlasTextRenderer::drawSDFGlyphs(void* targetHandle, void* textureHan
callgl(BindVertexArray, 0);
callgl(BindBuffer, GR_GL_ARRAY_BUFFER, 0);
callgl(BindBuffer, GR_GL_ELEMENT_ARRAY_BUFFER, 0);
- callgl(VertexAttribPointer, 0, 2, GR_GL_FLOAT, GR_GL_FALSE, sizeof(SDFVertex), vertices);
- size_t colorOffset = 2 * sizeof(float);
+ callgl(VertexAttribPointer, 0, 3, GR_GL_FLOAT, GR_GL_FALSE, sizeof(SDFVertex), vertices);
+ size_t colorOffset = 3 * sizeof(float);
callgl(VertexAttribPointer, 1, 4, GR_GL_UNSIGNED_BYTE, GR_GL_TRUE, sizeof(SDFVertex),
reinterpret_cast<const char*>(vertices) + colorOffset);
size_t texOffset = colorOffset + sizeof(uint32_t);