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
DEF_TEST(Paint_copy,reporter)23 DEF_TEST(Paint_copy, reporter) {
24 SkPaint paint;
25 // set a few member variables
26 paint.setStyle(SkPaint::kStrokeAndFill_Style);
27 paint.setStrokeWidth(SkIntToScalar(2));
28 // set a few pointers
29 paint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle,
30 SkBlurMask::ConvertRadiusToSigma(1)));
31
32 // copy the paint using the copy constructor and check they are the same
33 SkPaint copiedPaint = paint;
34 REPORTER_ASSERT(reporter, paint == copiedPaint);
35
36 // copy the paint using the equal operator and check they are the same
37 copiedPaint = paint;
38 REPORTER_ASSERT(reporter, paint == copiedPaint);
39
40 // clean the paint and check they are back to their initial states
41 SkPaint cleanPaint;
42 paint.reset();
43 copiedPaint.reset();
44 REPORTER_ASSERT(reporter, cleanPaint == paint);
45 REPORTER_ASSERT(reporter, cleanPaint == copiedPaint);
46 }
47
48 // found and fixed for webkit: mishandling when we hit recursion limit on
49 // mostly degenerate cubic flatness test
DEF_TEST(Paint_regression_cubic,reporter)50 DEF_TEST(Paint_regression_cubic, reporter) {
51 SkPath path, stroke;
52 SkPaint paint;
53
54 path.moveTo(460.2881309415525f,
55 303.250847066498f);
56 path.cubicTo(463.36378422175284f,
57 302.1169735073363f,
58 456.32239330810046f,
59 304.720354932878f,
60 453.15255460013304f,
61 305.788586869862f);
62
63 SkRect fillR, strokeR;
64 fillR = path.getBounds();
65
66 paint.setStyle(SkPaint::kStroke_Style);
67 paint.setStrokeWidth(SkIntToScalar(2));
68 paint.getFillPath(path, &stroke);
69 strokeR = stroke.getBounds();
70
71 SkRect maxR = fillR;
72 SkScalar miter = std::max(SK_Scalar1, paint.getStrokeMiter());
73 SkScalar inset = paint.getStrokeJoin() == SkPaint::kMiter_Join ?
74 paint.getStrokeWidth() * miter :
75 paint.getStrokeWidth();
76 maxR.inset(-inset, -inset);
77
78 // test that our stroke didn't explode
79 REPORTER_ASSERT(reporter, maxR.contains(strokeR));
80 }
81
DEF_TEST(Paint_flattening,reporter)82 DEF_TEST(Paint_flattening, reporter) {
83 const SkPaint::Cap caps[] = {
84 SkPaint::kButt_Cap,
85 SkPaint::kRound_Cap,
86 SkPaint::kSquare_Cap,
87 };
88 const SkPaint::Join joins[] = {
89 SkPaint::kMiter_Join,
90 SkPaint::kRound_Join,
91 SkPaint::kBevel_Join,
92 };
93 const SkPaint::Style styles[] = {
94 SkPaint::kFill_Style,
95 SkPaint::kStroke_Style,
96 SkPaint::kStrokeAndFill_Style,
97 };
98
99 #define FOR_SETUP(index, array, setter) \
100 for (size_t index = 0; index < SK_ARRAY_COUNT(array); ++index) { \
101 paint.setter(array[index]);
102
103 SkPaint paint;
104 paint.setAntiAlias(true);
105
106 // we don't serialize hinting or encoding -- soon to be removed from paint
107
108 FOR_SETUP(l, caps, setStrokeCap)
109 FOR_SETUP(m, joins, setStrokeJoin)
110 FOR_SETUP(p, styles, setStyle)
111
112 SkBinaryWriteBuffer writer;
113 SkPaintPriv::Flatten(paint, writer);
114
115 SkAutoMalloc buf(writer.bytesWritten());
116 writer.writeToMemory(buf.get());
117 SkReadBuffer reader(buf.get(), writer.bytesWritten());
118
119 SkPaint paint2 = reader.readPaint();
120 REPORTER_ASSERT(reporter, paint2 == paint);
121
122 }}}
123 #undef FOR_SETUP
124
125 }
126
127 // found and fixed for android: not initializing rect for string's of length 0
128 DEF_TEST(Paint_regression_measureText, reporter) {
129
130 SkFont font;
131 font.setSize(12.0f);
132
133 SkRect r;
134 r.setLTRB(SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN);
135
136 // test that the rect was reset
137 font.measureText("", 0, SkTextEncoding::kUTF8, &r);
138 REPORTER_ASSERT(reporter, r.isEmpty());
139 }
140
141 #define ASSERT(expr) REPORTER_ASSERT(r, expr)
142
143 DEF_TEST(Paint_MoreFlattening, r) {
144 SkPaint paint;
145 paint.setColor(0x00AABBCC);
146 paint.setBlendMode(SkBlendMode::kModulate);
147
148 SkBinaryWriteBuffer writer;
149 SkPaintPriv::Flatten(paint, writer);
150
151 SkAutoMalloc buf(writer.bytesWritten());
152 writer.writeToMemory(buf.get());
153 SkReadBuffer reader(buf.get(), writer.bytesWritten());
154
155 SkPaint other = reader.readPaint();
156 ASSERT(reader.offset() == writer.bytesWritten());
157
158 // No matter the encoding, these must always hold.
159 ASSERT(other.getColor() == paint.getColor());
160 ASSERT(other.asBlendMode() == paint.asBlendMode());
161 }
162
163 #include "include/effects/SkColorMatrixFilter.h"
164
165 DEF_TEST(Paint_nothingToDraw, r) {
166 SkPaint paint;
167
168 REPORTER_ASSERT(r, !paint.nothingToDraw());
169 paint.setAlpha(0);
170 REPORTER_ASSERT(r, paint.nothingToDraw());
171
172 paint.setAlpha(0xFF);
173 paint.setBlendMode(SkBlendMode::kDst);
174 REPORTER_ASSERT(r, paint.nothingToDraw());
175
176 paint.setAlpha(0);
177 paint.setBlendMode(SkBlendMode::kSrcOver);
178
179 SkColorMatrix cm;
180 cm.setIdentity(); // does not change alpha
181 paint.setColorFilter(SkColorFilters::Matrix(cm));
182 REPORTER_ASSERT(r, paint.nothingToDraw());
183
184 cm.postTranslate(0, 0, 0, 1.0f/255); // wacks alpha
185 paint.setColorFilter(SkColorFilters::Matrix(cm));
186 REPORTER_ASSERT(r, !paint.nothingToDraw());
187 }
188
189 DEF_TEST(Font_getpos, r) {
190 SkFont font;
191 const char text[] = "Hamburgefons!@#!#23425,./;'[]";
192 int count = font.countText(text, strlen(text), SkTextEncoding::kUTF8);
193 SkAutoTArray<uint16_t> glyphStorage(count);
194 uint16_t* glyphs = glyphStorage.get();
195 (void)font.textToGlyphs(text, strlen(text), SkTextEncoding::kUTF8, glyphs, count);
196
197 SkAutoTArray<SkScalar> widthStorage(count);
198 SkAutoTArray<SkScalar> xposStorage(count);
199 SkAutoTArray<SkPoint> posStorage(count);
200
201 SkScalar* widths = widthStorage.get();
202 SkScalar* xpos = xposStorage.get();
203 SkPoint* pos = posStorage.get();
204
205 for (bool subpix : { false, true }) {
206 font.setSubpixel(subpix);
207 for (auto hint : { SkFontHinting::kNone, SkFontHinting::kSlight, SkFontHinting::kNormal, SkFontHinting::kFull}) {
208 font.setHinting(hint);
209 for (auto size : { 1.0f, 12.0f, 100.0f }) {
210 font.setSize(size);
211
212 font.getWidths(glyphs, count, widths);
213 font.getXPos(glyphs, count, xpos, 10);
214 font.getPos(glyphs, count, pos, {10, 20});
215
216 auto nearly_eq = [](SkScalar a, SkScalar b) {
217 return SkScalarAbs(a - b) < 0.000001f;
218 };
219
220 SkScalar x = 10;
221 for (int i = 0; i < count; ++i) {
222 REPORTER_ASSERT(r, nearly_eq(x, xpos[i]));
223 REPORTER_ASSERT(r, nearly_eq(x, pos[i].fX));
224 REPORTER_ASSERT(r, nearly_eq(20, pos[i].fY));
225 x += widths[i];
226 }
227 }
228 }
229 }
230 }
231
232 DEF_TEST(Paint_dither, reporter) {
233 SkPaint p;
234 p.setDither(true);
235
236 bool shouldDither = SkPaintPriv::ShouldDither(p, kBGRA_8888_SkColorType);
237
238 REPORTER_ASSERT(reporter, !shouldDither);
239 }
240