1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <gtest/gtest.h>
18
19 #include "minikin/BoundsCache.h"
20
21 #include "FontTestUtils.h"
22 #include "LocaleListCache.h"
23 #include "UnicodeUtils.h"
24
25 namespace minikin {
26
27 class TestableBoundsCache : public BoundsCache {
28 public:
TestableBoundsCache(uint32_t maxEntries)29 TestableBoundsCache(uint32_t maxEntries) : BoundsCache(maxEntries) {}
30 };
31
32 class BoundsCapture {
33 public:
BoundsCapture()34 BoundsCapture() {}
35
operator ()(const MinikinRect & rect,float advance)36 void operator()(const MinikinRect& rect, float advance) {
37 mRect = rect;
38 mAdvance = advance;
39 }
40
rect() const41 const MinikinRect& rect() const { return mRect; }
advance() const42 float advance() const { return mAdvance; }
43
44 private:
45 MinikinRect mRect;
46 float mAdvance;
47 };
48
TEST(BoundsCacheTest,cacheHitTest)49 TEST(BoundsCacheTest, cacheHitTest) {
50 auto text = utf8ToUtf16("android");
51 Range range(0, text.size());
52 MinikinPaint paint(buildFontCollection("Ascii.ttf"));
53
54 TestableBoundsCache boundsCache(10);
55
56 BoundsCapture bounds1;
57 boundsCache.getOrCreate(text, range, paint, false /* LTR */, StartHyphenEdit::NO_EDIT,
58 EndHyphenEdit::NO_EDIT, bounds1);
59
60 BoundsCapture bounds2;
61 boundsCache.getOrCreate(text, range, paint, false /* LTR */, StartHyphenEdit::NO_EDIT,
62 EndHyphenEdit::NO_EDIT, bounds2);
63
64 EXPECT_EQ(bounds1.rect(), bounds2.rect());
65 EXPECT_EQ(bounds1.advance(), bounds2.advance());
66 }
67
TEST(BoundsCacheTest,cacheMissTest)68 TEST(BoundsCacheTest, cacheMissTest) {
69 auto text1 = utf8ToUtf16("android");
70 auto text2 = utf8ToUtf16("αβγδζ");
71 MinikinPaint paint(buildFontCollection("Ascii.ttf"));
72
73 TestableBoundsCache boundsCache(10);
74
75 BoundsCapture bounds1;
76 BoundsCapture bounds2;
77
78 {
79 SCOPED_TRACE("Different text");
80 boundsCache.getOrCreate(text1, Range(0, text1.size()), paint, false /* LTR */,
81 StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds1);
82 boundsCache.getOrCreate(text2, Range(0, text2.size()), paint, false /* LTR */,
83 StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds2);
84 EXPECT_NE(bounds1.rect(), bounds2.rect());
85 EXPECT_NE(bounds1.advance(), bounds2.advance());
86 }
87 {
88 SCOPED_TRACE("Different range");
89 boundsCache.getOrCreate(text1, Range(0, text1.size()), paint, false /* LTR */,
90 StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds1);
91 boundsCache.getOrCreate(text1, Range(1, text1.size()), paint, false /* LTR */,
92 StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds2);
93 EXPECT_NE(bounds1.rect(), bounds2.rect());
94 EXPECT_NE(bounds1.advance(), bounds2.advance());
95 }
96 {
97 SCOPED_TRACE("Different collection");
98 MinikinPaint paint1(buildFontCollection("Ascii.ttf"));
99 paint1.size = 10.0f;
100 paint1.scaleX = 1.0f;
101 boundsCache.getOrCreate(text1, Range(0, text1.size()), paint1, false /* LTR */,
102 StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds1);
103 MinikinPaint paint2(buildFontCollection("Emoji.ttf"));
104 paint2.size = 10.0f;
105 paint2.scaleX = 1.0f;
106 boundsCache.getOrCreate(text1, Range(0, text1.size()), paint2, false /* LTR */,
107 StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds2);
108 EXPECT_NE(bounds1.rect(), bounds2.rect());
109 EXPECT_NE(bounds1.advance(), bounds2.advance());
110 }
111 {
112 SCOPED_TRACE("Different size");
113 auto collection = buildFontCollection("Ascii.ttf");
114 MinikinPaint paint1(collection);
115 paint1.size = 10.0f;
116 paint1.scaleX = 1.0f;
117 boundsCache.getOrCreate(text1, Range(0, text1.size()), paint1, false /* LTR */,
118 StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds1);
119 MinikinPaint paint2(collection);
120 paint2.size = 20.0f;
121 paint2.scaleX = 1.0f;
122 boundsCache.getOrCreate(text1, Range(0, text1.size()), paint2, false /* LTR */,
123 StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds2);
124 EXPECT_NE(bounds1.rect(), bounds2.rect());
125 EXPECT_NE(bounds1.advance(), bounds2.advance());
126 }
127 {
128 SCOPED_TRACE("Different letter spacing");
129 auto collection = buildFontCollection("Ascii.ttf");
130 MinikinPaint paint1(collection);
131 paint1.letterSpacing = 0.0f;
132 paint1.size = 10.0f;
133 paint1.scaleX = 1.0f;
134 boundsCache.getOrCreate(text1, Range(0, text1.size()), paint1, false /* LTR */,
135 StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds1);
136 MinikinPaint paint2(collection);
137 paint2.letterSpacing = 1.0f;
138 paint2.size = 10.0f;
139 paint2.scaleX = 1.0f;
140 boundsCache.getOrCreate(text1, Range(0, text1.size()), paint2, false /* LTR */,
141 StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds2);
142 EXPECT_NE(bounds1.rect(), bounds2.rect());
143 EXPECT_NE(bounds1.advance(), bounds2.advance());
144 }
145 }
146
TEST(BoundsCacheTest,cacheOverflowTest)147 TEST(BoundsCacheTest, cacheOverflowTest) {
148 auto text = utf8ToUtf16("android");
149 Range range(0, text.size());
150 MinikinPaint paint(buildFontCollection("Ascii.ttf"));
151
152 TestableBoundsCache boundsCache(5);
153
154 BoundsCapture bounds1;
155 boundsCache.getOrCreate(text, range, paint, false /* LTR */, StartHyphenEdit::NO_EDIT,
156 EndHyphenEdit::NO_EDIT, bounds1);
157
158 for (char c = 'a'; c <= 'z'; c++) {
159 auto text1 = utf8ToUtf16(std::string(10, c));
160 BoundsCapture bounds2;
161 boundsCache.getOrCreate(text1, Range(0, text1.size()), paint, false /* LTR */,
162 StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, bounds2);
163 }
164
165 BoundsCapture bounds3;
166 boundsCache.getOrCreate(text, range, paint, false /* LTR */, StartHyphenEdit::NO_EDIT,
167 EndHyphenEdit::NO_EDIT, bounds3);
168 EXPECT_EQ(bounds1.rect(), bounds3.rect());
169 EXPECT_EQ(bounds1.advance(), bounds3.advance());
170 }
171
172 } // namespace minikin
173