1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2019 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "src/core/SkEnumerate.h" 9cb93a386Sopenharmony_ci#include "src/core/SkGlyphBuffer.h" 10cb93a386Sopenharmony_ci#include "src/core/SkGlyphRunPainter.h" 11cb93a386Sopenharmony_ci#include "src/core/SkScalerContext.h" 12cb93a386Sopenharmony_ci#include "tests/Test.h" 13cb93a386Sopenharmony_ci 14cb93a386Sopenharmony_ciDEF_TEST(SkPackedGlyphIDCtor, reporter) { 15cb93a386Sopenharmony_ci using PG = SkPackedGlyphID; 16cb93a386Sopenharmony_ci // x and y are in one quarter the sub-pixel sampling frequency. 17cb93a386Sopenharmony_ci // Number of steps on the interval [0, 1) 18cb93a386Sopenharmony_ci const int perUnit = 1u << (PG::kSubPixelPosLen + 2); 19cb93a386Sopenharmony_ci const float step = 1.f / perUnit; 20cb93a386Sopenharmony_ci const int testLimit = 2 * perUnit; 21cb93a386Sopenharmony_ci auto freqRound = [](uint32_t x) -> uint32_t { 22cb93a386Sopenharmony_ci return ((x + 2) >> 2) & PG::kSubPixelPosMask; 23cb93a386Sopenharmony_ci }; 24cb93a386Sopenharmony_ci 25cb93a386Sopenharmony_ci { 26cb93a386Sopenharmony_ci // Normal sub-pixel with y-axis snapping. 27cb93a386Sopenharmony_ci auto roundingSpec = SkGlyphPositionRoundingSpec(true, kX_SkAxisAlignment); 28cb93a386Sopenharmony_ci SkIPoint mask = roundingSpec.ignorePositionFieldMask; 29cb93a386Sopenharmony_ci for (int x = -testLimit; x < testLimit; x++) { 30cb93a386Sopenharmony_ci float fx = x * step; 31cb93a386Sopenharmony_ci SkPoint roundedPos = SkPoint{fx, 0} + roundingSpec.halfAxisSampleFreq; 32cb93a386Sopenharmony_ci SkPackedGlyphID packedID{3, roundedPos, mask}; 33cb93a386Sopenharmony_ci uint32_t subX = freqRound(x); 34cb93a386Sopenharmony_ci uint32_t subY = 0; 35cb93a386Sopenharmony_ci SkPackedGlyphID correctID(3, subX, subY); 36cb93a386Sopenharmony_ci SkASSERT(packedID == correctID); 37cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, packedID == correctID); 38cb93a386Sopenharmony_ci } 39cb93a386Sopenharmony_ci } 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_ci { 42cb93a386Sopenharmony_ci // No subpixel positioning. 43cb93a386Sopenharmony_ci auto roundingSpec = SkGlyphPositionRoundingSpec(false, kNone_SkAxisAlignment); 44cb93a386Sopenharmony_ci SkIPoint mask = roundingSpec.ignorePositionFieldMask; 45cb93a386Sopenharmony_ci for (int y = -testLimit; y < testLimit; y++) { 46cb93a386Sopenharmony_ci for (int x = -testLimit; x < testLimit; x++) { 47cb93a386Sopenharmony_ci float fx = x * step, fy = y * step; 48cb93a386Sopenharmony_ci SkPoint roundedPos = SkPoint{fx, fy} + roundingSpec.halfAxisSampleFreq; 49cb93a386Sopenharmony_ci SkPackedGlyphID packedID{3, roundedPos, mask}; 50cb93a386Sopenharmony_ci uint32_t subX = 0; 51cb93a386Sopenharmony_ci uint32_t subY = 0; 52cb93a386Sopenharmony_ci SkPackedGlyphID correctID(3, subX, subY); 53cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, packedID == correctID); 54cb93a386Sopenharmony_ci } 55cb93a386Sopenharmony_ci } 56cb93a386Sopenharmony_ci } 57cb93a386Sopenharmony_ci 58cb93a386Sopenharmony_ci { 59cb93a386Sopenharmony_ci // Subpixel with no axis snapping. 60cb93a386Sopenharmony_ci auto roundingSpec = SkGlyphPositionRoundingSpec(true, kNone_SkAxisAlignment); 61cb93a386Sopenharmony_ci SkIPoint mask = roundingSpec.ignorePositionFieldMask; 62cb93a386Sopenharmony_ci for (int y = -testLimit; y < testLimit; y++) { 63cb93a386Sopenharmony_ci for (int x = -testLimit; x < testLimit; x++) { 64cb93a386Sopenharmony_ci float fx = x * step, fy = y * step; 65cb93a386Sopenharmony_ci SkPoint roundedPos = SkPoint{fx, fy} + roundingSpec.halfAxisSampleFreq; 66cb93a386Sopenharmony_ci SkPackedGlyphID packedID{3, roundedPos, mask}; 67cb93a386Sopenharmony_ci uint32_t subX = freqRound(x); 68cb93a386Sopenharmony_ci uint32_t subY = freqRound(y); 69cb93a386Sopenharmony_ci SkPackedGlyphID correctID(3, subX, subY); 70cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, packedID == correctID); 71cb93a386Sopenharmony_ci } 72cb93a386Sopenharmony_ci } 73cb93a386Sopenharmony_ci } 74cb93a386Sopenharmony_ci 75cb93a386Sopenharmony_ci { 76cb93a386Sopenharmony_ci // Test dynamic range by transposing a large distance. 77cb93a386Sopenharmony_ci // Floating point numbers have 24 bits of precision. The largest distance is 24 - 2 (for 78cb93a386Sopenharmony_ci // sub-pixel) - 1 (for truncation to floor trick in the code). This leaves 21 bits. Large 79cb93a386Sopenharmony_ci // Distance is 2^21 - 2 (because the test is on the interval [-2, 2). 80cb93a386Sopenharmony_ci const uint32_t kLogLargeDistance = 24 - PG::kSubPixelPosLen - 1; 81cb93a386Sopenharmony_ci const int64_t kLargeDistance = (1ull << kLogLargeDistance) - 2; 82cb93a386Sopenharmony_ci auto roundingSpec = SkGlyphPositionRoundingSpec(true, kNone_SkAxisAlignment); 83cb93a386Sopenharmony_ci SkIPoint mask = roundingSpec.ignorePositionFieldMask; 84cb93a386Sopenharmony_ci for (int y = -32; y < 33; y++) { 85cb93a386Sopenharmony_ci for (int x = -32; x < 33; x++) { 86cb93a386Sopenharmony_ci float fx = x * step + kLargeDistance, fy = y * step + kLargeDistance; 87cb93a386Sopenharmony_ci SkPoint roundedPos = SkPoint{fx, fy} + roundingSpec.halfAxisSampleFreq; 88cb93a386Sopenharmony_ci SkPackedGlyphID packedID{3, roundedPos, mask}; 89cb93a386Sopenharmony_ci uint32_t subX = freqRound(x); 90cb93a386Sopenharmony_ci uint32_t subY = freqRound(y); 91cb93a386Sopenharmony_ci SkPackedGlyphID correctID(3, subX, subY); 92cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, packedID == correctID); 93cb93a386Sopenharmony_ci } 94cb93a386Sopenharmony_ci } 95cb93a386Sopenharmony_ci } 96cb93a386Sopenharmony_ci} 97cb93a386Sopenharmony_ci 98cb93a386Sopenharmony_ciDEF_TEST(SkSourceGlyphBufferBasic, reporter) { 99cb93a386Sopenharmony_ci SkSourceGlyphBuffer rejects; 100cb93a386Sopenharmony_ci // Positions are picked to avoid precision problems. 101cb93a386Sopenharmony_ci const SkPoint positions[] = {{10.25,10.25}, {20.5,10.25}, {30.75,10.25}, {40,10.25}}; 102cb93a386Sopenharmony_ci const SkGlyphID glyphIDs[] = {1, 2, 3, 4}; 103cb93a386Sopenharmony_ci auto source = SkMakeZip(glyphIDs, positions); 104cb93a386Sopenharmony_ci 105cb93a386Sopenharmony_ci rejects.setSource(source); 106cb93a386Sopenharmony_ci for (auto [i, glyphID, pos] : SkMakeEnumerate(rejects.source())) { 107cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, glyphID == std::get<0>(source[i])); 108cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, pos == std::get<1>(source[i])); 109cb93a386Sopenharmony_ci } 110cb93a386Sopenharmony_ci // Reject a couple of glyphs. 111cb93a386Sopenharmony_ci rejects.reject(1); 112cb93a386Sopenharmony_ci rejects.reject(2, 100); 113cb93a386Sopenharmony_ci rejects.flipRejectsToSource(); 114cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, rejects.rejectedMaxDimension() == 100); 115cb93a386Sopenharmony_ci for (auto [i, glyphID, pos] : SkMakeEnumerate(rejects.source())) { 116cb93a386Sopenharmony_ci // This will index 1 and 2 from the original source. 117cb93a386Sopenharmony_ci size_t j = i + 1; 118cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, glyphID == std::get<0>(source[j])); 119cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, pos == std::get<1>(source[j])); 120cb93a386Sopenharmony_ci } 121cb93a386Sopenharmony_ci 122cb93a386Sopenharmony_ci // Reject an additional glyph 123cb93a386Sopenharmony_ci rejects.reject(0, 10); 124cb93a386Sopenharmony_ci rejects.flipRejectsToSource(); 125cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, rejects.rejectedMaxDimension() == 10); 126cb93a386Sopenharmony_ci for (auto [i, glyphID, pos] : SkMakeEnumerate(rejects.source())) { 127cb93a386Sopenharmony_ci // This will index 1 from the original source. 128cb93a386Sopenharmony_ci size_t j = i + 1; 129cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, glyphID == std::get<0>(source[j])); 130cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, pos == std::get<1>(source[j])); 131cb93a386Sopenharmony_ci } 132cb93a386Sopenharmony_ci 133cb93a386Sopenharmony_ci // Start all over 134cb93a386Sopenharmony_ci rejects.setSource(source); 135cb93a386Sopenharmony_ci for (auto [i, glyphID, pos] : SkMakeEnumerate(rejects.source())) { 136cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, glyphID == std::get<0>(source[i])); 137cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, pos == std::get<1>(source[i])); 138cb93a386Sopenharmony_ci } 139cb93a386Sopenharmony_ci 140cb93a386Sopenharmony_ci // Check that everything is working after calling setSource. 141cb93a386Sopenharmony_ci rejects.reject(1); 142cb93a386Sopenharmony_ci rejects.reject(2, 100); 143cb93a386Sopenharmony_ci rejects.flipRejectsToSource(); 144cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, rejects.rejectedMaxDimension() == 100); 145cb93a386Sopenharmony_ci for (auto [i, glyphID, pos] : SkMakeEnumerate(rejects.source())) { 146cb93a386Sopenharmony_ci // This will index 1 and 2 from the original source. 147cb93a386Sopenharmony_ci size_t j = i + 1; 148cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, glyphID == std::get<0>(source[j])); 149cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, pos == std::get<1>(source[j])); 150cb93a386Sopenharmony_ci } 151cb93a386Sopenharmony_ci} 152cb93a386Sopenharmony_ci 153cb93a386Sopenharmony_ciDEF_TEST(SkDrawableGlyphBufferBasic, reporter) { 154cb93a386Sopenharmony_ci // Positions are picked to avoid precision problems. 155cb93a386Sopenharmony_ci const SkPoint positions[] = {{10.25,10.25}, {20.5,10.25}, {30.75,10.25}, {40,10.25}}; 156cb93a386Sopenharmony_ci const SkGlyphID glyphIDs[] = {1, 2, 3, 4}; 157cb93a386Sopenharmony_ci SkGlyph glyphs[100]; 158cb93a386Sopenharmony_ci auto source = SkMakeZip(glyphIDs, positions); 159cb93a386Sopenharmony_ci 160cb93a386Sopenharmony_ci { 161cb93a386Sopenharmony_ci SkDrawableGlyphBuffer drawable; 162cb93a386Sopenharmony_ci drawable.ensureSize(100); 163cb93a386Sopenharmony_ci drawable.startSource(source); 164cb93a386Sopenharmony_ci for (auto [i, packedID, pos] : SkMakeEnumerate(drawable.input())) { 165cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, packedID.packedID().glyphID() == glyphIDs[i]); 166cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, pos == positions[i]); 167cb93a386Sopenharmony_ci } 168cb93a386Sopenharmony_ci } 169cb93a386Sopenharmony_ci 170cb93a386Sopenharmony_ci { 171cb93a386Sopenharmony_ci SkDrawableGlyphBuffer drawable; 172cb93a386Sopenharmony_ci drawable.ensureSize(100); 173cb93a386Sopenharmony_ci SkMatrix matrix = SkMatrix::Scale(0.5, 0.5); 174cb93a386Sopenharmony_ci SkGlyphPositionRoundingSpec rounding{true, kX_SkAxisAlignment}; 175cb93a386Sopenharmony_ci drawable.startBitmapDevice(source, {100, 100}, matrix, rounding); 176cb93a386Sopenharmony_ci for (auto [i, packedID, pos] : SkMakeEnumerate(drawable.input())) { 177cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, glyphIDs[i] == packedID.packedID().glyphID()); 178cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 179cb93a386Sopenharmony_ci pos.x() == positions[i].x() * 0.5 + 50 + SkPackedGlyphID::kSubpixelRound); 180cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, pos.y() == positions[i].y() * 0.5 + 50 + 0.5); 181cb93a386Sopenharmony_ci } 182cb93a386Sopenharmony_ci } 183cb93a386Sopenharmony_ci 184cb93a386Sopenharmony_ci { 185cb93a386Sopenharmony_ci SkDrawableGlyphBuffer drawable; 186cb93a386Sopenharmony_ci drawable.ensureSize(100); 187cb93a386Sopenharmony_ci drawable.startSource(source); 188cb93a386Sopenharmony_ci for (auto [i, packedID, pos] : SkMakeEnumerate(drawable.input())) { 189cb93a386Sopenharmony_ci drawable.push_back(&glyphs[i], i); 190cb93a386Sopenharmony_ci } 191cb93a386Sopenharmony_ci for (auto [i, glyph, pos] : SkMakeEnumerate(drawable.drawable())) { 192cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, glyph.glyph() == &glyphs[i]); 193cb93a386Sopenharmony_ci } 194cb93a386Sopenharmony_ci } 195cb93a386Sopenharmony_ci} 196