blob: af584ffc65c92b28daf756491bc6f9fdb07429e1 [file] [log] [blame]
/*
* Copyright 2020 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/core/SkCanvas.h"
#include "include/core/SkData.h"
#include "include/core/SkDrawable.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPath.h"
#include "include/core/SkPoint.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkTypes.h"
#include "src/base/SkArenaAlloc.h"
#include "src/core/SkGlyph.h"
#include "src/core/SkMask.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkWriteBuffer.h"
#include "tests/Test.h"
#include <cstddef>
#include <cstdint>
#include <iterator>
#include <optional>
DEF_TEST(SkGlyphRectBasic, reporter) {
using namespace skglyph;
SkGlyphRect r{1, 1, 10, 10};
REPORTER_ASSERT(reporter, !r.empty());
SkGlyphRect a = rect_union(r, empty_rect());
REPORTER_ASSERT(reporter, a.rect() == SkRect::MakeLTRB(1, 1, 10, 10));
auto widthHeight = a.widthHeight();
REPORTER_ASSERT(reporter, widthHeight.x() == 9 && widthHeight.y() == 9);
a = rect_intersection(r, full_rect());
REPORTER_ASSERT(reporter, a.rect() == SkRect::MakeLTRB(1, 1, 10, 10));
SkGlyphRect acc = full_rect();
for (int x = -10; x < 10; x++) {
for(int y = -10; y < 10; y++) {
acc = rect_intersection(acc, SkGlyphRect(x, y, x + 20, y + 20));
}
}
REPORTER_ASSERT(reporter, acc.rect() == SkRect::MakeLTRB(9, 9, 10, 10));
acc = empty_rect();
for (int x = -10; x < 10; x++) {
for(int y = -10; y < 10; y++) {
acc = rect_union(acc, SkGlyphRect(x, y, x + 20, y + 20));
}
}
REPORTER_ASSERT(reporter, acc.rect() == SkRect::MakeLTRB(-10, -10, 29, 29));
}
class SkGlyphTestPeer {
public:
static void SetGlyph(SkGlyph* glyph) {
glyph->fAdvanceX = 10;
glyph->fAdvanceY = 11;
glyph->fLeft = -1;
glyph->fTop = -2;
glyph->fWidth = 8;
glyph->fHeight = 9;
glyph->fMaskFormat = SkMask::Format::kA8_Format;
}
};
DEF_TEST(SkGlyph_SendMetrics, reporter) {
SkGlyph srcGlyph{SkPackedGlyphID{(SkGlyphID)12}};
SkGlyphTestPeer::SetGlyph(&srcGlyph);
SkBinaryWriteBuffer writeBuffer;
srcGlyph.flattenMetrics(writeBuffer);
sk_sp<SkData> data = writeBuffer.snapshotAsData();
SkReadBuffer readBuffer{data->data(), data->size()};
std::optional<SkGlyph> dstGlyph = SkGlyph::MakeFromBuffer(readBuffer);
REPORTER_ASSERT(reporter, dstGlyph.has_value());
REPORTER_ASSERT(reporter, srcGlyph.advanceVector() == dstGlyph->advanceVector());
REPORTER_ASSERT(reporter, srcGlyph.rect() == dstGlyph->rect());
REPORTER_ASSERT(reporter, srcGlyph.maskFormat() == dstGlyph->maskFormat());
uint8_t badData[] = {1, 2, 3, 4, 5, 6, 7, 8};
SkReadBuffer badBuffer{badData, std::size(badData)};
dstGlyph = SkGlyph::MakeFromBuffer(badBuffer);
REPORTER_ASSERT(reporter, !dstGlyph.has_value());
}
DEF_TEST(SkGlyph_SendWithImage, reporter) {
SkArenaAlloc alloc{256};
SkGlyph srcGlyph{SkPackedGlyphID{(SkGlyphID)12}};
SkGlyphTestPeer::SetGlyph(&srcGlyph);
static constexpr uint8_t X = 0xff;
static constexpr uint8_t O = 0x00;
uint8_t imageData[][8] = {
{X,X,X,X,X,X,X,X},
{X,O,O,O,O,O,O,X},
{X,O,O,O,O,O,O,X},
{X,O,O,O,O,O,O,X},
{X,O,O,X,X,O,O,X},
{X,O,O,O,O,O,O,X},
{X,O,O,O,O,O,O,X},
{X,O,O,O,O,O,O,X},
{X,X,X,X,X,X,X,X},
};
srcGlyph.setImage(&alloc, imageData);
SkBinaryWriteBuffer writeBuffer;
srcGlyph.flattenMetrics(writeBuffer);
srcGlyph.flattenImage(writeBuffer);
sk_sp<SkData> data = writeBuffer.snapshotAsData();
SkReadBuffer readBuffer{data->data(), data->size()};
std::optional<SkGlyph> dstGlyph = SkGlyph::MakeFromBuffer(readBuffer);
REPORTER_ASSERT(reporter, dstGlyph.has_value());
REPORTER_ASSERT(reporter, srcGlyph.advanceVector() == dstGlyph->advanceVector());
REPORTER_ASSERT(reporter, srcGlyph.rect() == dstGlyph->rect());
REPORTER_ASSERT(reporter, srcGlyph.maskFormat() == dstGlyph->maskFormat());
dstGlyph->addImageFromBuffer(readBuffer, &alloc);
uint8_t* dstImage = (uint8_t*)dstGlyph->image();
for (int y = 0; y < dstGlyph->height(); ++y) {
for (int x = 0; x < dstGlyph->width(); ++x) {
REPORTER_ASSERT(reporter, imageData[y][x] == dstImage[y * dstGlyph->rowBytes() + x]);
}
}
// Add good metrics, but mess up image data
SkBinaryWriteBuffer badWriteBuffer;
srcGlyph.flattenMetrics(badWriteBuffer);
badWriteBuffer.writeInt(7);
badWriteBuffer.writeInt(8);
data = badWriteBuffer.snapshotAsData();
SkReadBuffer badReadBuffer{data->data(), data->size()};
dstGlyph = SkGlyph::MakeFromBuffer(badReadBuffer);
REPORTER_ASSERT(reporter, dstGlyph.has_value());
REPORTER_ASSERT(reporter, srcGlyph.advanceVector() == dstGlyph->advanceVector());
REPORTER_ASSERT(reporter, srcGlyph.rect() == dstGlyph->rect());
REPORTER_ASSERT(reporter, srcGlyph.maskFormat() == dstGlyph->maskFormat());
dstGlyph->addImageFromBuffer(badReadBuffer, &alloc);
REPORTER_ASSERT(reporter, !badReadBuffer.isValid());
REPORTER_ASSERT(reporter, !dstGlyph->setImageHasBeenCalled());
}
DEF_TEST(SkGlyph_SendWithPath, reporter) {
SkArenaAlloc alloc{256};
SkGlyph srcGlyph{SkPackedGlyphID{(SkGlyphID)12}};
SkGlyphTestPeer::SetGlyph(&srcGlyph);
SkPath srcPath;
srcPath.addRect(srcGlyph.rect());
srcGlyph.setPath(&alloc, &srcPath, false);
SkBinaryWriteBuffer writeBuffer;
srcGlyph.flattenMetrics(writeBuffer);
srcGlyph.flattenPath(writeBuffer);
sk_sp<SkData> data = writeBuffer.snapshotAsData();
SkReadBuffer readBuffer{data->data(), data->size()};
std::optional<SkGlyph> dstGlyph = SkGlyph::MakeFromBuffer(readBuffer);
REPORTER_ASSERT(reporter, dstGlyph.has_value());
REPORTER_ASSERT(reporter, srcGlyph.advanceVector() == dstGlyph->advanceVector());
REPORTER_ASSERT(reporter, srcGlyph.rect() == dstGlyph->rect());
REPORTER_ASSERT(reporter, srcGlyph.maskFormat() == dstGlyph->maskFormat());
dstGlyph->addPathFromBuffer(readBuffer, &alloc);
REPORTER_ASSERT(reporter, dstGlyph->setPathHasBeenCalled());
const SkPath* dstPath = dstGlyph->path();
REPORTER_ASSERT(reporter, *dstPath == srcPath);
// Add good metrics, but mess up path data
SkBinaryWriteBuffer badWriteBuffer;
srcGlyph.flattenMetrics(badWriteBuffer);
badWriteBuffer.writeInt(7);
badWriteBuffer.writeInt(8);
data = badWriteBuffer.snapshotAsData();
SkReadBuffer badReadBuffer{data->data(), data->size()};
dstGlyph = SkGlyph::MakeFromBuffer(badReadBuffer);
REPORTER_ASSERT(reporter, dstGlyph.has_value());
REPORTER_ASSERT(reporter, srcGlyph.advanceVector() == dstGlyph->advanceVector());
REPORTER_ASSERT(reporter, srcGlyph.rect() == dstGlyph->rect());
REPORTER_ASSERT(reporter, srcGlyph.maskFormat() == dstGlyph->maskFormat());
dstGlyph->addPathFromBuffer(badReadBuffer, &alloc);
REPORTER_ASSERT(reporter, !badReadBuffer.isValid());
REPORTER_ASSERT(reporter, !dstGlyph->setPathHasBeenCalled());
}
DEF_TEST(SkGlyph_SendWithDrawable, reporter) {
SkArenaAlloc alloc{256};
SkGlyph srcGlyph{SkPackedGlyphID{(SkGlyphID)12}};
SkGlyphTestPeer::SetGlyph(&srcGlyph);
class TestDrawable final : public SkDrawable {
public:
TestDrawable(SkRect rect) : fRect(rect) {}
private:
const SkRect fRect;
SkRect onGetBounds() override { return fRect; }
size_t onApproximateBytesUsed() override {
return 0;
}
void onDraw(SkCanvas* canvas) override {
SkPaint paint;
canvas->drawRect(fRect, paint);
}
};
sk_sp<SkDrawable> srcDrawable = sk_make_sp<TestDrawable>(srcGlyph.rect());
srcGlyph.setDrawable(&alloc, srcDrawable);
REPORTER_ASSERT(reporter, srcGlyph.setDrawableHasBeenCalled());
SkBinaryWriteBuffer writeBuffer;
srcGlyph.flattenMetrics(writeBuffer);
srcGlyph.flattenDrawable(writeBuffer);
sk_sp<SkData> data = writeBuffer.snapshotAsData();
SkReadBuffer readBuffer{data->data(), data->size()};
std::optional<SkGlyph> dstGlyph = SkGlyph::MakeFromBuffer(readBuffer);
REPORTER_ASSERT(reporter, dstGlyph.has_value());
REPORTER_ASSERT(reporter, srcGlyph.advanceVector() == dstGlyph->advanceVector());
REPORTER_ASSERT(reporter, srcGlyph.rect() == dstGlyph->rect());
REPORTER_ASSERT(reporter, srcGlyph.maskFormat() == dstGlyph->maskFormat());
dstGlyph->addDrawableFromBuffer(readBuffer, &alloc);
REPORTER_ASSERT(reporter, dstGlyph->setDrawableHasBeenCalled());
SkDrawable* dstDrawable = dstGlyph->drawable();
REPORTER_ASSERT(reporter, dstDrawable->getBounds() == srcDrawable->getBounds());
// Add good metrics, but mess up drawable data
SkBinaryWriteBuffer badWriteBuffer;
srcGlyph.flattenMetrics(badWriteBuffer);
badWriteBuffer.writeInt(7);
badWriteBuffer.writeInt(8);
data = badWriteBuffer.snapshotAsData();
SkReadBuffer badReadBuffer{data->data(), data->size()};
dstGlyph = SkGlyph::MakeFromBuffer(badReadBuffer);
REPORTER_ASSERT(reporter, dstGlyph.has_value());
REPORTER_ASSERT(reporter, srcGlyph.advanceVector() == dstGlyph->advanceVector());
REPORTER_ASSERT(reporter, srcGlyph.rect() == dstGlyph->rect());
REPORTER_ASSERT(reporter, srcGlyph.maskFormat() == dstGlyph->maskFormat());
dstGlyph->addDrawableFromBuffer(badReadBuffer, &alloc);
REPORTER_ASSERT(reporter, !badReadBuffer.isValid());
REPORTER_ASSERT(reporter, !dstGlyph->setDrawableHasBeenCalled());
}