blob: 77c4c740a09bd313f438d36ad73f4579fefbadf0 [file] [log] [blame]
Herbert Derby0be4c2c2019-10-09 12:26:56 -04001/*
2 * Copyright 2019 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "src/core/SkEnumerate.h"
9#include "src/core/SkGlyphBuffer.h"
10#include "src/core/SkGlyphRunPainter.h"
11#include "src/core/SkScalerContext.h"
12#include "tests/Test.h"
13
Herb Derbyf5ad3f42019-10-30 16:33:16 -040014DEF_TEST(SkPackedGlyphIDCtor, reporter) {
Herb Derby29597492019-11-06 15:47:43 -050015 using PG = SkPackedGlyphID;
16 // x and y are in one quarter the sub-pixel sampling frequency.
17 // Number of steps on the interval [0, 1)
18 const int perUnit = 1u << (PG::kSubPixelPosLen + 2);
19 const float step = 1.f / perUnit;
20 const int testLimit = 2 * perUnit;
21 auto freqRound = [](uint32_t x) -> uint32_t {
22 return ((x + 2) >> 2) & PG::kSubPixelPosMask;
23 };
24
Herb Derbyf5ad3f42019-10-30 16:33:16 -040025 {
26 // Normal sub-pixel with y-axis snapping.
27 auto roundingSpec = SkGlyphPositionRoundingSpec(true, kX_SkAxisAlignment);
28 SkIPoint mask = roundingSpec.ignorePositionFieldMask;
Herb Derby29597492019-11-06 15:47:43 -050029 for (int x = -testLimit; x < testLimit; x++) {
30 float fx = x * step;
31 SkPoint roundedPos = SkPoint{fx, 0} + roundingSpec.halfAxisSampleFreq;
32 SkPackedGlyphID packedID{3, roundedPos, mask};
33 uint32_t subX = freqRound(x);
34 uint32_t subY = 0;
35 SkPackedGlyphID correctID(3, subX, subY);
36 SkASSERT(packedID == correctID);
37 REPORTER_ASSERT(reporter, packedID == correctID);
Herb Derbyf5ad3f42019-10-30 16:33:16 -040038 }
39 }
40
41 {
Herb Derbyf7ce19e2019-11-06 13:04:54 -050042 // No subpixel positioning.
43 auto roundingSpec = SkGlyphPositionRoundingSpec(false, kNone_SkAxisAlignment);
44 SkIPoint mask = roundingSpec.ignorePositionFieldMask;
Herb Derby29597492019-11-06 15:47:43 -050045 for (int y = -testLimit; y < testLimit; y++) {
46 for (int x = -testLimit; x < testLimit; x++) {
Herb Derbyf7ce19e2019-11-06 13:04:54 -050047 float fx = x * step, fy = y * step;
48 SkPoint roundedPos = SkPoint{fx, fy} + roundingSpec.halfAxisSampleFreq;
49 SkPackedGlyphID packedID{3, roundedPos, mask};
Herb Derby29597492019-11-06 15:47:43 -050050 uint32_t subX = 0;
51 uint32_t subY = 0;
Herb Derbyf7ce19e2019-11-06 13:04:54 -050052 SkPackedGlyphID correctID(3, subX, subY);
53 REPORTER_ASSERT(reporter, packedID == correctID);
54 }
55 }
56 }
57
58 {
Herb Derbyf5ad3f42019-10-30 16:33:16 -040059 // Subpixel with no axis snapping.
60 auto roundingSpec = SkGlyphPositionRoundingSpec(true, kNone_SkAxisAlignment);
61 SkIPoint mask = roundingSpec.ignorePositionFieldMask;
Herb Derby29597492019-11-06 15:47:43 -050062 for (int y = -testLimit; y < testLimit; y++) {
63 for (int x = -testLimit; x < testLimit; x++) {
Herb Derbyf5ad3f42019-10-30 16:33:16 -040064 float fx = x * step, fy = y * step;
65 SkPoint roundedPos = SkPoint{fx, fy} + roundingSpec.halfAxisSampleFreq;
66 SkPackedGlyphID packedID{3, roundedPos, mask};
Herb Derby29597492019-11-06 15:47:43 -050067 uint32_t subX = freqRound(x);
68 uint32_t subY = freqRound(y);
Herb Derbyf5ad3f42019-10-30 16:33:16 -040069 SkPackedGlyphID correctID(3, subX, subY);
70 REPORTER_ASSERT(reporter, packedID == correctID);
71 }
72 }
73 }
74
75 {
Herb Derbyf7ce19e2019-11-06 13:04:54 -050076 // Test dynamic range by transposing a large distance.
77 // Floating point numbers have 24 bits of precision. The largest distance is 24 - 2 (for
78 // sub-pixel) - 1 (for truncation to floor trick in the code). This leaves 21 bits. Large
79 // Distance is 2^21 - 2 (because the test is on the interval [-2, 2).
Herb Derby29597492019-11-06 15:47:43 -050080 const uint32_t kLogLargeDistance = 24 - PG::kSubPixelPosLen - 1;
81 const int64_t kLargeDistance = (1ull << kLogLargeDistance) - 2;
Herb Derbyf7ce19e2019-11-06 13:04:54 -050082 auto roundingSpec = SkGlyphPositionRoundingSpec(true, kNone_SkAxisAlignment);
Herb Derbyf5ad3f42019-10-30 16:33:16 -040083 SkIPoint mask = roundingSpec.ignorePositionFieldMask;
84 for (int y = -32; y < 33; y++) {
85 for (int x = -32; x < 33; x++) {
Herb Derbyf7ce19e2019-11-06 13:04:54 -050086 float fx = x * step + kLargeDistance, fy = y * step + kLargeDistance;
Herb Derbyf5ad3f42019-10-30 16:33:16 -040087 SkPoint roundedPos = SkPoint{fx, fy} + roundingSpec.halfAxisSampleFreq;
88 SkPackedGlyphID packedID{3, roundedPos, mask};
Herb Derby29597492019-11-06 15:47:43 -050089 uint32_t subX = freqRound(x);
90 uint32_t subY = freqRound(y);
Herb Derbyf5ad3f42019-10-30 16:33:16 -040091 SkPackedGlyphID correctID(3, subX, subY);
92 REPORTER_ASSERT(reporter, packedID == correctID);
93 }
94 }
95 }
96}
Herbert Derbyd7689d42019-10-11 10:56:31 -040097
98DEF_TEST(SkSourceGlyphBufferBasic, reporter) {
99 SkSourceGlyphBuffer rejects;
100 // Positions are picked to avoid precision problems.
101 const SkPoint positions[] = {{10.25,10.25}, {20.5,10.25}, {30.75,10.25}, {40,10.25}};
102 const SkGlyphID glyphIDs[] = {1, 2, 3, 4};
103 auto source = SkMakeZip(glyphIDs, positions);
104
105 rejects.setSource(source);
Herb Derby81777ac2019-11-14 13:51:43 -0500106 for (auto [i, glyphID, pos] : SkMakeEnumerate(rejects.source())) {
Herbert Derbyd7689d42019-10-11 10:56:31 -0400107 REPORTER_ASSERT(reporter, glyphID == std::get<0>(source[i]));
108 REPORTER_ASSERT(reporter, pos == std::get<1>(source[i]));
109 }
110 // Reject a couple of glyphs.
111 rejects.reject(1);
112 rejects.reject(2, 100);
113 rejects.flipRejectsToSource();
114 REPORTER_ASSERT(reporter, rejects.rejectedMaxDimension() == 100);
Herb Derby81777ac2019-11-14 13:51:43 -0500115 for (auto [i, glyphID, pos] : SkMakeEnumerate(rejects.source())) {
Herbert Derbyd7689d42019-10-11 10:56:31 -0400116 // This will index 1 and 2 from the original source.
117 size_t j = i + 1;
118 REPORTER_ASSERT(reporter, glyphID == std::get<0>(source[j]));
119 REPORTER_ASSERT(reporter, pos == std::get<1>(source[j]));
120 }
121
122 // Reject an additional glyph
123 rejects.reject(0, 10);
124 rejects.flipRejectsToSource();
125 REPORTER_ASSERT(reporter, rejects.rejectedMaxDimension() == 10);
Herb Derby81777ac2019-11-14 13:51:43 -0500126 for (auto [i, glyphID, pos] : SkMakeEnumerate(rejects.source())) {
Herbert Derbyd7689d42019-10-11 10:56:31 -0400127 // This will index 1 from the original source.
128 size_t j = i + 1;
129 REPORTER_ASSERT(reporter, glyphID == std::get<0>(source[j]));
130 REPORTER_ASSERT(reporter, pos == std::get<1>(source[j]));
131 }
132
133 // Start all over
134 rejects.setSource(source);
Herb Derby81777ac2019-11-14 13:51:43 -0500135 for (auto [i, glyphID, pos] : SkMakeEnumerate(rejects.source())) {
Herbert Derbyd7689d42019-10-11 10:56:31 -0400136 REPORTER_ASSERT(reporter, glyphID == std::get<0>(source[i]));
137 REPORTER_ASSERT(reporter, pos == std::get<1>(source[i]));
138 }
139
140 // Check that everything is working after calling setSource.
141 rejects.reject(1);
142 rejects.reject(2, 100);
143 rejects.flipRejectsToSource();
144 REPORTER_ASSERT(reporter, rejects.rejectedMaxDimension() == 100);
Herb Derby81777ac2019-11-14 13:51:43 -0500145 for (auto [i, glyphID, pos] : SkMakeEnumerate(rejects.source())) {
Herbert Derbyd7689d42019-10-11 10:56:31 -0400146 // This will index 1 and 2 from the original source.
147 size_t j = i + 1;
148 REPORTER_ASSERT(reporter, glyphID == std::get<0>(source[j]));
149 REPORTER_ASSERT(reporter, pos == std::get<1>(source[j]));
150 }
151}
152
Herbert Derby0be4c2c2019-10-09 12:26:56 -0400153DEF_TEST(SkDrawableGlyphBufferBasic, reporter) {
154 // Positions are picked to avoid precision problems.
155 const SkPoint positions[] = {{10.25,10.25}, {20.5,10.25}, {30.75,10.25}, {40,10.25}};
156 const SkGlyphID glyphIDs[] = {1, 2, 3, 4};
157 SkGlyph glyphs[100];
158 auto source = SkMakeZip(glyphIDs, positions);
159
160 {
161 SkDrawableGlyphBuffer drawable;
162 drawable.ensureSize(100);
Herb Derby79c56742020-05-14 12:26:25 -0400163 drawable.startSource(source);
Herb Derby81777ac2019-11-14 13:51:43 -0500164 for (auto [i, packedID, pos] : SkMakeEnumerate(drawable.input())) {
Herb Derbyc7a8df82019-10-30 11:58:18 -0400165 REPORTER_ASSERT(reporter, packedID.packedID().glyphID() == glyphIDs[i]);
Herb Derby79c56742020-05-14 12:26:25 -0400166 REPORTER_ASSERT(reporter, pos == positions[i]);
Herbert Derby0be4c2c2019-10-09 12:26:56 -0400167 }
168 }
169
170 {
171 SkDrawableGlyphBuffer drawable;
172 drawable.ensureSize(100);
173 SkMatrix matrix = SkMatrix::MakeScale(0.5);
174 SkGlyphPositionRoundingSpec rounding{true, kX_SkAxisAlignment};
Herb Derbye7825ff2020-05-15 10:08:49 -0400175 drawable.startBitmapDevice(source, {100, 100}, matrix, rounding);
Herb Derby81777ac2019-11-14 13:51:43 -0500176 for (auto [i, packedID, pos] : SkMakeEnumerate(drawable.input())) {
Herb Derby95ea4c42019-09-30 16:26:52 -0400177 REPORTER_ASSERT(reporter, glyphIDs[i] == packedID.packedID().glyphID());
Herb Derby29597492019-11-06 15:47:43 -0500178 REPORTER_ASSERT(reporter,
179 pos.x() == positions[i].x() * 0.5 + 50 + SkPackedGlyphID::kSubpixelRound);
Herbert Derby0be4c2c2019-10-09 12:26:56 -0400180 REPORTER_ASSERT(reporter, pos.y() == positions[i].y() * 0.5 + 50 + 0.5);
181 }
182 }
183
184 {
185 SkDrawableGlyphBuffer drawable;
186 drawable.ensureSize(100);
Herb Derby79c56742020-05-14 12:26:25 -0400187 drawable.startSource(source);
Herb Derby81777ac2019-11-14 13:51:43 -0500188 for (auto [i, packedID, pos] : SkMakeEnumerate(drawable.input())) {
Herbert Derby0be4c2c2019-10-09 12:26:56 -0400189 drawable.push_back(&glyphs[i], i);
190 }
Herb Derby81777ac2019-11-14 13:51:43 -0500191 for (auto [i, glyph, pos] : SkMakeEnumerate(drawable.drawable())) {
Herbert Derby0be4c2c2019-10-09 12:26:56 -0400192 REPORTER_ASSERT(reporter, glyph.glyph() == &glyphs[i]);
193 }
194 }
195}