blob: 1c819258511e89523777c25712a1cd1808c80f9f [file]
/*
* Copyright 2021 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/core/SkBitmap.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkFont.h"
#include "include/core/SkFontStyle.h"
#include "include/core/SkFontTypes.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkPaint.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkSurface.h"
#include "include/core/SkTextBlob.h"
#include "include/core/SkTypeface.h"
#include "include/core/SkTypes.h"
#include "include/gpu/GpuTypes.h"
#include "include/gpu/ganesh/GrDirectContext.h"
#include "include/gpu/ganesh/SkSurfaceGanesh.h"
#include "include/private/base/SkTDArray.h"
#include "include/private/chromium/Slug.h"
#include "src/text/gpu/SlugImpl.h"
#include "src/utils/SkFloatUtils.h"
#include "tests/CtsEnforcement.h"
#include "tests/Test.h"
#include "tools/ToolUtils.h"
#include "tools/fonts/FontToolUtils.h"
#include <cstdint>
#include <cstring>
struct GrContextOptions;
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(Slug_empty,
reporter,
ctxInfo,
CtsEnforcement::kApiLevel_T) {
auto dContext = ctxInfo.directContext();
SkImageInfo info = SkImageInfo::MakeN32Premul(256, 256);
auto surface(SkSurfaces::RenderTarget(dContext, skgpu::Budgeted::kNo, info));
auto canvas = surface->getCanvas();
static const char* kText = " ";
auto typeface = ToolUtils::CreatePortableTypeface("serif", SkFontStyle());
SkFont font(typeface);
size_t txtLen = strlen(kText);
int glyphCount = font.countText(kText, txtLen, SkTextEncoding::kUTF8);
SkTDArray<SkGlyphID> glyphs;
glyphs.append(glyphCount);
font.textToGlyphs(kText, txtLen, SkTextEncoding::kUTF8, glyphs);
SkTextBlobBuilder builder;
font.setSubpixel(true);
font.setEdging(SkFont::Edging::kAntiAlias);
font.setTypeface(typeface);
font.setSize(16);
const SkTextBlobBuilder::RunBuffer& buf = builder.allocRun(font, glyphs.size(), 0, 0);
memcpy(buf.glyphs, glyphs.begin(), glyphs.size() * sizeof(SkGlyphID));
auto blob = builder.make();
SkPaint p;
p.setAntiAlias(true);
sk_sp<sktext::gpu::Slug> slug = sktext::gpu::Slug::ConvertBlob(canvas, *blob, {10, 10}, p);
REPORTER_ASSERT(reporter, slug == nullptr);
}
static void set_sdf_options(GrContextOptions* options) {
options->fMinDistanceFieldFontSize = 4;
options->fGlyphsAsPathsFontSize = 256;
options->fSupportBilerpFromGlyphAtlas = true;
}
DEF_GANESH_TEST_FOR_CONTEXTS(Slug_b520113415,
skgpu::IsRenderingContext,
reporter,
ctxInfo,
set_sdf_options,
CtsEnforcement::kNextRelease) {
auto dContext = ctxInfo.directContext();
SkImageInfo info = SkImageInfo::MakeN32Premul(256, 256);
auto surface = SkSurfaces::RenderTarget(dContext, skgpu::Budgeted::kNo, info);
REPORTER_ASSERT(reporter, surface);
auto canvas = surface->getCanvas();
// This matrix is big enough such that with the font below...
SkMatrix canvasMatrix = SkMatrix::Scale(1.2345f, 6.7890f);
canvas->save();
canvas->setMatrix(canvasMatrix);
// ... it will force SDFT (6.789 x 24 = ~162.9).
auto typeface = ToolUtils::CreatePortableTypeface("serif", SkFontStyle());
SkFont font(typeface);
font.setSubpixel(true);
font.setSize(24);
static const char* kText = "A";
int glyphCount = font.countText(kText, 1, SkTextEncoding::kUTF8);
SkTDArray<SkGlyphID> glyphs;
glyphs.append(glyphCount);
font.textToGlyphs(kText, 1, SkTextEncoding::kUTF8, glyphs);
SkTextBlobBuilder builder;
const SkTextBlobBuilder::RunBuffer& buf = builder.allocRun(font, glyphs.size(), 0, 0);
memcpy(buf.glyphs, glyphs.begin(), glyphs.size() * sizeof(SkGlyphID));
auto blob = builder.make();
SkPaint paint;
paint.setAntiAlias(true);
sk_sp<sktext::gpu::Slug> slug = sktext::gpu::Slug::ConvertBlob(canvas, *blob, {0, 0}, paint);
canvas->restore();
if (!slug) {
return;
}
sk_sp<SkData> data = slug->serialize();
if (!data || data->size() == 0) {
return;
}
// Copy data to a writable buffer so we can corrupt it
size_t size = data->size();
std::unique_ptr<uint8_t[]> writableData(new uint8_t[size]);
memcpy(writableData.get(), data->data(), size);
// The creationMatrix of VertexFiller inside SDFTSubRun is located 216 bytes in.
// We can overwrite it to have a matrix with perspective.
if (size < 216 + 9 * sizeof(float)) {
ERRORF(reporter, "Serialized Slug is too small to contain creationMatrix!");
return;
}
float* f = reinterpret_cast<float*>(writableData.get() + 216);
f[0] = 1.0f; f[1] = 0.0f; f[2] = 0.0f;
f[3] = 0.0f; f[4] = 1.0f; f[5] = 0.0f;
f[6] = 0.0078125f; f[7] = 0.0f; f[8] = 1.0f;
// Deserialize the forged slug. This should return nullptr. Previously, when we went to draw it,
// the perspective would cause issues.
sk_sp<sktext::gpu::Slug> forgedSlug =
sktext::gpu::Slug::Deserialize(writableData.get(), size, nullptr);
REPORTER_ASSERT(reporter, forgedSlug == nullptr);
}