skia2/tests/SkGlyphBufferTest.cpp
Ben Wagner bee5ccd548 Avoid "drawable" when not referring to SkDrawable.
Change all use of "drawable" to "accepted" in glyph drawing code. To
improve uniformity "rejects" is also changed to "rejected".  This is
motivated by the desire to add SkDrawable backed glyph rendering, which
would make the use of "drawable" for both "glyphs which are drawable"
and "glyph which renders with SkDrawable" very confusing.

Change-Id: I6d080bc9ec25f81aa9479757d2cca47ae74f4db6
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/504236
Reviewed-by: Herb Derby <herb@google.com>
Commit-Queue: Ben Wagner <bungeman@google.com>
2022-02-04 15:52:11 +00:00

196 lines
8.0 KiB
C++

/*
* Copyright 2019 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "src/core/SkEnumerate.h"
#include "src/core/SkGlyphBuffer.h"
#include "src/core/SkGlyphRunPainter.h"
#include "src/core/SkScalerContext.h"
#include "tests/Test.h"
DEF_TEST(SkPackedGlyphIDCtor, reporter) {
using PG = SkPackedGlyphID;
// x and y are in one quarter the sub-pixel sampling frequency.
// Number of steps on the interval [0, 1)
const int perUnit = 1u << (PG::kSubPixelPosLen + 2);
const float step = 1.f / perUnit;
const int testLimit = 2 * perUnit;
auto freqRound = [](uint32_t x) -> uint32_t {
return ((x + 2) >> 2) & PG::kSubPixelPosMask;
};
{
// Normal sub-pixel with y-axis snapping.
auto roundingSpec = SkGlyphPositionRoundingSpec(true, kX_SkAxisAlignment);
SkIPoint mask = roundingSpec.ignorePositionFieldMask;
for (int x = -testLimit; x < testLimit; x++) {
float fx = x * step;
SkPoint roundedPos = SkPoint{fx, 0} + roundingSpec.halfAxisSampleFreq;
SkPackedGlyphID packedID{3, roundedPos, mask};
uint32_t subX = freqRound(x);
uint32_t subY = 0;
SkPackedGlyphID correctID(3, subX, subY);
SkASSERT(packedID == correctID);
REPORTER_ASSERT(reporter, packedID == correctID);
}
}
{
// No subpixel positioning.
auto roundingSpec = SkGlyphPositionRoundingSpec(false, kNone_SkAxisAlignment);
SkIPoint mask = roundingSpec.ignorePositionFieldMask;
for (int y = -testLimit; y < testLimit; y++) {
for (int x = -testLimit; x < testLimit; x++) {
float fx = x * step, fy = y * step;
SkPoint roundedPos = SkPoint{fx, fy} + roundingSpec.halfAxisSampleFreq;
SkPackedGlyphID packedID{3, roundedPos, mask};
uint32_t subX = 0;
uint32_t subY = 0;
SkPackedGlyphID correctID(3, subX, subY);
REPORTER_ASSERT(reporter, packedID == correctID);
}
}
}
{
// Subpixel with no axis snapping.
auto roundingSpec = SkGlyphPositionRoundingSpec(true, kNone_SkAxisAlignment);
SkIPoint mask = roundingSpec.ignorePositionFieldMask;
for (int y = -testLimit; y < testLimit; y++) {
for (int x = -testLimit; x < testLimit; x++) {
float fx = x * step, fy = y * step;
SkPoint roundedPos = SkPoint{fx, fy} + roundingSpec.halfAxisSampleFreq;
SkPackedGlyphID packedID{3, roundedPos, mask};
uint32_t subX = freqRound(x);
uint32_t subY = freqRound(y);
SkPackedGlyphID correctID(3, subX, subY);
REPORTER_ASSERT(reporter, packedID == correctID);
}
}
}
{
// Test dynamic range by transposing a large distance.
// Floating point numbers have 24 bits of precision. The largest distance is 24 - 2 (for
// sub-pixel) - 1 (for truncation to floor trick in the code). This leaves 21 bits. Large
// Distance is 2^21 - 2 (because the test is on the interval [-2, 2).
const uint32_t kLogLargeDistance = 24 - PG::kSubPixelPosLen - 1;
const int64_t kLargeDistance = (1ull << kLogLargeDistance) - 2;
auto roundingSpec = SkGlyphPositionRoundingSpec(true, kNone_SkAxisAlignment);
SkIPoint mask = roundingSpec.ignorePositionFieldMask;
for (int y = -32; y < 33; y++) {
for (int x = -32; x < 33; x++) {
float fx = x * step + kLargeDistance, fy = y * step + kLargeDistance;
SkPoint roundedPos = SkPoint{fx, fy} + roundingSpec.halfAxisSampleFreq;
SkPackedGlyphID packedID{3, roundedPos, mask};
uint32_t subX = freqRound(x);
uint32_t subY = freqRound(y);
SkPackedGlyphID correctID(3, subX, subY);
REPORTER_ASSERT(reporter, packedID == correctID);
}
}
}
}
DEF_TEST(SkSourceGlyphBufferBasic, reporter) {
SkSourceGlyphBuffer rejects;
// Positions are picked to avoid precision problems.
const SkPoint positions[] = {{10.25,10.25}, {20.5,10.25}, {30.75,10.25}, {40,10.25}};
const SkGlyphID glyphIDs[] = {1, 2, 3, 4};
auto source = SkMakeZip(glyphIDs, positions);
rejects.setSource(source);
for (auto [i, glyphID, pos] : SkMakeEnumerate(rejects.source())) {
REPORTER_ASSERT(reporter, glyphID == std::get<0>(source[i]));
REPORTER_ASSERT(reporter, pos == std::get<1>(source[i]));
}
// Reject a couple of glyphs.
rejects.reject(1);
rejects.reject(2, 100);
rejects.flipRejectsToSource();
REPORTER_ASSERT(reporter, std::get<1>(rejects.maxDimensionHint()) == 100);
for (auto [i, glyphID, pos] : SkMakeEnumerate(rejects.source())) {
// This will index 1 and 2 from the original source.
size_t j = i + 1;
REPORTER_ASSERT(reporter, glyphID == std::get<0>(source[j]));
REPORTER_ASSERT(reporter, pos == std::get<1>(source[j]));
}
// Reject an additional glyph
rejects.reject(0, 10);
rejects.flipRejectsToSource();
REPORTER_ASSERT(reporter, std::get<1>(rejects.maxDimensionHint()) == 10);
for (auto [i, glyphID, pos] : SkMakeEnumerate(rejects.source())) {
// This will index 1 from the original source.
size_t j = i + 1;
REPORTER_ASSERT(reporter, glyphID == std::get<0>(source[j]));
REPORTER_ASSERT(reporter, pos == std::get<1>(source[j]));
}
// Start all over
rejects.setSource(source);
for (auto [i, glyphID, pos] : SkMakeEnumerate(rejects.source())) {
REPORTER_ASSERT(reporter, glyphID == std::get<0>(source[i]));
REPORTER_ASSERT(reporter, pos == std::get<1>(source[i]));
}
// Check that everything is working after calling setSource.
rejects.reject(1);
rejects.reject(2, 100);
rejects.flipRejectsToSource();
REPORTER_ASSERT(reporter, std::get<1>(rejects.maxDimensionHint()) == 100);
for (auto [i, glyphID, pos] : SkMakeEnumerate(rejects.source())) {
// This will index 1 and 2 from the original source.
size_t j = i + 1;
REPORTER_ASSERT(reporter, glyphID == std::get<0>(source[j]));
REPORTER_ASSERT(reporter, pos == std::get<1>(source[j]));
}
}
DEF_TEST(SkDrawableGlyphBufferBasic, reporter) {
// Positions are picked to avoid precision problems.
const SkPoint positions[] = {{10.25,10.25}, {20.5,10.25}, {30.75,10.25}, {40,10.25}};
const SkGlyphID glyphIDs[] = {1, 2, 3, 4};
SkGlyph glyphs[100];
auto source = SkMakeZip(glyphIDs, positions);
{
SkDrawableGlyphBuffer accepted;
accepted.ensureSize(100);
accepted.startSource(source);
for (auto [i, packedID, pos] : SkMakeEnumerate(accepted.input())) {
REPORTER_ASSERT(reporter, packedID.packedID().glyphID() == glyphIDs[i]);
REPORTER_ASSERT(reporter, pos == positions[i]);
}
}
{
SkDrawableGlyphBuffer accepted;
accepted.ensureSize(100);
SkMatrix matrix = SkMatrix::Scale(0.5, 0.5);
SkGlyphPositionRoundingSpec rounding{true, kX_SkAxisAlignment};
accepted.startBitmapDevice(source, {100, 100}, matrix, rounding);
for (auto [i, packedID, pos] : SkMakeEnumerate(accepted.input())) {
REPORTER_ASSERT(reporter, glyphIDs[i] == packedID.packedID().glyphID());
REPORTER_ASSERT(reporter,
pos.x() == positions[i].x() * 0.5 + 50 + SkPackedGlyphID::kSubpixelRound);
REPORTER_ASSERT(reporter, pos.y() == positions[i].y() * 0.5 + 50 + 0.5);
}
}
{
SkDrawableGlyphBuffer accepted;
accepted.ensureSize(100);
accepted.startSource(source);
for (auto [i, packedID, pos] : SkMakeEnumerate(accepted.input())) {
accepted.accept(&glyphs[i], i);
}
for (auto [i, glyph, pos] : SkMakeEnumerate(accepted.accepted())) {
REPORTER_ASSERT(reporter, glyph.glyph() == &glyphs[i]);
}
}
}