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