• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2011 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 "include/core/SkFont.h"
9 #include "include/core/SkMaskFilter.h"
10 #include "include/core/SkPath.h"
11 #include "include/core/SkTypeface.h"
12 #include "include/private/SkTo.h"
13 #include "include/utils/SkRandom.h"
14 #include "src/core/SkAutoMalloc.h"
15 #include "src/core/SkBlurMask.h"
16 #include "src/core/SkPaintPriv.h"
17 #include "src/core/SkReadBuffer.h"
18 #include "src/core/SkWriteBuffer.h"
19 #include "src/utils/SkUTF.h"
20 #include "tests/Test.h"
21 #undef ASSERT
22 
23 // temparary api for bicubic, just be sure we can set/clear it
DEF_TEST(Paint_filterQuality,reporter)24 DEF_TEST(Paint_filterQuality, reporter) {
25     SkPaint p0, p1;
26 
27     REPORTER_ASSERT(reporter, kNone_SkFilterQuality == p0.getFilterQuality());
28 
29     static const SkFilterQuality gQualitys[] = {
30         kNone_SkFilterQuality,
31         kLow_SkFilterQuality,
32         kMedium_SkFilterQuality,
33         kHigh_SkFilterQuality
34     };
35     for (size_t i = 0; i < SK_ARRAY_COUNT(gQualitys); ++i) {
36         p0.setFilterQuality(gQualitys[i]);
37         REPORTER_ASSERT(reporter, gQualitys[i] == p0.getFilterQuality());
38         p1 = p0;
39         REPORTER_ASSERT(reporter, gQualitys[i] == p1.getFilterQuality());
40 
41         p0.reset();
42         REPORTER_ASSERT(reporter, kNone_SkFilterQuality == p0.getFilterQuality());
43     }
44 }
45 
DEF_TEST(Paint_copy,reporter)46 DEF_TEST(Paint_copy, reporter) {
47     SkPaint paint;
48     // set a few member variables
49     paint.setStyle(SkPaint::kStrokeAndFill_Style);
50     paint.setStrokeWidth(SkIntToScalar(2));
51     // set a few pointers
52     paint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle,
53                                                SkBlurMask::ConvertRadiusToSigma(1)));
54 
55     // copy the paint using the copy constructor and check they are the same
56     SkPaint copiedPaint = paint;
57     REPORTER_ASSERT(reporter, paint.getHash() == copiedPaint.getHash());
58     REPORTER_ASSERT(reporter, paint == copiedPaint);
59 
60     // copy the paint using the equal operator and check they are the same
61     copiedPaint = paint;
62     REPORTER_ASSERT(reporter, paint == copiedPaint);
63 
64     // clean the paint and check they are back to their initial states
65     SkPaint cleanPaint;
66     paint.reset();
67     copiedPaint.reset();
68     REPORTER_ASSERT(reporter, cleanPaint == paint);
69     REPORTER_ASSERT(reporter, cleanPaint == copiedPaint);
70 }
71 
72 // found and fixed for webkit: mishandling when we hit recursion limit on
73 // mostly degenerate cubic flatness test
DEF_TEST(Paint_regression_cubic,reporter)74 DEF_TEST(Paint_regression_cubic, reporter) {
75     SkPath path, stroke;
76     SkPaint paint;
77 
78     path.moveTo(460.2881309415525f,
79                 303.250847066498f);
80     path.cubicTo(463.36378422175284f,
81                  302.1169735073363f,
82                  456.32239330810046f,
83                  304.720354932878f,
84                  453.15255460013304f,
85                  305.788586869862f);
86 
87     SkRect fillR, strokeR;
88     fillR = path.getBounds();
89 
90     paint.setStyle(SkPaint::kStroke_Style);
91     paint.setStrokeWidth(SkIntToScalar(2));
92     paint.getFillPath(path, &stroke);
93     strokeR = stroke.getBounds();
94 
95     SkRect maxR = fillR;
96     SkScalar miter = SkMaxScalar(SK_Scalar1, paint.getStrokeMiter());
97     SkScalar inset = paint.getStrokeJoin() == SkPaint::kMiter_Join ?
98                             paint.getStrokeWidth() * miter :
99                             paint.getStrokeWidth();
100     maxR.inset(-inset, -inset);
101 
102     // test that our stroke didn't explode
103     REPORTER_ASSERT(reporter, maxR.contains(strokeR));
104 }
105 
DEF_TEST(Paint_flattening,reporter)106 DEF_TEST(Paint_flattening, reporter) {
107     const SkFilterQuality levels[] = {
108         kNone_SkFilterQuality,
109         kLow_SkFilterQuality,
110         kMedium_SkFilterQuality,
111         kHigh_SkFilterQuality,
112     };
113     const SkPaint::Cap caps[] = {
114         SkPaint::kButt_Cap,
115         SkPaint::kRound_Cap,
116         SkPaint::kSquare_Cap,
117     };
118     const SkPaint::Join joins[] = {
119         SkPaint::kMiter_Join,
120         SkPaint::kRound_Join,
121         SkPaint::kBevel_Join,
122     };
123     const SkPaint::Style styles[] = {
124         SkPaint::kFill_Style,
125         SkPaint::kStroke_Style,
126         SkPaint::kStrokeAndFill_Style,
127     };
128 
129 #define FOR_SETUP(index, array, setter)                                 \
130     for (size_t index = 0; index < SK_ARRAY_COUNT(array); ++index) {    \
131         paint.setter(array[index]);
132 
133     SkPaint paint;
134     paint.setAntiAlias(true);
135 
136     // we don't serialize hinting or encoding -- soon to be removed from paint
137 
138     FOR_SETUP(i, levels, setFilterQuality)
139     FOR_SETUP(l, caps, setStrokeCap)
140     FOR_SETUP(m, joins, setStrokeJoin)
141     FOR_SETUP(p, styles, setStyle)
142 
143     SkBinaryWriteBuffer writer;
144     SkPaintPriv::Flatten(paint, writer);
145 
146     SkAutoMalloc buf(writer.bytesWritten());
147     writer.writeToMemory(buf.get());
148     SkReadBuffer reader(buf.get(), writer.bytesWritten());
149 
150     SkPaint paint2;
151     SkPaintPriv::Unflatten(&paint2, reader, nullptr);
152     REPORTER_ASSERT(reporter, paint2 == paint);
153 
154     }}}}
155 #undef FOR_SETUP
156 
157 }
158 
159 // found and fixed for android: not initializing rect for string's of length 0
160 DEF_TEST(Paint_regression_measureText, reporter) {
161 
162     SkFont font;
163     font.setSize(12.0f);
164 
165     SkRect r;
166     r.setLTRB(SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN);
167 
168     // test that the rect was reset
169     font.measureText("", 0, SkTextEncoding::kUTF8, &r);
170     REPORTER_ASSERT(reporter, r.isEmpty());
171 }
172 
173 #define ASSERT(expr) REPORTER_ASSERT(r, expr)
174 
175 DEF_TEST(Paint_MoreFlattening, r) {
176     SkPaint paint;
177     paint.setColor(0x00AABBCC);
178     paint.setBlendMode(SkBlendMode::kModulate);
179 
180     SkBinaryWriteBuffer writer;
181     SkPaintPriv::Flatten(paint, writer);
182 
183     SkAutoMalloc buf(writer.bytesWritten());
184     writer.writeToMemory(buf.get());
185     SkReadBuffer reader(buf.get(), writer.bytesWritten());
186 
187     SkPaint other;
188     SkPaintPriv::Unflatten(&other, reader, nullptr);
189     ASSERT(reader.offset() == writer.bytesWritten());
190 
191     // No matter the encoding, these must always hold.
192     ASSERT(other.getColor()      == paint.getColor());
193     ASSERT(other.getBlendMode()  == paint.getBlendMode());
194 }
195 
196 DEF_TEST(Paint_getHash, r) {
197     // Try not to inspect the actual hash values in here.
198     // We might want to change the hash function.
199 
200     SkPaint paint;
201     const uint32_t defaultHash = paint.getHash();
202 
203     // Check that some arbitrary field affects the hash.
204     paint.setColor(0xFF00FF00);
205     REPORTER_ASSERT(r, paint.getHash() != defaultHash);
206     paint.setColor(SK_ColorBLACK);  // Reset to default value.
207     REPORTER_ASSERT(r, paint.getHash() == defaultHash);
208 
209     // This is part of fBitfields, the last field we hash.
210     paint.setBlendMode(SkBlendMode::kSrc);
211     REPORTER_ASSERT(r, paint.getHash() != defaultHash);
212     paint.setBlendMode(SkBlendMode::kSrcOver);
213     REPORTER_ASSERT(r, paint.getHash() == defaultHash);
214 }
215 
216 #include "include/effects/SkColorMatrixFilter.h"
217 
218 DEF_TEST(Paint_nothingToDraw, r) {
219     SkPaint paint;
220 
221     REPORTER_ASSERT(r, !paint.nothingToDraw());
222     paint.setAlpha(0);
223     REPORTER_ASSERT(r, paint.nothingToDraw());
224 
225     paint.setAlpha(0xFF);
226     paint.setBlendMode(SkBlendMode::kDst);
227     REPORTER_ASSERT(r, paint.nothingToDraw());
228 
229     paint.setAlpha(0);
230     paint.setBlendMode(SkBlendMode::kSrcOver);
231 
232     SkColorMatrix cm;
233     cm.setIdentity();   // does not change alpha
234     paint.setColorFilter(SkColorFilters::Matrix(cm));
235     REPORTER_ASSERT(r, paint.nothingToDraw());
236 
237     cm.postTranslate(0, 0, 0, 1.0f/255);    // wacks alpha
238     paint.setColorFilter(SkColorFilters::Matrix(cm));
239     REPORTER_ASSERT(r, !paint.nothingToDraw());
240 }
241 
242 DEF_TEST(Font_getpos, r) {
243     SkFont font;
244     const char text[] = "Hamburgefons!@#!#23425,./;'[]";
245     int count = font.countText(text, strlen(text), SkTextEncoding::kUTF8);
246     SkAutoTArray<uint16_t> glyphStorage(count);
247     uint16_t* glyphs = glyphStorage.get();
248     (void)font.textToGlyphs(text, strlen(text), SkTextEncoding::kUTF8, glyphs, count);
249 
250     SkAutoTArray<SkScalar> widthStorage(count);
251     SkAutoTArray<SkScalar> xposStorage(count);
252     SkAutoTArray<SkPoint> posStorage(count);
253 
254     SkScalar* widths = widthStorage.get();
255     SkScalar* xpos = xposStorage.get();
256     SkPoint* pos = posStorage.get();
257 
258     for (bool subpix : { false, true }) {
259         font.setSubpixel(subpix);
260         for (auto hint : { SkFontHinting::kNone, SkFontHinting::kSlight, SkFontHinting::kNormal, SkFontHinting::kFull}) {
261             font.setHinting(hint);
262             for (auto size : { 1.0f, 12.0f, 100.0f }) {
263                 font.setSize(size);
264 
265                 font.getWidths(glyphs, count, widths);
266                 font.getXPos(glyphs, count, xpos, 10);
267                 font.getPos(glyphs, count, pos, {10, 20});
268 
269                 auto nearly_eq = [](SkScalar a, SkScalar b) {
270                     return SkScalarAbs(a - b) < 0.000001f;
271                 };
272 
273                 SkScalar x = 10;
274                 for (int i = 0; i < count; ++i) {
275                     REPORTER_ASSERT(r, nearly_eq(x,  xpos[i]));
276                     REPORTER_ASSERT(r, nearly_eq(x,   pos[i].fX));
277                     REPORTER_ASSERT(r, nearly_eq(20,  pos[i].fY));
278                     x += widths[i];
279                 }
280             }
281         }
282     }
283 }
284