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