skia2/tests/DrawTextTest.cpp
Herb Derby b6cce2d4c7 don't draw strings that have no glyphs
This string had several characters which resulted in zero
glyphs. Having zero glyphs bypassed the buffer sizing code,
and continued to process the glyph run list assuming it had
7 runs because the buffer sizing code also clears the run list.
This caused the code to process runs from a previous SkTextBlob,
which was already deleted.

If the there are no glyphs, call the buffer sizing code to
set up all the invariants. Exit if there are no runs produced.

Bug: oss-fuzz:33915

Change-Id: I9f3f38a58112c44ddd65265c68d982b3b0dcd79c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/403439
Reviewed-by: Ben Wagner <bungeman@google.com>
Commit-Queue: Herb Derby <herb@google.com>
2021-05-03 19:27:54 +00:00

181 lines
6.1 KiB
C++

/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/core/SkBitmap.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkColor.h"
#include "include/core/SkFont.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPathEffect.h"
#include "include/core/SkPoint.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/core/SkSurface.h"
#include "include/core/SkTextBlob.h"
#include "include/core/SkTypeface.h"
#include "include/core/SkTypes.h"
#include "include/effects/SkDashPathEffect.h"
#include "tests/Test.h"
#include <cmath>
static const SkColor bgColor = SK_ColorWHITE;
static void create(SkBitmap* bm, SkIRect bound) {
bm->allocN32Pixels(bound.width(), bound.height());
}
/** Assumes that the ref draw was completely inside ref canvas --
implies that everything outside is "bgColor".
Checks that all overlap is the same and that all non-overlap on the
ref is "bgColor".
*/
static bool compare(const SkBitmap& ref, const SkIRect& iref,
const SkBitmap& test, const SkIRect& itest)
{
const int xOff = itest.fLeft - iref.fLeft;
const int yOff = itest.fTop - iref.fTop;
for (int y = 0; y < test.height(); ++y) {
for (int x = 0; x < test.width(); ++x) {
SkColor testColor = test.getColor(x, y);
int refX = x + xOff;
int refY = y + yOff;
SkColor refColor;
if (refX >= 0 && refX < ref.width() &&
refY >= 0 && refY < ref.height())
{
refColor = ref.getColor(refX, refY);
} else {
refColor = bgColor;
}
if (refColor != testColor) {
return false;
}
}
}
return true;
}
/** Test that drawing glyphs with empty paths is different from drawing glyphs without paths. */
DEF_TEST(DrawText_dashout, reporter) {
SkIRect size = SkIRect::MakeWH(64, 64);
SkBitmap drawTextBitmap;
create(&drawTextBitmap, size);
SkCanvas drawTextCanvas(drawTextBitmap);
SkBitmap drawDashedTextBitmap;
create(&drawDashedTextBitmap, size);
SkCanvas drawDashedTextCanvas(drawDashedTextBitmap);
SkBitmap emptyBitmap;
create(&emptyBitmap, size);
SkCanvas emptyCanvas(emptyBitmap);
SkPoint point = SkPoint::Make(25.0f, 25.0f);
SkFont font(nullptr, 20);
font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
font.setSubpixel(true);
SkPaint paint;
paint.setColor(SK_ColorGRAY);
paint.setStyle(SkPaint::kStroke_Style);
// Draw a stroked "A" without a dash which will draw something.
drawTextCanvas.drawColor(SK_ColorWHITE);
drawTextCanvas.drawString("A", point.fX, point.fY, font, paint);
// Draw an "A" but with a dash which will never draw anything.
paint.setStrokeWidth(2);
constexpr SkScalar bigInterval = 10000;
static constexpr SkScalar intervals[] = { 1, bigInterval };
paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 2));
drawDashedTextCanvas.drawColor(SK_ColorWHITE);
drawDashedTextCanvas.drawString("A", point.fX, point.fY, font, paint);
// Draw nothing.
emptyCanvas.drawColor(SK_ColorWHITE);
REPORTER_ASSERT(reporter, !compare(drawTextBitmap, size, emptyBitmap, size));
REPORTER_ASSERT(reporter, compare(drawDashedTextBitmap, size, emptyBitmap, size));
}
// Test drawing text at some unusual coordinates.
// We measure success by not crashing or asserting.
DEF_TEST(DrawText_weirdCoordinates, r) {
auto surface = SkSurface::MakeRasterN32Premul(10,10);
auto canvas = surface->getCanvas();
SkScalar oddballs[] = { 0.0f, (float)INFINITY, (float)NAN, 34359738368.0f };
for (auto x : oddballs) {
canvas->drawString("a", +x, 0.0f, SkFont(), SkPaint());
canvas->drawString("a", -x, 0.0f, SkFont(), SkPaint());
}
for (auto y : oddballs) {
canvas->drawString("a", 0.0f, +y, SkFont(), SkPaint());
canvas->drawString("a", 0.0f, -y, SkFont(), SkPaint());
}
}
// Test drawing text with some unusual matricies.
// We measure success by not crashing or asserting.
DEF_TEST(DrawText_weirdMatricies, r) {
auto surface = SkSurface::MakeRasterN32Premul(100,100);
auto canvas = surface->getCanvas();
SkFont font;
font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
struct {
SkScalar textSize;
SkScalar matrix[9];
} testCases[] = {
// 2x2 singular
{10, { 0, 0, 0, 0, 0, 0, 0, 0, 1}},
{10, { 0, 0, 0, 0, 1, 0, 0, 0, 1}},
{10, { 0, 0, 0, 1, 0, 0, 0, 0, 1}},
{10, { 0, 0, 0, 1, 1, 0, 0, 0, 1}},
{10, { 0, 1, 0, 0, 1, 0, 0, 0, 1}},
{10, { 1, 0, 0, 0, 0, 0, 0, 0, 1}},
{10, { 1, 0, 0, 1, 0, 0, 0, 0, 1}},
{10, { 1, 1, 0, 0, 0, 0, 0, 0, 1}},
{10, { 1, 1, 0, 1, 1, 0, 0, 0, 1}},
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1305085 .
{ 1, {10, 20, 0, 20, 40, 0, 0, 0, 1}},
};
for (const auto& testCase : testCases) {
font.setSize(testCase.textSize);
const SkScalar(&m)[9] = testCase.matrix;
SkMatrix mat;
mat.setAll(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]);
canvas->setMatrix(mat);
canvas->drawString("Hamburgefons", 10, 10, font, SkPaint());
}
}
// This produces no glyphs, and is to check that buffers from previous draws don't get
// reused.
DEF_TEST(DrawText_noglyphs, r) {
auto surface = SkSurface::MakeRasterN32Premul(100,100);
auto canvas = surface->getCanvas();
auto text = "Hamburgfons";
{
// scoped to ensure blob is deleted.
auto blob = SkTextBlob::MakeFromText(text, strlen(text), SkFont());
canvas->drawTextBlob(blob, 10, 10, SkPaint());
}
canvas->drawString(
"\x0d\xf3\xf2\xf2\xe9\x0d\x0d\x0d\x05\x0d\x0d\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xe3",
10, 20, SkFont(), SkPaint());
}