Add matrix stack to SkAtlasTextTarget.
Makes SkAtlasTextRenderer::SDFVertex now has a 3 component position vector. Change-Id: I7ec1a8068fb84388a82e1748d6e9d02820d55abd Reviewed-on: https://skia-review.googlesource.com/84202 Commit-Queue: Brian Salomon <bsalomon@google.com> Reviewed-by: Jim Van Verth <jvanverth@google.com>
This commit is contained in:
parent
e1367b4a06
commit
b5086961f3
@ -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) {
|
||||
|
@ -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). */
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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});
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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 =
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user