1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2011 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "include/core/SkBitmap.h"
9cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h"
10cb93a386Sopenharmony_ci#include "include/core/SkColor.h"
11cb93a386Sopenharmony_ci#include "include/core/SkFont.h"
12cb93a386Sopenharmony_ci#include "include/core/SkMatrix.h"
13cb93a386Sopenharmony_ci#include "include/core/SkPaint.h"
14cb93a386Sopenharmony_ci#include "include/core/SkPathEffect.h"
15cb93a386Sopenharmony_ci#include "include/core/SkPoint.h"
16cb93a386Sopenharmony_ci#include "include/core/SkRect.h"
17cb93a386Sopenharmony_ci#include "include/core/SkRefCnt.h"
18cb93a386Sopenharmony_ci#include "include/core/SkScalar.h"
19cb93a386Sopenharmony_ci#include "include/core/SkSurface.h"
20cb93a386Sopenharmony_ci#include "include/core/SkTextBlob.h"
21cb93a386Sopenharmony_ci#include "include/core/SkTypeface.h"
22cb93a386Sopenharmony_ci#include "include/core/SkTypes.h"
23cb93a386Sopenharmony_ci#include "include/effects/SkDashPathEffect.h"
24cb93a386Sopenharmony_ci#include "tests/Test.h"
25cb93a386Sopenharmony_ci
26cb93a386Sopenharmony_ci#include <cmath>
27cb93a386Sopenharmony_ci
28cb93a386Sopenharmony_cistatic const SkColor bgColor = SK_ColorWHITE;
29cb93a386Sopenharmony_ci
30cb93a386Sopenharmony_cistatic void create(SkBitmap* bm, SkIRect bound) {
31cb93a386Sopenharmony_ci    bm->allocN32Pixels(bound.width(), bound.height());
32cb93a386Sopenharmony_ci}
33cb93a386Sopenharmony_ci
34cb93a386Sopenharmony_ci/** Assumes that the ref draw was completely inside ref canvas --
35cb93a386Sopenharmony_ci    implies that everything outside is "bgColor".
36cb93a386Sopenharmony_ci    Checks that all overlap is the same and that all non-overlap on the
37cb93a386Sopenharmony_ci    ref is "bgColor".
38cb93a386Sopenharmony_ci */
39cb93a386Sopenharmony_cistatic bool compare(const SkBitmap& ref, const SkIRect& iref,
40cb93a386Sopenharmony_ci                    const SkBitmap& test, const SkIRect& itest)
41cb93a386Sopenharmony_ci{
42cb93a386Sopenharmony_ci    const int xOff = itest.fLeft - iref.fLeft;
43cb93a386Sopenharmony_ci    const int yOff = itest.fTop - iref.fTop;
44cb93a386Sopenharmony_ci
45cb93a386Sopenharmony_ci    for (int y = 0; y < test.height(); ++y) {
46cb93a386Sopenharmony_ci        for (int x = 0; x < test.width(); ++x) {
47cb93a386Sopenharmony_ci            SkColor testColor = test.getColor(x, y);
48cb93a386Sopenharmony_ci            int refX = x + xOff;
49cb93a386Sopenharmony_ci            int refY = y + yOff;
50cb93a386Sopenharmony_ci            SkColor refColor;
51cb93a386Sopenharmony_ci            if (refX >= 0 && refX < ref.width() &&
52cb93a386Sopenharmony_ci                refY >= 0 && refY < ref.height())
53cb93a386Sopenharmony_ci            {
54cb93a386Sopenharmony_ci                refColor = ref.getColor(refX, refY);
55cb93a386Sopenharmony_ci            } else {
56cb93a386Sopenharmony_ci                refColor = bgColor;
57cb93a386Sopenharmony_ci            }
58cb93a386Sopenharmony_ci            if (refColor != testColor) {
59cb93a386Sopenharmony_ci                return false;
60cb93a386Sopenharmony_ci            }
61cb93a386Sopenharmony_ci        }
62cb93a386Sopenharmony_ci    }
63cb93a386Sopenharmony_ci    return true;
64cb93a386Sopenharmony_ci}
65cb93a386Sopenharmony_ci
66cb93a386Sopenharmony_ci/** Test that drawing glyphs with empty paths is different from drawing glyphs without paths. */
67cb93a386Sopenharmony_ciDEF_TEST(DrawText_dashout, reporter) {
68cb93a386Sopenharmony_ci    SkIRect size = SkIRect::MakeWH(64, 64);
69cb93a386Sopenharmony_ci
70cb93a386Sopenharmony_ci    SkBitmap drawTextBitmap;
71cb93a386Sopenharmony_ci    create(&drawTextBitmap, size);
72cb93a386Sopenharmony_ci    SkCanvas drawTextCanvas(drawTextBitmap);
73cb93a386Sopenharmony_ci
74cb93a386Sopenharmony_ci    SkBitmap drawDashedTextBitmap;
75cb93a386Sopenharmony_ci    create(&drawDashedTextBitmap, size);
76cb93a386Sopenharmony_ci    SkCanvas drawDashedTextCanvas(drawDashedTextBitmap);
77cb93a386Sopenharmony_ci
78cb93a386Sopenharmony_ci    SkBitmap emptyBitmap;
79cb93a386Sopenharmony_ci    create(&emptyBitmap, size);
80cb93a386Sopenharmony_ci    SkCanvas emptyCanvas(emptyBitmap);
81cb93a386Sopenharmony_ci
82cb93a386Sopenharmony_ci    SkPoint point = SkPoint::Make(25.0f, 25.0f);
83cb93a386Sopenharmony_ci    SkFont font(nullptr, 20);
84cb93a386Sopenharmony_ci    font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
85cb93a386Sopenharmony_ci    font.setSubpixel(true);
86cb93a386Sopenharmony_ci
87cb93a386Sopenharmony_ci    SkPaint paint;
88cb93a386Sopenharmony_ci    paint.setColor(SK_ColorGRAY);
89cb93a386Sopenharmony_ci    paint.setStyle(SkPaint::kStroke_Style);
90cb93a386Sopenharmony_ci
91cb93a386Sopenharmony_ci    // Draw a stroked "A" without a dash which will draw something.
92cb93a386Sopenharmony_ci    drawTextCanvas.drawColor(SK_ColorWHITE);
93cb93a386Sopenharmony_ci    drawTextCanvas.drawString("A", point.fX, point.fY, font, paint);
94cb93a386Sopenharmony_ci
95cb93a386Sopenharmony_ci    // Draw an "A" but with a dash which will never draw anything.
96cb93a386Sopenharmony_ci    paint.setStrokeWidth(2);
97cb93a386Sopenharmony_ci    constexpr SkScalar bigInterval = 10000;
98cb93a386Sopenharmony_ci    static constexpr SkScalar intervals[] = { 1, bigInterval };
99cb93a386Sopenharmony_ci    paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 2));
100cb93a386Sopenharmony_ci
101cb93a386Sopenharmony_ci    drawDashedTextCanvas.drawColor(SK_ColorWHITE);
102cb93a386Sopenharmony_ci    drawDashedTextCanvas.drawString("A", point.fX, point.fY, font, paint);
103cb93a386Sopenharmony_ci
104cb93a386Sopenharmony_ci    // Draw nothing.
105cb93a386Sopenharmony_ci    emptyCanvas.drawColor(SK_ColorWHITE);
106cb93a386Sopenharmony_ci
107cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, !compare(drawTextBitmap, size, emptyBitmap, size));
108cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, compare(drawDashedTextBitmap, size, emptyBitmap, size));
109cb93a386Sopenharmony_ci}
110cb93a386Sopenharmony_ci
111cb93a386Sopenharmony_ci// Test drawing text at some unusual coordinates.
112cb93a386Sopenharmony_ci// We measure success by not crashing or asserting.
113cb93a386Sopenharmony_ciDEF_TEST(DrawText_weirdCoordinates, r) {
114cb93a386Sopenharmony_ci    auto surface = SkSurface::MakeRasterN32Premul(10,10);
115cb93a386Sopenharmony_ci    auto canvas = surface->getCanvas();
116cb93a386Sopenharmony_ci
117cb93a386Sopenharmony_ci    SkScalar oddballs[] = { 0.0f, (float)INFINITY, (float)NAN, 34359738368.0f };
118cb93a386Sopenharmony_ci
119cb93a386Sopenharmony_ci    for (auto x : oddballs) {
120cb93a386Sopenharmony_ci        canvas->drawString("a", +x, 0.0f, SkFont(), SkPaint());
121cb93a386Sopenharmony_ci        canvas->drawString("a", -x, 0.0f, SkFont(), SkPaint());
122cb93a386Sopenharmony_ci    }
123cb93a386Sopenharmony_ci    for (auto y : oddballs) {
124cb93a386Sopenharmony_ci        canvas->drawString("a", 0.0f, +y, SkFont(), SkPaint());
125cb93a386Sopenharmony_ci        canvas->drawString("a", 0.0f, -y, SkFont(), SkPaint());
126cb93a386Sopenharmony_ci    }
127cb93a386Sopenharmony_ci}
128cb93a386Sopenharmony_ci
129cb93a386Sopenharmony_ci// Test drawing text with some unusual matricies.
130cb93a386Sopenharmony_ci// We measure success by not crashing or asserting.
131cb93a386Sopenharmony_ciDEF_TEST(DrawText_weirdMatricies, r) {
132cb93a386Sopenharmony_ci    auto surface = SkSurface::MakeRasterN32Premul(100,100);
133cb93a386Sopenharmony_ci    auto canvas = surface->getCanvas();
134cb93a386Sopenharmony_ci
135cb93a386Sopenharmony_ci    SkFont font;
136cb93a386Sopenharmony_ci    font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
137cb93a386Sopenharmony_ci
138cb93a386Sopenharmony_ci    struct {
139cb93a386Sopenharmony_ci        SkScalar textSize;
140cb93a386Sopenharmony_ci        SkScalar matrix[9];
141cb93a386Sopenharmony_ci    } testCases[] = {
142cb93a386Sopenharmony_ci        // 2x2 singular
143cb93a386Sopenharmony_ci        {10, { 0,  0,  0,  0,  0,  0,  0,  0,  1}},
144cb93a386Sopenharmony_ci        {10, { 0,  0,  0,  0,  1,  0,  0,  0,  1}},
145cb93a386Sopenharmony_ci        {10, { 0,  0,  0,  1,  0,  0,  0,  0,  1}},
146cb93a386Sopenharmony_ci        {10, { 0,  0,  0,  1,  1,  0,  0,  0,  1}},
147cb93a386Sopenharmony_ci        {10, { 0,  1,  0,  0,  1,  0,  0,  0,  1}},
148cb93a386Sopenharmony_ci        {10, { 1,  0,  0,  0,  0,  0,  0,  0,  1}},
149cb93a386Sopenharmony_ci        {10, { 1,  0,  0,  1,  0,  0,  0,  0,  1}},
150cb93a386Sopenharmony_ci        {10, { 1,  1,  0,  0,  0,  0,  0,  0,  1}},
151cb93a386Sopenharmony_ci        {10, { 1,  1,  0,  1,  1,  0,  0,  0,  1}},
152cb93a386Sopenharmony_ci        // See https://bugzilla.mozilla.org/show_bug.cgi?id=1305085 .
153cb93a386Sopenharmony_ci        { 1, {10, 20,  0, 20, 40,  0,  0,  0,  1}},
154cb93a386Sopenharmony_ci    };
155cb93a386Sopenharmony_ci
156cb93a386Sopenharmony_ci    for (const auto& testCase : testCases) {
157cb93a386Sopenharmony_ci        font.setSize(testCase.textSize);
158cb93a386Sopenharmony_ci        const SkScalar(&m)[9] = testCase.matrix;
159cb93a386Sopenharmony_ci        SkMatrix mat;
160cb93a386Sopenharmony_ci        mat.setAll(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]);
161cb93a386Sopenharmony_ci        canvas->setMatrix(mat);
162cb93a386Sopenharmony_ci        canvas->drawString("Hamburgefons", 10, 10, font, SkPaint());
163cb93a386Sopenharmony_ci    }
164cb93a386Sopenharmony_ci}
165cb93a386Sopenharmony_ci
166cb93a386Sopenharmony_ci// This produces no glyphs, and is to check that buffers from previous draws don't get
167cb93a386Sopenharmony_ci// reused.
168cb93a386Sopenharmony_ciDEF_TEST(DrawText_noglyphs, r) {
169cb93a386Sopenharmony_ci    auto surface = SkSurface::MakeRasterN32Premul(100,100);
170cb93a386Sopenharmony_ci    auto canvas = surface->getCanvas();
171cb93a386Sopenharmony_ci    auto text = "Hamburgfons";
172cb93a386Sopenharmony_ci    {
173cb93a386Sopenharmony_ci        // scoped to ensure blob is deleted.
174cb93a386Sopenharmony_ci        auto blob = SkTextBlob::MakeFromText(text, strlen(text), SkFont());
175cb93a386Sopenharmony_ci        canvas->drawTextBlob(blob, 10, 10, SkPaint());
176cb93a386Sopenharmony_ci    }
177cb93a386Sopenharmony_ci    canvas->drawString(
178cb93a386Sopenharmony_ci            "\x0d\xf3\xf2\xf2\xe9\x0d\x0d\x0d\x05\x0d\x0d\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xe3",
179cb93a386Sopenharmony_ci            10, 20, SkFont(), SkPaint());
180cb93a386Sopenharmony_ci}
181