Lottie experiments

This commit is contained in:
Isaac 2024-06-11 12:29:24 +04:00
parent 5b08504388
commit 992bfbde1e
266 changed files with 47526 additions and 6 deletions

View File

@ -201,6 +201,7 @@ ios_application(
resources = [
"//Tests/Common:LaunchScreen",
":TestDataBundle",
"//Tests/LottieMetalTest/skia",
],
frameworks = [
],

View File

@ -25,6 +25,8 @@ objc_library(
deps = [
"//submodules/LottieCpp",
"//Tests/LottieMetalTest/thorvg",
"//Tests/LottieMetalTest/skia",
"//Tests/LottieMetalTest/skia:libskia"
],
sdk_frameworks = [
"Foundation",

View File

@ -0,0 +1,316 @@
#include "SkiaCanvasImpl.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkColor.h"
#include "include/core/SkFont.h"
#include "include/core/SkFontTypes.h"
#include "include/core/SkGraphics.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPoint.h"
#include "include/core/SkRect.h"
#include "include/core/SkShader.h"
#include "include/core/SkString.h"
#include "include/core/SkSurface.h"
#include "include/core/SkTileMode.h"
#include "include/core/SkPath.h"
#include "include/core/SkPathEffect.h"
#include "include/effects/SkDashPathEffect.h"
#include "include/effects/SkGradientShader.h"
namespace lottie {
namespace {
SkColor skColor(Color const &color) {
return SkColorSetARGB((uint8_t)(color.a * 255.0), (uint8_t)(color.r * 255.0), (uint8_t)(color.g * 255.0), (uint8_t)(color.b * 255.0));
}
void skPath(CanvasPathEnumerator const &enumeratePath, SkPath &nativePath) {
enumeratePath([&](PathCommand const &command) {
switch (command.type) {
case PathCommandType::MoveTo: {
nativePath.moveTo(command.points[0].x, command.points[0].y);
break;
}
case PathCommandType::LineTo: {
nativePath.lineTo(command.points[0].x, command.points[0].y);
break;
}
case PathCommandType::CurveTo: {
nativePath.cubicTo(command.points[0].x, command.points[0].y, command.points[1].x, command.points[1].y, command.points[2].x, command.points[2].y);
break;
}
case PathCommandType::Close: {
nativePath.close();
break;
}
}
});
}
}
SkiaCanvasImpl::SkiaCanvasImpl(int width, int height) :
_width(width), _height(height) {
int bytesPerRow = width * 4;
_pixelData = malloc(bytesPerRow * height);
_ownsPixelData = true;
_surface = SkSurfaces::WrapPixels(
SkImageInfo::MakeN32Premul(width, height),
_pixelData,
bytesPerRow,
nullptr
);
_canvas = _surface->getCanvas();
_canvas->resetMatrix();
_canvas->clear(SkColorSetARGB(0, 0, 0, 0));
}
SkiaCanvasImpl::SkiaCanvasImpl(int width, int height, int bytesPerRow, void *pixelData) {
_pixelData = pixelData;
_ownsPixelData = false;
_surface = SkSurfaces::WrapPixels(
SkImageInfo::MakeN32Premul(width, height),
_pixelData,
bytesPerRow,
nullptr
);
_canvas = _surface->getCanvas();
_canvas->resetMatrix();
_canvas->clear(SkColorSetARGB(0, 0, 0, 0));
}
SkiaCanvasImpl::~SkiaCanvasImpl() {
if (_ownsPixelData) {
free(_pixelData);
}
}
int SkiaCanvasImpl::width() const {
return _width;
}
int SkiaCanvasImpl::height() const {
return _height;
}
std::shared_ptr<Canvas> SkiaCanvasImpl::makeLayer(int width, int height) {
return std::make_shared<SkiaCanvasImpl>(width, height);
}
void SkiaCanvasImpl::saveState() {
_canvas->save();
}
void SkiaCanvasImpl::restoreState() {
_canvas->restore();
}
void SkiaCanvasImpl::fillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Color const &color) {
SkPaint paint;
paint.setColor(skColor(color));
paint.setAlphaf(_alpha);
paint.setAntiAlias(true);
paint.setBlendMode(_blendMode);
SkPath nativePath;
skPath(enumeratePath, nativePath);
nativePath.setFillType(fillRule == FillRule::EvenOdd ? SkPathFillType::kEvenOdd : SkPathFillType::kWinding);
_canvas->drawPath(nativePath, paint);
}
void SkiaCanvasImpl::linearGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) {
SkPaint paint;
paint.setAntiAlias(true);
paint.setBlendMode(_blendMode);
paint.setDither(false);
paint.setStyle(SkPaint::Style::kFill_Style);
SkPoint linearPoints[2] = {
SkPoint::Make(start.x, start.y),
SkPoint::Make(end.x, end.y)
};
std::vector<SkColor> colors;
for (const auto &color : gradient.colors()) {
colors.push_back(skColor(Color(color.r, color.g, color.b, color.a * _alpha)));
}
std::vector<SkScalar> locations;
for (auto location : gradient.locations()) {
locations.push_back(location);
}
paint.setShader(SkGradientShader::MakeLinear(linearPoints, colors.data(), locations.data(), (int)colors.size(), SkTileMode::kMirror));
SkPath nativePath;
skPath(enumeratePath, nativePath);
nativePath.setFillType(fillRule == FillRule::EvenOdd ? SkPathFillType::kEvenOdd : SkPathFillType::kWinding);
_canvas->drawPath(nativePath, paint);
}
void SkiaCanvasImpl::radialGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) {
SkPaint paint;
paint.setAntiAlias(true);
paint.setBlendMode(_blendMode);
paint.setDither(false);
paint.setStyle(SkPaint::Style::kFill_Style);
std::vector<SkColor> colors;
for (const auto &color : gradient.colors()) {
colors.push_back(skColor(Color(color.r, color.g, color.b, color.a * _alpha)));
}
std::vector<SkScalar> locations;
for (auto location : gradient.locations()) {
locations.push_back(location);
}
paint.setShader(SkGradientShader::MakeRadial(SkPoint::Make(startCenter.x, startCenter.y), endRadius, colors.data(), locations.data(), (int)colors.size(), SkTileMode::kMirror));
SkPath nativePath;
skPath(enumeratePath, nativePath);
nativePath.setFillType(fillRule == FillRule::EvenOdd ? SkPathFillType::kEvenOdd : SkPathFillType::kWinding);
_canvas->drawPath(nativePath, paint);
}
void SkiaCanvasImpl::strokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector<float> const &dashPattern, lottie::Color const &color) {
SkPaint paint;
paint.setAntiAlias(true);
paint.setBlendMode(_blendMode);
paint.setColor(skColor(color));
paint.setAlphaf(_alpha);
paint.setStyle(SkPaint::Style::kStroke_Style);
paint.setStrokeWidth(lineWidth);
switch (lineJoin) {
case LineJoin::Miter: {
paint.setStrokeJoin(SkPaint::Join::kMiter_Join);
break;
}
case LineJoin::Round: {
paint.setStrokeJoin(SkPaint::Join::kRound_Join);
break;
}
case LineJoin::Bevel: {
paint.setStrokeJoin(SkPaint::Join::kBevel_Join);
break;
}
default: {
paint.setStrokeJoin(SkPaint::Join::kBevel_Join);
break;
}
}
switch (lineCap) {
case LineCap::Butt: {
paint.setStrokeCap(SkPaint::Cap::kButt_Cap);
break;
}
case LineCap::Round: {
paint.setStrokeCap(SkPaint::Cap::kRound_Cap);
break;
}
case LineCap::Square: {
paint.setStrokeCap(SkPaint::Cap::kSquare_Cap);
break;
}
default: {
paint.setStrokeCap(SkPaint::Cap::kSquare_Cap);
break;
}
}
if (!dashPattern.empty()) {
std::vector<SkScalar> intervals;
intervals.reserve(dashPattern.size());
for (auto value : dashPattern) {
intervals.push_back(value);
}
paint.setPathEffect(SkDashPathEffect::Make(intervals.data(), (int)intervals.size(), dashPhase));
}
SkPath nativePath;
skPath(enumeratePath, nativePath);
_canvas->drawPath(nativePath, paint);
}
void SkiaCanvasImpl::linearGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector<float> const &dashPattern, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) {
assert(false);
}
void SkiaCanvasImpl::radialGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector<float> const &dashPattern, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) {
assert(false);
}
void SkiaCanvasImpl::fill(lottie::CGRect const &rect, lottie::Color const &fillColor) {
SkPaint paint;
paint.setAntiAlias(true);
paint.setColor(skColor(fillColor));
paint.setAlphaf(_alpha);
paint.setBlendMode(_blendMode);
_canvas->drawRect(SkRect::MakeXYWH(rect.x, rect.y, rect.width, rect.height), paint);
}
void SkiaCanvasImpl::setBlendMode(BlendMode blendMode) {
switch (blendMode) {
case BlendMode::Normal: {
_blendMode = SkBlendMode::kSrcOver;
break;
}
case BlendMode::DestinationIn: {
_blendMode = SkBlendMode::kDstIn;
break;
}
case BlendMode::DestinationOut: {
_blendMode = SkBlendMode::kDstOut;
break;
}
default: {
_blendMode = SkBlendMode::kSrcOver;
break;
}
}
}
void SkiaCanvasImpl::setAlpha(float alpha) {
_alpha = alpha;
}
void SkiaCanvasImpl::concatenate(lottie::Transform2D const &transform) {
SkScalar m9[9] = {
transform.rows().columns[0][0], transform.rows().columns[1][0], transform.rows().columns[2][0],
transform.rows().columns[0][1], transform.rows().columns[1][1], transform.rows().columns[2][1],
transform.rows().columns[0][2], transform.rows().columns[1][2], transform.rows().columns[2][2]
};
SkMatrix matrix;
matrix.set9(m9);
_canvas->concat(matrix);
}
void SkiaCanvasImpl::draw(std::shared_ptr<Canvas> const &other, lottie::CGRect const &rect) {
SkiaCanvasImpl *impl = (SkiaCanvasImpl *)other.get();
auto image = impl->surface()->makeImageSnapshot();
SkPaint paint;
paint.setBlendMode(_blendMode);
paint.setAlphaf(_alpha);
_canvas->drawImageRect(image.get(), SkRect::MakeXYWH(rect.x, rect.y, rect.width, rect.height), SkSamplingOptions(SkFilterMode::kLinear), &paint);
}
void SkiaCanvasImpl::flush() {
}
sk_sp<SkSurface> SkiaCanvasImpl::surface() const {
return _surface;
}
}

View File

@ -0,0 +1,57 @@
#ifndef SkiaCanvasImpl_h
#define SkiaCanvasImpl_h
#include <LottieCpp/LottieCpp.h>
#include "include/core/SkCanvas.h"
#include "include/core/SkSurface.h"
namespace lottie {
class SkiaCanvasImpl: public Canvas {
public:
SkiaCanvasImpl(int width, int height);
SkiaCanvasImpl(int width, int height, int bytesPerRow, void *pixelData);
virtual ~SkiaCanvasImpl();
virtual int width() const override;
virtual int height() const override;
virtual std::shared_ptr<Canvas> makeLayer(int width, int height) override;
virtual void saveState() override;
virtual void restoreState() override;
virtual void fillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Color const &color) override;
virtual void linearGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) override;
virtual void radialGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) override;
virtual void strokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector<float> const &dashPattern, lottie::Color const &color) override;
virtual void linearGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector<float> const &dashPattern, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) override;
virtual void radialGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector<float> const &dashPattern, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) override;
virtual void fill(lottie::CGRect const &rect, lottie::Color const &fillColor) override;
virtual void setBlendMode(BlendMode blendMode) override;
virtual void setAlpha(float alpha) override;
virtual void concatenate(lottie::Transform2D const &transform) override;
virtual void draw(std::shared_ptr<Canvas> const &other, lottie::CGRect const &rect) override;
void flush();
sk_sp<SkSurface> surface() const;
private:
void *_pixelData = nullptr;
bool _ownsPixelData = false;
int _width = 0;
int _height = 0;
sk_sp<SkSurface> _surface;
SkCanvas *_canvas = nullptr;
SkBlendMode _blendMode = SkBlendMode::kSrcOver;
double _alpha = 1.0;
};
}
#endif

View File

@ -5,11 +5,14 @@
#import "CoreGraphicsCanvasImpl.h"
#import "ThorVGCanvasImpl.h"
#import "SkiaCanvasImpl.h"
#include <LottieCpp/RenderTreeNode.h>
#include <LottieCpp/CGPathCocoa.h>
#include <LottieCpp/VectorsCocoa.h>
#import <Accelerate/Accelerate.h>
CGRect getPathNativeBoundingBox(CGPathRef _Nonnull path) {
auto rect = calculatePathBoundingBox(path);
return CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
@ -69,7 +72,84 @@ CGRect getPathNativeBoundingBox(CGPathRef _Nonnull path) {
return [[UIImage alloc] initWithCGImage:std::static_pointer_cast<lottie::CanvasImpl::Image>(image)->nativeImage()];
} else {
if ((int64_t)"" < 0) {
if ((int64_t)"" > 0) {
/*auto surface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul((int)size.width, (int)size.height));
int bytesPerRow = ((int)size.width) * 4;
void *pixelData = malloc(bytesPerRow * (int)size.height);
sk_sp<SkSurface> surface2 = SkSurfaces::WrapPixels(
SkImageInfo::MakeN32Premul((int)size.width, (int)size.height),
pixelData,
bytesPerRow,
nullptr
);
SkCanvas *canvas = surface->getCanvas();
SkPaint paint;
paint.setAntiAlias(true);
SkPath path;
path.moveTo(124, 108);
path.lineTo(172, 24);
path.addCircle(50, 50, 30);
path.moveTo(36, 148);
path.quadTo(66, 188, 120, 136);
canvas->drawPath(path, paint);
paint.setStyle(SkPaint::kStroke_Style);
paint.setColor(SK_ColorBLUE);
paint.setStrokeWidth(3);
canvas->drawPath(path, paint);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
CGContextRef targetContext = CGBitmapContextCreate(pixelData, (int)size.width, (int)size.height, 8, bytesPerRow, colorSpace, bitmapInfo);
CGColorSpaceRelease(colorSpace);
CGImageRef bitmapImage = CGBitmapContextCreateImage(targetContext);
UIImage *image = [[UIImage alloc] initWithCGImage:bitmapImage scale:1.0f orientation:UIImageOrientationDownMirrored];
CGImageRelease(bitmapImage);
CGContextRelease(targetContext);
free(pixelData);
return image;*/
int bytesPerRow = ((int)size.width) * 4;
void *pixelData = malloc(bytesPerRow * (int)size.height);
auto context = std::make_shared<lottie::SkiaCanvasImpl>((int)size.width, (int)size.height, bytesPerRow, pixelData);
_canvasRenderer->render(_renderer, context, lottie::Vector2D(size.width, size.height));
context->flush();
vImage_Buffer src;
src.data = (void *)pixelData;
src.width = (int)size.width;
src.height = (int)size.height;
src.rowBytes = bytesPerRow;
uint8_t permuteMap[4] = {2, 1, 0, 3};
vImagePermuteChannels_ARGB8888(&src, &src, permuteMap, kvImageDoNotTile);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
CGContextRef targetContext = CGBitmapContextCreate(pixelData, (int)size.width, (int)size.height, 8, bytesPerRow, colorSpace, bitmapInfo);
CGColorSpaceRelease(colorSpace);
CGImageRef bitmapImage = CGBitmapContextCreateImage(targetContext);
UIImage *image = [[UIImage alloc] initWithCGImage:bitmapImage scale:1.0f orientation:UIImageOrientationDownMirrored];
CGImageRelease(bitmapImage);
CGContextRelease(targetContext);
free(pixelData);
return image;
} else if ((int64_t)"" < 0) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
lottie::ThorVGCanvasImpl::initializeOnce();

View File

@ -113,15 +113,15 @@ public final class ViewController: UIViewController {
SharedDisplayLinkDriver.shared.updateForegroundState(true)
let bundlePath = Bundle.main.path(forResource: "TestDataBundle", ofType: "bundle")!
let filePath = bundlePath + "/fireworks.json"
let filePath = bundlePath + "/fire.json"
let performanceFrameSize = 8
let performanceFrameSize = 512
self.view.layer.addSublayer(MetalEngine.shared.rootLayer)
if "".isEmpty {
if !"".isEmpty {
if #available(iOS 13.0, *) {
self.test = ReferenceCompareTest(view: self.view, testNonReference: false)
self.test = ReferenceCompareTest(view: self.view, testNonReference: true)
}
} else if !"".isEmpty {
/*let cachedAnimation = cacheLottieMetalAnimation(path: filePath)!

View File

@ -0,0 +1,43 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
load("@build_bazel_rules_apple//apple:apple.bzl",
"apple_dynamic_framework_import",
)
apple_dynamic_framework_import(
name = "libskia",
framework_imports = glob([
"libskia.framework/**"
]),
visibility = ["//visibility:public"],
)
objc_library(
name = "skia",
enable_modules = True,
module_name = "skia",
srcs = glob([
]),
copts = [
"-I{}/PublicHeaders/skia".format(package_name()),
],
linkopts = [
"-Wl,-rpath,@loader_path/Frameworks/libskia.framework",
],
hdrs = glob([
"PublicHeaders/**/*.h",
]),
includes = [
"PublicHeaders",
"PublicHeaders/skia",
],
deps = [
":libskia",
],
sdk_frameworks = [
"Foundation",
],
visibility = [
"//visibility:public",
],
)

View File

@ -0,0 +1,15 @@
set noparent
# Include one of the following reviewers for CLs that add or change Skia's public API:
brianosman@google.com
egdaniel@google.com
fmalita@google.com
fmalita@chromium.org
hcm@google.com
herb@google.com
robertphillips@google.com
per-file BUILD.bazel=bungeman@google.com
per-file BUILD.bazel=jcgregorio@google.com
per-file BUILD.bazel=kjlubick@google.com
per-file BUILD.bazel=lovisolo@google.com

View File

@ -0,0 +1,297 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkAndroidCodec_DEFINED
#define SkAndroidCodec_DEFINED
#include "include/codec/SkCodec.h"
#include "include/core/SkColorSpace.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkSize.h"
#include "include/core/SkTypes.h"
#include "include/private/SkEncodedInfo.h"
#include "include/private/base/SkNoncopyable.h"
#include "modules/skcms/skcms.h"
// TODO(kjlubick, bungeman) Replace these includes with forward declares
#include "include/codec/SkEncodedImageFormat.h" // IWYU pragma: keep
#include "include/core/SkAlphaType.h" // IWYU pragma: keep
#include "include/core/SkColorType.h" // IWYU pragma: keep
#include <cstddef>
#include <memory>
class SkData;
class SkPngChunkReader;
class SkStream;
struct SkGainmapInfo;
struct SkIRect;
/**
* Abstract interface defining image codec functionality that is necessary for
* Android.
*/
class SK_API SkAndroidCodec : SkNoncopyable {
public:
/**
* Deprecated.
*
* Now that SkAndroidCodec supports multiframe images, there are multiple
* ways to handle compositing an oriented frame on top of an oriented frame
* with different tradeoffs. SkAndroidCodec now ignores the orientation and
* forces the client to handle it.
*/
enum class ExifOrientationBehavior {
kIgnore,
kRespect,
};
/**
* Pass ownership of an SkCodec to a newly-created SkAndroidCodec.
*/
static std::unique_ptr<SkAndroidCodec> MakeFromCodec(std::unique_ptr<SkCodec>);
/**
* If this stream represents an encoded image that we know how to decode,
* return an SkAndroidCodec that can decode it. Otherwise return NULL.
*
* The SkPngChunkReader handles unknown chunks in PNGs.
* See SkCodec.h for more details.
*
* If NULL is returned, the stream is deleted immediately. Otherwise, the
* SkCodec takes ownership of it, and will delete it when done with it.
*/
static std::unique_ptr<SkAndroidCodec> MakeFromStream(std::unique_ptr<SkStream>,
SkPngChunkReader* = nullptr);
/**
* If this data represents an encoded image that we know how to decode,
* return an SkAndroidCodec that can decode it. Otherwise return NULL.
*
* The SkPngChunkReader handles unknown chunks in PNGs.
* See SkCodec.h for more details.
*/
static std::unique_ptr<SkAndroidCodec> MakeFromData(sk_sp<SkData>, SkPngChunkReader* = nullptr);
virtual ~SkAndroidCodec();
// TODO: fInfo is now just a cache of SkCodec's SkImageInfo. No need to
// cache and return a reference here, once Android call-sites are updated.
const SkImageInfo& getInfo() const { return fInfo; }
/**
* Return the ICC profile of the encoded data.
*/
const skcms_ICCProfile* getICCProfile() const {
return fCodec->getEncodedInfo().profile();
}
/**
* Format of the encoded data.
*/
SkEncodedImageFormat getEncodedFormat() const { return fCodec->getEncodedFormat(); }
/**
* @param requestedColorType Color type requested by the client
*
* |requestedColorType| may be overriden. We will default to kF16
* for high precision images.
*
* In the general case, if it is possible to decode to
* |requestedColorType|, this returns |requestedColorType|.
* Otherwise, this returns a color type that is an appropriate
* match for the the encoded data.
*/
SkColorType computeOutputColorType(SkColorType requestedColorType);
/**
* @param requestedUnpremul Indicates if the client requested
* unpremultiplied output
*
* Returns the appropriate alpha type to decode to. If the image
* has alpha, the value of requestedUnpremul will be honored.
*/
SkAlphaType computeOutputAlphaType(bool requestedUnpremul);
/**
* @param outputColorType Color type that the client will decode to.
* @param prefColorSpace Preferred color space to decode to.
* This may not return |prefColorSpace| for
* specific color types.
*
* Returns the appropriate color space to decode to.
*/
sk_sp<SkColorSpace> computeOutputColorSpace(SkColorType outputColorType,
sk_sp<SkColorSpace> prefColorSpace = nullptr);
/**
* Compute the appropriate sample size to get to |size|.
*
* @param size As an input parameter, the desired output size of
* the decode. As an output parameter, the smallest sampled size
* larger than the input.
* @return the sample size to set AndroidOptions::fSampleSize to decode
* to the output |size|.
*/
int computeSampleSize(SkISize* size) const;
/**
* Returns the dimensions of the scaled output image, for an input
* sampleSize.
*
* When the sample size divides evenly into the original dimensions, the
* scaled output dimensions will simply be equal to the original
* dimensions divided by the sample size.
*
* When the sample size does not divide even into the original
* dimensions, the codec may round up or down, depending on what is most
* efficient to decode.
*
* Finally, the codec will always recommend a non-zero output, so the output
* dimension will always be one if the sampleSize is greater than the
* original dimension.
*/
SkISize getSampledDimensions(int sampleSize) const;
/**
* Return (via desiredSubset) a subset which can decoded from this codec,
* or false if the input subset is invalid.
*
* @param desiredSubset in/out parameter
* As input, a desired subset of the original bounds
* (as specified by getInfo).
* As output, if true is returned, desiredSubset may
* have been modified to a subset which is
* supported. Although a particular change may have
* been made to desiredSubset to create something
* supported, it is possible other changes could
* result in a valid subset. If false is returned,
* desiredSubset's value is undefined.
* @return true If the input desiredSubset is valid.
* desiredSubset may be modified to a subset
* supported by the codec.
* false If desiredSubset is invalid (NULL or not fully
* contained within the image).
*/
bool getSupportedSubset(SkIRect* desiredSubset) const;
// TODO: Rename SkCodec::getValidSubset() to getSupportedSubset()
/**
* Returns the dimensions of the scaled, partial output image, for an
* input sampleSize and subset.
*
* @param sampleSize Factor to scale down by.
* @param subset Must be a valid subset of the original image
* dimensions and a subset supported by SkAndroidCodec.
* getSubset() can be used to obtain a subset supported
* by SkAndroidCodec.
* @return Size of the scaled partial image. Or zero size
* if either of the inputs is invalid.
*/
SkISize getSampledSubsetDimensions(int sampleSize, const SkIRect& subset) const;
/**
* Additional options to pass to getAndroidPixels().
*/
// FIXME: It's a bit redundant to name these AndroidOptions when this class is already
// called SkAndroidCodec. On the other hand, it's may be a bit confusing to call
// these Options when SkCodec has a slightly different set of Options. Maybe these
// should be DecodeOptions or SamplingOptions?
struct AndroidOptions : public SkCodec::Options {
AndroidOptions()
: SkCodec::Options()
, fSampleSize(1)
{}
/**
* The client may provide an integer downscale factor for the decode.
* The codec may implement this downscaling by sampling or another
* method if it is more efficient.
*
* The default is 1, representing no downscaling.
*/
int fSampleSize;
};
/**
* Decode into the given pixels, a block of memory of size at
* least (info.fHeight - 1) * rowBytes + (info.fWidth *
* bytesPerPixel)
*
* Repeated calls to this function should give the same results,
* allowing the PixelRef to be immutable.
*
* @param info A description of the format (config, size)
* expected by the caller. This can simply be identical
* to the info returned by getInfo().
*
* This contract also allows the caller to specify
* different output-configs, which the implementation can
* decide to support or not.
*
* A size that does not match getInfo() implies a request
* to scale or subset. If the codec cannot perform this
* scaling or subsetting, it will return an error code.
*
* The AndroidOptions object is also used to specify any requested scaling or subsetting
* using options->fSampleSize and options->fSubset. If NULL, the defaults (as specified above
* for AndroidOptions) are used.
*
* @return Result kSuccess, or another value explaining the type of failure.
*/
// FIXME: It's a bit redundant to name this getAndroidPixels() when this class is already
// called SkAndroidCodec. On the other hand, it's may be a bit confusing to call
// this getPixels() when it is a slightly different API than SkCodec's getPixels().
// Maybe this should be decode() or decodeSubset()?
SkCodec::Result getAndroidPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
const AndroidOptions* options);
/**
* Simplified version of getAndroidPixels() where we supply the default AndroidOptions as
* specified above for AndroidOptions. It will not perform any scaling or subsetting.
*/
SkCodec::Result getAndroidPixels(const SkImageInfo& info, void* pixels, size_t rowBytes);
SkCodec::Result getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) {
return this->getAndroidPixels(info, pixels, rowBytes);
}
SkCodec* codec() const { return fCodec.get(); }
/**
* Retrieve the gainmap for an image.
*
* @param outInfo On success, this is populated with the parameters for
* rendering this gainmap. This parameter must be non-nullptr.
*
* @param outGainmapImageStream On success, this is populated with a stream from which the
* gainmap image may be decoded. This parameter is optional, and
* may be set to nullptr.
*
* @return If this has a gainmap image and that gainmap image was
* successfully extracted then return true. Otherwise return
* false.
*/
bool getAndroidGainmap(SkGainmapInfo* outInfo,
std::unique_ptr<SkStream>* outGainmapImageStream);
protected:
SkAndroidCodec(SkCodec*);
virtual SkISize onGetSampledDimensions(int sampleSize) const = 0;
virtual bool onGetSupportedSubset(SkIRect* desiredSubset) const = 0;
virtual SkCodec::Result onGetAndroidPixels(const SkImageInfo& info, void* pixels,
size_t rowBytes, const AndroidOptions& options) = 0;
private:
const SkImageInfo fInfo;
std::unique_ptr<SkCodec> fCodec;
};
#endif // SkAndroidCodec_DEFINED

View File

@ -0,0 +1,44 @@
/*
* Copyright 2023 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkAvifDecoder_DEFINED
#define SkAvifDecoder_DEFINED
#include "include/codec/SkCodec.h"
#include "include/core/SkRefCnt.h"
#include "include/private/base/SkAPI.h"
class SkData;
class SkStream;
#include <memory>
namespace SkAvifDecoder {
/** Returns true if this data claims to be a AVIF image. */
SK_API bool IsAvif(const void*, size_t);
/**
* Attempts to decode the given bytes as a AVIF.
*
* If the bytes are not a AVIF, returns nullptr.
*
* DecodeContext is ignored
*/
SK_API std::unique_ptr<SkCodec> Decode(std::unique_ptr<SkStream>,
SkCodec::Result*,
SkCodecs::DecodeContext = nullptr);
SK_API std::unique_ptr<SkCodec> Decode(sk_sp<SkData>,
SkCodec::Result*,
SkCodecs::DecodeContext = nullptr);
inline constexpr SkCodecs::Decoder Decoder() {
return { "avif", IsAvif, Decode };
}
} // namespace SkAvifDecoder
#endif // SkAvifDecoder_DEFINED

View File

@ -0,0 +1,44 @@
/*
* Copyright 2023 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkBmpDecoder_DEFINED
#define SkBmpDecoder_DEFINED
#include "include/codec/SkCodec.h"
#include "include/core/SkRefCnt.h"
#include "include/private/base/SkAPI.h"
class SkData;
class SkStream;
#include <memory>
namespace SkBmpDecoder {
/** Returns true if this data claims to be a BMP image. */
SK_API bool IsBmp(const void*, size_t);
/**
* Attempts to decode the given bytes as a BMP.
*
* If the bytes are not a BMP, returns nullptr.
*
* DecodeContext is ignored
*/
SK_API std::unique_ptr<SkCodec> Decode(std::unique_ptr<SkStream>,
SkCodec::Result*,
SkCodecs::DecodeContext = nullptr);
SK_API std::unique_ptr<SkCodec> Decode(sk_sp<SkData>,
SkCodec::Result*,
SkCodecs::DecodeContext = nullptr);
inline constexpr SkCodecs::Decoder Decoder() {
return { "bmp", IsBmp, Decode };
}
} // namespace SkBmpDecoder
#endif // SkBmpDecoder_DEFINED

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,61 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkCodecAnimation_DEFINED
#define SkCodecAnimation_DEFINED
namespace SkCodecAnimation {
/**
* This specifies how the next frame is based on this frame.
*
* Names are based on the GIF 89a spec.
*
* The numbers correspond to values in a GIF.
*/
enum class DisposalMethod {
/**
* The next frame should be drawn on top of this one.
*
* In a GIF, a value of 0 (not specified) is also treated as Keep.
*/
kKeep = 1,
/**
* Similar to Keep, except the area inside this frame's rectangle
* should be cleared to the BackGround color (transparent) before
* drawing the next frame.
*/
kRestoreBGColor = 2,
/**
* The next frame should be drawn on top of the previous frame - i.e.
* disregarding this one.
*
* In a GIF, a value of 4 is also treated as RestorePrevious.
*/
kRestorePrevious = 3,
};
/**
* How to blend the current frame.
*/
enum class Blend {
/**
* Blend with the prior frame as if using SkBlendMode::kSrcOver.
*/
kSrcOver,
/**
* Blend with the prior frame as if using SkBlendMode::kSrc.
*
* This frame's pixels replace the destination pixels.
*/
kSrc,
};
} // namespace SkCodecAnimation
#endif // SkCodecAnimation_DEFINED

View File

@ -0,0 +1,33 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkEncodedImageFormat_DEFINED
#define SkEncodedImageFormat_DEFINED
#include <stdint.h>
/**
* Enum describing format of encoded data.
*/
enum class SkEncodedImageFormat {
kBMP,
kGIF,
kICO,
kJPEG,
kPNG,
kWBMP,
kWEBP,
kPKM,
kKTX,
kASTC,
kDNG,
kHEIF,
kAVIF,
kJPEGXL,
};
#endif // SkEncodedImageFormat_DEFINED

View File

@ -0,0 +1,54 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkEncodedOrigin_DEFINED
#define SkEncodedOrigin_DEFINED
#include "include/core/SkMatrix.h"
// These values match the orientation www.exif.org/Exif2-2.PDF.
enum SkEncodedOrigin {
kTopLeft_SkEncodedOrigin = 1, // Default
kTopRight_SkEncodedOrigin = 2, // Reflected across y-axis
kBottomRight_SkEncodedOrigin = 3, // Rotated 180
kBottomLeft_SkEncodedOrigin = 4, // Reflected across x-axis
kLeftTop_SkEncodedOrigin = 5, // Reflected across x-axis, Rotated 90 CCW
kRightTop_SkEncodedOrigin = 6, // Rotated 90 CW
kRightBottom_SkEncodedOrigin = 7, // Reflected across x-axis, Rotated 90 CW
kLeftBottom_SkEncodedOrigin = 8, // Rotated 90 CCW
kDefault_SkEncodedOrigin = kTopLeft_SkEncodedOrigin,
kLast_SkEncodedOrigin = kLeftBottom_SkEncodedOrigin,
};
/**
* Given an encoded origin and the width and height of the source data, returns a matrix
* that transforms the source rectangle with upper left corner at [0, 0] and origin to a correctly
* oriented destination rectangle of [0, 0, w, h].
*/
static inline SkMatrix SkEncodedOriginToMatrix(SkEncodedOrigin origin, int w, int h) {
switch (origin) {
case kTopLeft_SkEncodedOrigin: return SkMatrix::I();
case kTopRight_SkEncodedOrigin: return SkMatrix::MakeAll(-1, 0, w, 0, 1, 0, 0, 0, 1);
case kBottomRight_SkEncodedOrigin: return SkMatrix::MakeAll(-1, 0, w, 0, -1, h, 0, 0, 1);
case kBottomLeft_SkEncodedOrigin: return SkMatrix::MakeAll( 1, 0, 0, 0, -1, h, 0, 0, 1);
case kLeftTop_SkEncodedOrigin: return SkMatrix::MakeAll( 0, 1, 0, 1, 0, 0, 0, 0, 1);
case kRightTop_SkEncodedOrigin: return SkMatrix::MakeAll( 0, -1, w, 1, 0, 0, 0, 0, 1);
case kRightBottom_SkEncodedOrigin: return SkMatrix::MakeAll( 0, -1, w, -1, 0, h, 0, 0, 1);
case kLeftBottom_SkEncodedOrigin: return SkMatrix::MakeAll( 0, 1, 0, -1, 0, h, 0, 0, 1);
}
SK_ABORT("Unexpected origin");
}
/**
* Return true if the encoded origin includes a 90 degree rotation, in which case the width
* and height of the source data are swapped relative to a correctly oriented destination.
*/
static inline bool SkEncodedOriginSwapsWidthHeight(SkEncodedOrigin origin) {
return origin >= kLeftTop_SkEncodedOrigin;
}
#endif // SkEncodedOrigin_DEFINED

View File

@ -0,0 +1,44 @@
/*
* Copyright 2023 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkGifDecoder_DEFINED
#define SkGifDecoder_DEFINED
#include "include/codec/SkCodec.h"
#include "include/core/SkRefCnt.h"
#include "include/private/base/SkAPI.h"
class SkData;
class SkStream;
#include <memory>
namespace SkGifDecoder {
/** Returns true if this data claims to be a GIF image. */
SK_API bool IsGif(const void*, size_t);
/**
* Attempts to decode the given bytes as a GIF.
*
* If the bytes are not a GIF, returns nullptr.
*
* DecodeContext is ignored
*/
SK_API std::unique_ptr<SkCodec> Decode(std::unique_ptr<SkStream>,
SkCodec::Result*,
SkCodecs::DecodeContext = nullptr);
SK_API std::unique_ptr<SkCodec> Decode(sk_sp<SkData>,
SkCodec::Result*,
SkCodecs::DecodeContext = nullptr);
inline constexpr SkCodecs::Decoder Decoder() {
return { "gif", IsGif, Decode };
}
} // namespace SkGifDecoder
#endif // SkGifDecoder_DEFINED

View File

@ -0,0 +1,44 @@
/*
* Copyright 2023 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkIcoDecoder_DEFINED
#define SkIcoDecoder_DEFINED
#include "include/codec/SkCodec.h"
#include "include/core/SkRefCnt.h"
#include "include/private/base/SkAPI.h"
class SkData;
class SkStream;
#include <memory>
namespace SkIcoDecoder {
/** Returns true if this data claims to be a ICO image. */
SK_API bool IsIco(const void*, size_t);
/**
* Attempts to decode the given bytes as a ICO.
*
* If the bytes are not a ICO, returns nullptr.
*
* DecodeContext is ignored
*/
SK_API std::unique_ptr<SkCodec> Decode(std::unique_ptr<SkStream>,
SkCodec::Result*,
SkCodecs::DecodeContext = nullptr);
SK_API std::unique_ptr<SkCodec> Decode(sk_sp<SkData>,
SkCodec::Result*,
SkCodecs::DecodeContext = nullptr);
inline constexpr SkCodecs::Decoder Decoder() {
return { "ico", IsIco, Decode };
}
} // namespace SkIcoDecoder
#endif // SkIcoDecoder_DEFINED

View File

@ -0,0 +1,44 @@
/*
* Copyright 2023 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkJpegDecoder_DEFINED
#define SkJpegDecoder_DEFINED
#include "include/codec/SkCodec.h"
#include "include/core/SkRefCnt.h"
#include "include/private/base/SkAPI.h"
class SkData;
class SkStream;
#include <memory>
namespace SkJpegDecoder {
/** Returns true if this data claims to be a JPEG image. */
SK_API bool IsJpeg(const void*, size_t);
/**
* Attempts to decode the given bytes as a JPEG.
*
* If the bytes are not a JPEG, returns nullptr.
*
* DecodeContext is ignored
*/
SK_API std::unique_ptr<SkCodec> Decode(std::unique_ptr<SkStream>,
SkCodec::Result*,
SkCodecs::DecodeContext = nullptr);
SK_API std::unique_ptr<SkCodec> Decode(sk_sp<SkData>,
SkCodec::Result*,
SkCodecs::DecodeContext = nullptr);
inline constexpr SkCodecs::Decoder Decoder() {
return { "jpeg", IsJpeg, Decode };
}
} // namespace SkJpegDecoder
#endif // SkJpegDecoder_DEFINED

View File

@ -0,0 +1,44 @@
/*
* Copyright 2023 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkJpegxlDecoder_DEFINED
#define SkJpegxlDecoder_DEFINED
#include "include/codec/SkCodec.h"
#include "include/core/SkRefCnt.h"
#include "include/private/base/SkAPI.h"
class SkData;
class SkStream;
#include <memory>
namespace SkJpegxlDecoder {
/** Returns true if this data claims to be a JPEGXL image. */
SK_API bool IsJpegxl(const void*, size_t);
/**
* Attempts to decode the given bytes as a JPEGXL.
*
* If the bytes are not a JPEGXL, returns nullptr.
*
* DecodeContext is ignored
*/
SK_API std::unique_ptr<SkCodec> Decode(std::unique_ptr<SkStream>,
SkCodec::Result*,
SkCodecs::DecodeContext = nullptr);
SK_API std::unique_ptr<SkCodec> Decode(sk_sp<SkData>,
SkCodec::Result*,
SkCodecs::DecodeContext = nullptr);
inline constexpr SkCodecs::Decoder Decoder() {
return { "jpegxl", IsJpegxl, Decode };
}
} // namespace SkJpegxlDecoder
#endif // SkJpegxlDecoder_DEFINED

View File

@ -0,0 +1,31 @@
/*
* Copyright 2023 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkPixmapUtils_DEFINED
#define SkPixmapUtils_DEFINED
#include "include/codec/SkEncodedOrigin.h"
#include "include/core/SkImageInfo.h"
#include "include/private/base/SkAPI.h"
class SkPixmap;
namespace SkPixmapUtils {
/**
* Copy the pixels in src into dst, applying the orientation transformations specified
* by origin. If the inputs are invalid, this returns false and no copy is made.
*/
SK_API bool Orient(const SkPixmap& dst, const SkPixmap& src, SkEncodedOrigin origin);
/**
* Return a copy of the provided ImageInfo with the width and height swapped.
*/
SK_API SkImageInfo SwapWidthHeight(const SkImageInfo& info);
} // namespace SkPixmapUtils
#endif // SkPixmapUtils_DEFINED

View File

@ -0,0 +1,45 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkPngChunkReader_DEFINED
#define SkPngChunkReader_DEFINED
#include "include/core/SkRefCnt.h"
#include "include/core/SkTypes.h"
/**
* SkPngChunkReader
*
* Base class for optional callbacks to retrieve meta/chunk data out of a PNG
* encoded image as it is being decoded.
* Used by SkCodec.
*/
class SkPngChunkReader : public SkRefCnt {
public:
/**
* This will be called by the decoder when it sees an unknown chunk.
*
* Use by SkCodec:
* Depending on the location of the unknown chunks, this callback may be
* called by
* - the factory (NewFromStream/NewFromData)
* - getPixels
* - startScanlineDecode
* - the first call to getScanlines/skipScanlines
* The callback may be called from a different thread (e.g. if the SkCodec
* is passed to another thread), and it may be called multiple times, if
* the SkCodec is used multiple times.
*
* @param tag Name for this type of chunk.
* @param data Data to be interpreted by the subclass.
* @param length Number of bytes of data in the chunk.
* @return true to continue decoding, or false to indicate an error, which
* will cause the decoder to not return the image.
*/
virtual bool readChunk(const char tag[], const void* data, size_t length) = 0;
};
#endif // SkPngChunkReader_DEFINED

View File

@ -0,0 +1,44 @@
/*
* Copyright 2023 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkPngDecoder_DEFINED
#define SkPngDecoder_DEFINED
#include "include/codec/SkCodec.h"
#include "include/core/SkRefCnt.h"
#include "include/private/base/SkAPI.h"
class SkData;
class SkStream;
#include <memory>
namespace SkPngDecoder {
/** Returns true if this data claims to be a PNG image. */
SK_API bool IsPng(const void*, size_t);
/**
* Attempts to decode the given bytes as a PNG.
*
* If the bytes are not a PNG, returns nullptr.
*
* DecodeContext, if non-null, is expected to be a SkPngChunkReader*
*/
SK_API std::unique_ptr<SkCodec> Decode(std::unique_ptr<SkStream>,
SkCodec::Result*,
SkCodecs::DecodeContext = nullptr);
SK_API std::unique_ptr<SkCodec> Decode(sk_sp<SkData>,
SkCodec::Result*,
SkCodecs::DecodeContext = nullptr);
inline constexpr SkCodecs::Decoder Decoder() {
return { "png", IsPng, Decode };
}
} // namespace SkPngDecoder
#endif // SkPngDecoder_DEFINED

View File

@ -0,0 +1,50 @@
/*
* Copyright 2023 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkRawDecoder_DEFINED
#define SkRawDecoder_DEFINED
#include "include/codec/SkCodec.h"
#include "include/core/SkRefCnt.h"
#include "include/private/base/SkAPI.h"
class SkData;
class SkStream;
#include <memory>
namespace SkRawDecoder {
inline bool IsRaw(const void*, size_t) {
// Raw formats are tricky to detect just by reading in the first several bytes.
// For example, PIEX might need to read 10k bytes to detect Sony's arw format
// https://github.com/google/piex/blob/f1e15dd837c04347504149f71db67a78fbeddc73/src/image_type_recognition/image_type_recognition_lite.cc#L152
// Thus, we just assume everything might be a RAW file and check it last.
return true;
}
/**
* Attempts to decode the given bytes as a raw image.
*
* If the bytes are not a raw, returns nullptr.
*
* DecodeContext is ignored
*/
SK_API std::unique_ptr<SkCodec> Decode(std::unique_ptr<SkStream>,
SkCodec::Result*,
SkCodecs::DecodeContext = nullptr);
SK_API std::unique_ptr<SkCodec> Decode(sk_sp<SkData>,
SkCodec::Result*,
SkCodecs::DecodeContext = nullptr);
// This decoder will always be checked last, no matter when it is registered.
inline constexpr SkCodecs::Decoder Decoder() {
return { "raw", IsRaw, Decode };
}
} // namespace SkRawDecoder
#endif // SkRawDecoder_DEFINED

View File

@ -0,0 +1,44 @@
/*
* Copyright 2023 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkWbmpDecoder_DEFINED
#define SkWbmpDecoder_DEFINED
#include "include/codec/SkCodec.h"
#include "include/core/SkRefCnt.h"
#include "include/private/base/SkAPI.h"
class SkData;
class SkStream;
#include <memory>
namespace SkWbmpDecoder {
/** Returns true if this data claims to be a WBMP image. */
SK_API bool IsWbmp(const void*, size_t);
/**
* Attempts to decode the given bytes as a WBMP.
*
* If the bytes are not a WBMP, returns nullptr.
*
* DecodeContext is ignored
*/
SK_API std::unique_ptr<SkCodec> Decode(std::unique_ptr<SkStream>,
SkCodec::Result*,
SkCodecs::DecodeContext = nullptr);
SK_API std::unique_ptr<SkCodec> Decode(sk_sp<SkData>,
SkCodec::Result*,
SkCodecs::DecodeContext = nullptr);
inline constexpr SkCodecs::Decoder Decoder() {
return { "wbmp", IsWbmp, Decode };
}
} // namespace SkWbmpDecoder
#endif // SkWbmpDecoder_DEFINED

View File

@ -0,0 +1,44 @@
/*
* Copyright 2023 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkWebpDecoder_DEFINED
#define SkWebpDecoder_DEFINED
#include "include/codec/SkCodec.h"
#include "include/core/SkRefCnt.h"
#include "include/private/base/SkAPI.h"
class SkData;
class SkStream;
#include <memory>
namespace SkWebpDecoder {
/** Returns true if this data claims to be a WEBP image. */
SK_API bool IsWebp(const void*, size_t);
/**
* Attempts to decode the given bytes as a WEBP.
*
* If the bytes are not a WEBP, returns nullptr.
*
* DecodeContext is ignored
*/
SK_API std::unique_ptr<SkCodec> Decode(std::unique_ptr<SkStream>,
SkCodec::Result*,
SkCodecs::DecodeContext = nullptr);
SK_API std::unique_ptr<SkCodec> Decode(sk_sp<SkData>,
SkCodec::Result*,
SkCodecs::DecodeContext = nullptr);
inline constexpr SkCodecs::Decoder Decoder() {
return { "webp", IsWebp, Decode };
}
} // namespace SkWebpDecoder
#endif // SkWebpDecoder_DEFINED

View File

@ -0,0 +1,2 @@
bungeman@google.com
kjlubick@google.com

View File

@ -0,0 +1,121 @@
/*
* Copyright 2006 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkUserConfig_DEFINED
#define SkUserConfig_DEFINED
/* SkTypes.h, the root of the public header files, includes this file
SkUserConfig.h after first initializing certain Skia defines, letting
this file change or augment those flags.
Below are optional defines that add, subtract, or change default behavior
in Skia. Your port can locally edit this file to enable/disable flags as
you choose, or these can be declared on your command line (i.e. -Dfoo).
By default, this #include file will always default to having all the flags
commented out, so including it will have no effect.
*/
///////////////////////////////////////////////////////////////////////////////
/* Skia has lots of debug-only code. Often this is just null checks or other
parameter checking, but sometimes it can be quite intrusive (e.g. check that
each 32bit pixel is in premultiplied form). This code can be very useful
during development, but will slow things down in a shipping product.
By default, these mutually exclusive flags are defined in SkTypes.h,
based on the presence or absence of NDEBUG, but that decision can be changed
here.
*/
//#define SK_DEBUG
//#define SK_RELEASE
/* To write debug messages to a console, skia will call SkDebugf(...) following
printf conventions (e.g. const char* format, ...). If you want to redirect
this to something other than printf, define yours here
*/
//#define SkDebugf(...) MyFunction(__VA_ARGS__)
/* Skia has both debug and release asserts. When an assert fails SK_ABORT will
be used to report an abort message. SK_ABORT is expected not to return. Skia
provides a default implementation which will print the message with SkDebugf
and then call sk_abort_no_print.
*/
//#define SK_ABORT(message, ...)
/* To specify a different default font strike cache memory limit, define this. If this is
undefined, skia will use a built-in value.
*/
//#define SK_DEFAULT_FONT_CACHE_LIMIT (1024 * 1024)
/* To specify a different default font strike cache count limit, define this. If this is
undefined, skia will use a built-in value.
*/
// #define SK_DEFAULT_FONT_CACHE_COUNT_LIMIT 2048
/* To specify the default size of the image cache, undefine this and set it to
the desired value (in bytes). SkGraphics.h as a runtime API to set this
value as well. If this is undefined, a built-in value will be used.
*/
//#define SK_DEFAULT_IMAGE_CACHE_LIMIT (1024 * 1024)
/* Define this to set the upper limit for text to support LCD. Values that
are very large increase the cost in the font cache and draw slower, without
improving readability. If this is undefined, Skia will use its default
value (e.g. 48)
*/
//#define SK_MAX_SIZE_FOR_LCDTEXT 48
/* Change the kN32_SkColorType ordering to BGRA to work in X windows.
*/
//#define SK_R32_SHIFT 16
/* Determines whether to build code that supports the Ganesh GPU backend. Some classes
that are not GPU-specific, such as SkShader subclasses, have optional code
that is used allows them to interact with this GPU backend. If you'd like to
include this code, include -DSK_GANESH in your cflags or uncomment below.
Defaults to not set (No Ganesh GPU backend).
This define affects the ABI of Skia, so make sure it matches the client which uses
the compiled version of Skia.
*/
//#define SK_GANESH
/* Skia makes use of histogram logging macros to trace the frequency of
events. By default, Skia provides no-op versions of these macros.
Skia consumers can provide their own definitions of these macros to
integrate with their histogram collection backend.
*/
//#define SK_HISTOGRAM_BOOLEAN(name, sample)
//#define SK_HISTOGRAM_ENUMERATION(name, sample, enum_size)
//#define SK_HISTOGRAM_EXACT_LINEAR(name, sample, value_max)
//#define SK_HISTOGRAM_MEMORY_KB(name, sample)
// To use smaller but slower mipmap builder
//#define SK_USE_DRAWING_MIPMAP_DOWNSAMPLER
/* Skia tries to make use of some non-standard C++ language extensions.
By default, Skia provides msvc and clang/gcc versions of these macros.
Skia consumers can provide their own definitions of these macros to
integrate with their own compilers and build system.
*/
//#define SK_ALWAYS_INLINE inline __attribute__((always_inline))
//#define SK_NEVER_INLINE __attribute__((noinline))
//#define SK_PRINTF_LIKE(A, B) __attribute__((format(printf, (A), (B))))
//#define SK_NO_SANITIZE(A) __attribute__((no_sanitize(A)))
//#define SK_TRIVIAL_ABI [[clang::trivial_abi]]
/*
* If compiling Skia as a DLL, public APIs should be exported. Skia will set
* SK_API to something sensible for Clang and MSVC, but if clients need to
* customize it for their build system or compiler, they may.
* If a client needs to use SK_API (e.g. overriding SK_ABORT), then they
* *must* define their own, the default will not be defined prior to loading
* this file.
*/
//#define SK_API __declspec(dllexport)
#endif

View File

@ -0,0 +1,45 @@
/*
* Copyright 2022 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkAlphaType_DEFINED
#define SkAlphaType_DEFINED
/** \enum SkAlphaType
Describes how to interpret the alpha component of a pixel. A pixel may
be opaque, or alpha, describing multiple levels of transparency.
In simple blending, alpha weights the draw color and the destination
color to create a new color. If alpha describes a weight from zero to one:
new color = draw color * alpha + destination color * (1 - alpha)
In practice alpha is encoded in two or more bits, where 1.0 equals all bits set.
RGB may have alpha included in each component value; the stored
value is the original RGB multiplied by alpha. Premultiplied color
components improve performance.
*/
enum SkAlphaType : int {
kUnknown_SkAlphaType, //!< uninitialized
kOpaque_SkAlphaType, //!< pixel is opaque
kPremul_SkAlphaType, //!< pixel components are premultiplied by alpha
kUnpremul_SkAlphaType, //!< pixel components are independent of alpha
kLastEnum_SkAlphaType = kUnpremul_SkAlphaType, //!< last valid value
};
/** Returns true if SkAlphaType equals kOpaque_SkAlphaType.
kOpaque_SkAlphaType is a hint that the SkColorType is opaque, or that all
alpha values are set to their 1.0 equivalent. If SkAlphaType is
kOpaque_SkAlphaType, and SkColorType is not opaque, then the result of
drawing any pixel with a alpha value less than 1.0 is undefined.
*/
static inline bool SkAlphaTypeIsOpaque(SkAlphaType at) {
return kOpaque_SkAlphaType == at;
}
#endif

View File

@ -0,0 +1,52 @@
/*
* Copyright 2012 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkAnnotation_DEFINED
#define SkAnnotation_DEFINED
#include "include/core/SkTypes.h"
class SkData;
struct SkPoint;
struct SkRect;
class SkCanvas;
/**
* Annotate the canvas by associating the specified URL with the
* specified rectangle (in local coordinates, just like drawRect).
*
* The URL is expected to be escaped and be valid 7-bit ASCII.
*
* If the backend of this canvas does not support annotations, this call is
* safely ignored.
*
* The caller is responsible for managing its ownership of the SkData.
*/
SK_API void SkAnnotateRectWithURL(SkCanvas*, const SkRect&, SkData*);
/**
* Annotate the canvas by associating a name with the specified point.
*
* If the backend of this canvas does not support annotations, this call is
* safely ignored.
*
* The caller is responsible for managing its ownership of the SkData.
*/
SK_API void SkAnnotateNamedDestination(SkCanvas*, const SkPoint&, SkData*);
/**
* Annotate the canvas by making the specified rectangle link to a named
* destination.
*
* If the backend of this canvas does not support annotations, this call is
* safely ignored.
*
* The caller is responsible for managing its ownership of the SkData.
*/
SK_API void SkAnnotateLinkToDestination(SkCanvas*, const SkRect&, SkData*);
#endif

View File

@ -0,0 +1,69 @@
/*
* Copyright 2024 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkArc_DEFINED
#define SkArc_DEFINED
#include "include/core/SkRect.h"
#include "include/core/SkScalar.h"
// Represents an arc along an oval boundary, or a closed wedge of the oval.
struct SkArc {
enum class Type : bool {
kArc, // An arc along the perimeter of the oval
kWedge // A closed wedge that includes the oval's center
};
SkArc() = default;
SkArc(const SkArc& arc) = default;
SkArc& operator=(const SkArc& arc) = default;
const SkRect& oval() const { return fOval; }
SkScalar startAngle() const { return fStartAngle; }
SkScalar sweepAngle() const { return fSweepAngle; }
bool isWedge() const { return fType == Type::kWedge; }
friend bool operator==(const SkArc& a, const SkArc& b) {
return a.fOval == b.fOval && a.fStartAngle == b.fStartAngle &&
a.fSweepAngle == b.fSweepAngle && a.fType == b.fType;
}
friend bool operator!=(const SkArc& a, const SkArc& b) { return !(a == b); }
// Preferred factory that explicitly states which type of arc
static SkArc Make(const SkRect& oval,
SkScalar startAngleDegrees,
SkScalar sweepAngleDegrees,
Type type) {
return SkArc(oval, startAngleDegrees, sweepAngleDegrees, type);
}
// Deprecated factory to assist with legacy code based on `useCenter`
static SkArc Make(const SkRect& oval,
SkScalar startAngleDegrees,
SkScalar sweepAngleDegrees,
bool useCenter) {
return SkArc(
oval, startAngleDegrees, sweepAngleDegrees, useCenter ? Type::kWedge : Type::kArc);
}
// Bounds of oval containing the arc.
SkRect fOval = SkRect::MakeEmpty();
// Angle in degrees where the arc begins. Zero means horizontally to the right.
SkScalar fStartAngle = 0;
// Sweep angle in degrees; positive is clockwise.
SkScalar fSweepAngle = 0;
Type fType = Type::kArc;
private:
SkArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, Type type)
: fOval(oval), fStartAngle(startAngle), fSweepAngle(sweepAngle), fType(type) {}
};
#endif

View File

@ -0,0 +1,67 @@
/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkBBHFactory_DEFINED
#define SkBBHFactory_DEFINED
#include "include/core/SkRefCnt.h"
#include "include/core/SkTypes.h"
// TODO(kjlubick) fix client users and then make this a forward declare
#include "include/core/SkRect.h" // IWYU pragma: keep
#include <cstddef>
#include <vector>
class SkBBoxHierarchy : public SkRefCnt {
public:
struct Metadata {
bool isDraw; // The corresponding SkRect bounds a draw command, not a pure state change.
};
/**
* Insert N bounding boxes into the hierarchy.
*/
virtual void insert(const SkRect[], int N) = 0;
virtual void insert(const SkRect[], const Metadata[], int N);
/**
* Populate results with the indices of bounding boxes intersecting that query.
*/
virtual void search(const SkRect& query, std::vector<int>* results) const = 0;
/**
* Return approximate size in memory of *this.
*/
virtual size_t bytesUsed() const = 0;
protected:
SkBBoxHierarchy() = default;
SkBBoxHierarchy(const SkBBoxHierarchy&) = delete;
SkBBoxHierarchy& operator=(const SkBBoxHierarchy&) = delete;
};
class SK_API SkBBHFactory {
public:
/**
* Allocate a new SkBBoxHierarchy. Return NULL on failure.
*/
virtual sk_sp<SkBBoxHierarchy> operator()() const = 0;
virtual ~SkBBHFactory() {}
protected:
SkBBHFactory() = default;
SkBBHFactory(const SkBBHFactory&) = delete;
SkBBHFactory& operator=(const SkBBHFactory&) = delete;
};
class SK_API SkRTreeFactory : public SkBBHFactory {
public:
sk_sp<SkBBoxHierarchy> operator()() const override;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,112 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkBlendMode_DEFINED
#define SkBlendMode_DEFINED
#include "include/core/SkTypes.h"
/**
* Blends are operators that take in two colors (source, destination) and return a new color.
* Many of these operate the same on all 4 components: red, green, blue, alpha. For these,
* we just document what happens to one component, rather than naming each one separately.
*
* Different SkColorTypes have different representations for color components:
* 8-bit: 0..255
* 6-bit: 0..63
* 5-bit: 0..31
* 4-bit: 0..15
* floats: 0...1
*
* The documentation is expressed as if the component values are always 0..1 (floats).
*
* For brevity, the documentation uses the following abbreviations
* s : source
* d : destination
* sa : source alpha
* da : destination alpha
*
* Results are abbreviated
* r : if all 4 components are computed in the same manner
* ra : result alpha component
* rc : result "color": red, green, blue components
*/
enum class SkBlendMode {
kClear, //!< r = 0
kSrc, //!< r = s
kDst, //!< r = d
kSrcOver, //!< r = s + (1-sa)*d
kDstOver, //!< r = d + (1-da)*s
kSrcIn, //!< r = s * da
kDstIn, //!< r = d * sa
kSrcOut, //!< r = s * (1-da)
kDstOut, //!< r = d * (1-sa)
kSrcATop, //!< r = s*da + d*(1-sa)
kDstATop, //!< r = d*sa + s*(1-da)
kXor, //!< r = s*(1-da) + d*(1-sa)
kPlus, //!< r = min(s + d, 1)
kModulate, //!< r = s*d
kScreen, //!< r = s + d - s*d
kOverlay, //!< multiply or screen, depending on destination
kDarken, //!< rc = s + d - max(s*da, d*sa), ra = kSrcOver
kLighten, //!< rc = s + d - min(s*da, d*sa), ra = kSrcOver
kColorDodge, //!< brighten destination to reflect source
kColorBurn, //!< darken destination to reflect source
kHardLight, //!< multiply or screen, depending on source
kSoftLight, //!< lighten or darken, depending on source
kDifference, //!< rc = s + d - 2*(min(s*da, d*sa)), ra = kSrcOver
kExclusion, //!< rc = s + d - two(s*d), ra = kSrcOver
kMultiply, //!< r = s*(1-da) + d*(1-sa) + s*d
kHue, //!< hue of source with saturation and luminosity of destination
kSaturation, //!< saturation of source with hue and luminosity of destination
kColor, //!< hue and saturation of source with luminosity of destination
kLuminosity, //!< luminosity of source with hue and saturation of destination
kLastCoeffMode = kScreen, //!< last porter duff blend mode
kLastSeparableMode = kMultiply, //!< last blend mode operating separately on components
kLastMode = kLuminosity, //!< last valid value
};
static constexpr int kSkBlendModeCount = static_cast<int>(SkBlendMode::kLastMode) + 1;
/**
* For Porter-Duff SkBlendModes (those <= kLastCoeffMode), these coefficients describe the blend
* equation used. Coefficient-based blend modes specify an equation:
* ('dstCoeff' * dst + 'srcCoeff' * src), where the coefficient values are constants, functions of
* the src or dst alpha, or functions of the src or dst color.
*/
enum class SkBlendModeCoeff {
kZero, /** 0 */
kOne, /** 1 */
kSC, /** src color */
kISC, /** inverse src color (i.e. 1 - sc) */
kDC, /** dst color */
kIDC, /** inverse dst color (i.e. 1 - dc) */
kSA, /** src alpha */
kISA, /** inverse src alpha (i.e. 1 - sa) */
kDA, /** dst alpha */
kIDA, /** inverse dst alpha (i.e. 1 - da) */
kCoeffCount
};
/**
* Returns true if 'mode' is a coefficient-based blend mode (<= kLastCoeffMode). If true is
* returned, the mode's src and dst coefficient functions are set in 'src' and 'dst'.
*/
SK_API bool SkBlendMode_AsCoeff(SkBlendMode mode, SkBlendModeCoeff* src, SkBlendModeCoeff* dst);
/** Returns name of blendMode as null-terminated C string.
@return C string
*/
SK_API const char* SkBlendMode_Name(SkBlendMode blendMode);
#endif

View File

@ -0,0 +1,31 @@
/*
* Copyright 2021 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkBlender_DEFINED
#define SkBlender_DEFINED
#include "include/core/SkBlendMode.h"
#include "include/core/SkFlattenable.h"
/**
* SkBlender represents a custom blend function in the Skia pipeline. When an SkBlender is
* present in a paint, the SkBlendMode is ignored. A blender combines a source color (the
* result of our paint) and destination color (from the canvas) into a final color.
*/
class SK_API SkBlender : public SkFlattenable {
public:
/**
* Create a blender that implements the specified BlendMode.
*/
static sk_sp<SkBlender> Mode(SkBlendMode mode);
private:
SkBlender() = default;
friend class SkBlenderBase;
};
#endif

View File

@ -0,0 +1,20 @@
/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkBlurTypes_DEFINED
#define SkBlurTypes_DEFINED
enum SkBlurStyle : int {
kNormal_SkBlurStyle, //!< fuzzy inside and outside
kSolid_SkBlurStyle, //!< solid inside, fuzzy outside
kOuter_SkBlurStyle, //!< nothing inside, fuzzy outside
kInner_SkBlurStyle, //!< fuzzy inside, nothing outside
kLastEnum_SkBlurStyle = kInner_SkBlurStyle,
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,61 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkCanvasVirtualEnforcer_DEFINED
#define SkCanvasVirtualEnforcer_DEFINED
#include "include/core/SkCanvas.h"
// If you would ordinarily want to inherit from Base (eg SkCanvas, SkNWayCanvas), instead
// inherit from SkCanvasVirtualEnforcer<Base>, which will make the build fail if you forget
// to override one of SkCanvas' key virtual hooks.
template <typename Base>
class SkCanvasVirtualEnforcer : public Base {
public:
using Base::Base;
protected:
void onDrawPaint(const SkPaint& paint) override = 0;
void onDrawBehind(const SkPaint&) override {} // make zero after android updates
void onDrawRect(const SkRect& rect, const SkPaint& paint) override = 0;
void onDrawRRect(const SkRRect& rrect, const SkPaint& paint) override = 0;
void onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
const SkPaint& paint) override = 0;
void onDrawOval(const SkRect& rect, const SkPaint& paint) override = 0;
void onDrawArc(const SkRect& rect, SkScalar startAngle, SkScalar sweepAngle, bool useCenter,
const SkPaint& paint) override = 0;
void onDrawPath(const SkPath& path, const SkPaint& paint) override = 0;
void onDrawRegion(const SkRegion& region, const SkPaint& paint) override = 0;
void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
const SkPaint& paint) override = 0;
void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
const SkPoint texCoords[4], SkBlendMode mode,
const SkPaint& paint) override = 0;
void onDrawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint pts[],
const SkPaint& paint) override = 0;
#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
// This is under active development for Chrome and not used in Android. Hold off on adding
// implementations in Android's SkCanvas subclasses until this stabilizes.
void onDrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4],
SkCanvas::QuadAAFlags aaFlags, const SkColor4f& color, SkBlendMode mode) override {}
#else
void onDrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4],
SkCanvas::QuadAAFlags aaFlags, const SkColor4f& color, SkBlendMode mode) override = 0;
#endif
void onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) override = 0;
void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override = 0;
void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override = 0;
void onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
const SkPaint* paint) override = 0;
};
#endif

View File

@ -0,0 +1,39 @@
/*
* Copyright 2022 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkCapabilities_DEFINED
#define SkCapabilities_DEFINED
#include "include/core/SkRefCnt.h"
#include "include/core/SkTypes.h"
#include "include/sksl/SkSLVersion.h"
namespace SkSL { struct ShaderCaps; }
#if defined(SK_GRAPHITE)
namespace skgpu::graphite { class Caps; }
#endif
class SK_API SkCapabilities : public SkRefCnt {
public:
static sk_sp<const SkCapabilities> RasterBackend();
SkSL::Version skslVersion() const { return fSkSLVersion; }
protected:
#if defined(SK_GRAPHITE)
friend class skgpu::graphite::Caps; // for ctor
#endif
SkCapabilities() = default;
void initSkCaps(const SkSL::ShaderCaps*);
SkSL::Version fSkSLVersion = SkSL::Version::k100;
};
#endif

View File

@ -0,0 +1,19 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkClipOp_DEFINED
#define SkClipOp_DEFINED
#include "include/core/SkTypes.h"
enum class SkClipOp {
kDifference = 0,
kIntersect = 1,
kMax_EnumValue = kIntersect
};
#endif

View File

@ -0,0 +1,447 @@
/*
* Copyright 2006 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkColor_DEFINED
#define SkColor_DEFINED
#include "include/core/SkAlphaType.h"
#include "include/core/SkScalar.h"
#include "include/core/SkTypes.h"
#include "include/private/base/SkCPUTypes.h"
#include <array>
#include <cstdint>
/** \file SkColor.h
Types, consts, functions, and macros for colors.
*/
/** 8-bit type for an alpha value. 255 is 100% opaque, zero is 100% transparent.
*/
typedef uint8_t SkAlpha;
/** 32-bit ARGB color value, unpremultiplied. Color components are always in
a known order. This is different from SkPMColor, which has its bytes in a configuration
dependent order, to match the format of kBGRA_8888_SkColorType bitmaps. SkColor
is the type used to specify colors in SkPaint and in gradients.
Color that is premultiplied has the same component values as color
that is unpremultiplied if alpha is 255, fully opaque, although may have the
component values in a different order.
*/
typedef uint32_t SkColor;
/** Returns color value from 8-bit component values. Asserts if SK_DEBUG is defined
if a, r, g, or b exceed 255. Since color is unpremultiplied, a may be smaller
than the largest of r, g, and b.
@param a amount of alpha, from fully transparent (0) to fully opaque (255)
@param r amount of red, from no red (0) to full red (255)
@param g amount of green, from no green (0) to full green (255)
@param b amount of blue, from no blue (0) to full blue (255)
@return color and alpha, unpremultiplied
*/
static constexpr inline SkColor SkColorSetARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
return SkASSERT(a <= 255 && r <= 255 && g <= 255 && b <= 255),
(a << 24) | (r << 16) | (g << 8) | (b << 0);
}
/** Returns color value from 8-bit component values, with alpha set
fully opaque to 255.
*/
#define SkColorSetRGB(r, g, b) SkColorSetARGB(0xFF, r, g, b)
/** Returns alpha byte from color value.
*/
#define SkColorGetA(color) (((color) >> 24) & 0xFF)
/** Returns red component of color, from zero to 255.
*/
#define SkColorGetR(color) (((color) >> 16) & 0xFF)
/** Returns green component of color, from zero to 255.
*/
#define SkColorGetG(color) (((color) >> 8) & 0xFF)
/** Returns blue component of color, from zero to 255.
*/
#define SkColorGetB(color) (((color) >> 0) & 0xFF)
/** Returns unpremultiplied color with red, blue, and green set from c; and alpha set
from a. Alpha component of c is ignored and is replaced by a in result.
@param c packed RGB, eight bits per component
@param a alpha: transparent at zero, fully opaque at 255
@return color with transparency
*/
[[nodiscard]] static constexpr inline SkColor SkColorSetA(SkColor c, U8CPU a) {
return (c & 0x00FFFFFF) | (a << 24);
}
/** Represents fully transparent SkAlpha value. SkAlpha ranges from zero,
fully transparent; to 255, fully opaque.
*/
constexpr SkAlpha SK_AlphaTRANSPARENT = 0x00;
/** Represents fully opaque SkAlpha value. SkAlpha ranges from zero,
fully transparent; to 255, fully opaque.
*/
constexpr SkAlpha SK_AlphaOPAQUE = 0xFF;
/** Represents fully transparent SkColor. May be used to initialize a destination
containing a mask or a non-rectangular image.
*/
constexpr SkColor SK_ColorTRANSPARENT = SkColorSetARGB(0x00, 0x00, 0x00, 0x00);
/** Represents fully opaque black.
*/
constexpr SkColor SK_ColorBLACK = SkColorSetARGB(0xFF, 0x00, 0x00, 0x00);
/** Represents fully opaque dark gray.
Note that SVG dark gray is equivalent to 0xFFA9A9A9.
*/
constexpr SkColor SK_ColorDKGRAY = SkColorSetARGB(0xFF, 0x44, 0x44, 0x44);
/** Represents fully opaque gray.
Note that HTML gray is equivalent to 0xFF808080.
*/
constexpr SkColor SK_ColorGRAY = SkColorSetARGB(0xFF, 0x88, 0x88, 0x88);
/** Represents fully opaque light gray. HTML silver is equivalent to 0xFFC0C0C0.
Note that SVG light gray is equivalent to 0xFFD3D3D3.
*/
constexpr SkColor SK_ColorLTGRAY = SkColorSetARGB(0xFF, 0xCC, 0xCC, 0xCC);
/** Represents fully opaque white.
*/
constexpr SkColor SK_ColorWHITE = SkColorSetARGB(0xFF, 0xFF, 0xFF, 0xFF);
/** Represents fully opaque red.
*/
constexpr SkColor SK_ColorRED = SkColorSetARGB(0xFF, 0xFF, 0x00, 0x00);
/** Represents fully opaque green. HTML lime is equivalent.
Note that HTML green is equivalent to 0xFF008000.
*/
constexpr SkColor SK_ColorGREEN = SkColorSetARGB(0xFF, 0x00, 0xFF, 0x00);
/** Represents fully opaque blue.
*/
constexpr SkColor SK_ColorBLUE = SkColorSetARGB(0xFF, 0x00, 0x00, 0xFF);
/** Represents fully opaque yellow.
*/
constexpr SkColor SK_ColorYELLOW = SkColorSetARGB(0xFF, 0xFF, 0xFF, 0x00);
/** Represents fully opaque cyan. HTML aqua is equivalent.
*/
constexpr SkColor SK_ColorCYAN = SkColorSetARGB(0xFF, 0x00, 0xFF, 0xFF);
/** Represents fully opaque magenta. HTML fuchsia is equivalent.
*/
constexpr SkColor SK_ColorMAGENTA = SkColorSetARGB(0xFF, 0xFF, 0x00, 0xFF);
/** Converts RGB to its HSV components.
hsv[0] contains hsv hue, a value from zero to less than 360.
hsv[1] contains hsv saturation, a value from zero to one.
hsv[2] contains hsv value, a value from zero to one.
@param red red component value from zero to 255
@param green green component value from zero to 255
@param blue blue component value from zero to 255
@param hsv three element array which holds the resulting HSV components
*/
SK_API void SkRGBToHSV(U8CPU red, U8CPU green, U8CPU blue, SkScalar hsv[3]);
/** Converts ARGB to its HSV components. Alpha in ARGB is ignored.
hsv[0] contains hsv hue, and is assigned a value from zero to less than 360.
hsv[1] contains hsv saturation, a value from zero to one.
hsv[2] contains hsv value, a value from zero to one.
@param color ARGB color to convert
@param hsv three element array which holds the resulting HSV components
*/
static inline void SkColorToHSV(SkColor color, SkScalar hsv[3]) {
SkRGBToHSV(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color), hsv);
}
/** Converts HSV components to an ARGB color. Alpha is passed through unchanged.
hsv[0] represents hsv hue, an angle from zero to less than 360.
hsv[1] represents hsv saturation, and varies from zero to one.
hsv[2] represents hsv value, and varies from zero to one.
Out of range hsv values are pinned.
@param alpha alpha component of the returned ARGB color
@param hsv three element array which holds the input HSV components
@return ARGB equivalent to HSV
*/
SK_API SkColor SkHSVToColor(U8CPU alpha, const SkScalar hsv[3]);
/** Converts HSV components to an ARGB color. Alpha is set to 255.
hsv[0] represents hsv hue, an angle from zero to less than 360.
hsv[1] represents hsv saturation, and varies from zero to one.
hsv[2] represents hsv value, and varies from zero to one.
Out of range hsv values are pinned.
@param hsv three element array which holds the input HSV components
@return RGB equivalent to HSV
*/
static inline SkColor SkHSVToColor(const SkScalar hsv[3]) {
return SkHSVToColor(0xFF, hsv);
}
/** 32-bit ARGB color value, premultiplied. The byte order for this value is
configuration dependent, matching the format of kBGRA_8888_SkColorType bitmaps.
This is different from SkColor, which is unpremultiplied, and is always in the
same byte order.
*/
typedef uint32_t SkPMColor;
/** Returns a SkPMColor value from unpremultiplied 8-bit component values.
@param a amount of alpha, from fully transparent (0) to fully opaque (255)
@param r amount of red, from no red (0) to full red (255)
@param g amount of green, from no green (0) to full green (255)
@param b amount of blue, from no blue (0) to full blue (255)
@return premultiplied color
*/
SK_API SkPMColor SkPreMultiplyARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
/** Returns pmcolor closest to color c. Multiplies c RGB components by the c alpha,
and arranges the bytes to match the format of kN32_SkColorType.
@param c unpremultiplied ARGB color
@return premultiplied color
*/
SK_API SkPMColor SkPreMultiplyColor(SkColor c);
/** \enum SkColorChannel
Describes different color channels one can manipulate
*/
enum class SkColorChannel {
kR, // the red channel
kG, // the green channel
kB, // the blue channel
kA, // the alpha channel
kLastEnum = kA,
};
/** Used to represent the channels available in a color type or texture format as a mask. */
enum SkColorChannelFlag : uint32_t {
kRed_SkColorChannelFlag = 1 << static_cast<uint32_t>(SkColorChannel::kR),
kGreen_SkColorChannelFlag = 1 << static_cast<uint32_t>(SkColorChannel::kG),
kBlue_SkColorChannelFlag = 1 << static_cast<uint32_t>(SkColorChannel::kB),
kAlpha_SkColorChannelFlag = 1 << static_cast<uint32_t>(SkColorChannel::kA),
kGray_SkColorChannelFlag = 0x10,
// Convenience values
kGrayAlpha_SkColorChannelFlags = kGray_SkColorChannelFlag | kAlpha_SkColorChannelFlag,
kRG_SkColorChannelFlags = kRed_SkColorChannelFlag | kGreen_SkColorChannelFlag,
kRGB_SkColorChannelFlags = kRG_SkColorChannelFlags | kBlue_SkColorChannelFlag,
kRGBA_SkColorChannelFlags = kRGB_SkColorChannelFlags | kAlpha_SkColorChannelFlag,
};
static_assert(0 == (kGray_SkColorChannelFlag & kRGBA_SkColorChannelFlags), "bitfield conflict");
/** \struct SkRGBA4f
RGBA color value, holding four floating point components. Color components are always in
a known order. kAT determines if the SkRGBA4f's R, G, and B components are premultiplied
by alpha or not.
Skia's public API always uses unpremultiplied colors, which can be stored as
SkRGBA4f<kUnpremul_SkAlphaType>. For convenience, this type can also be referred to
as SkColor4f.
*/
template <SkAlphaType kAT>
struct SkRGBA4f {
float fR; //!< red component
float fG; //!< green component
float fB; //!< blue component
float fA; //!< alpha component
/** Compares SkRGBA4f with other, and returns true if all components are equal.
@param other SkRGBA4f to compare
@return true if SkRGBA4f equals other
*/
bool operator==(const SkRGBA4f& other) const {
return fA == other.fA && fR == other.fR && fG == other.fG && fB == other.fB;
}
/** Compares SkRGBA4f with other, and returns true if not all components are equal.
@param other SkRGBA4f to compare
@return true if SkRGBA4f is not equal to other
*/
bool operator!=(const SkRGBA4f& other) const {
return !(*this == other);
}
/** Returns SkRGBA4f multiplied by scale.
@param scale value to multiply by
@return SkRGBA4f as (fR * scale, fG * scale, fB * scale, fA * scale)
*/
SkRGBA4f operator*(float scale) const {
return { fR * scale, fG * scale, fB * scale, fA * scale };
}
/** Returns SkRGBA4f multiplied component-wise by scale.
@param scale SkRGBA4f to multiply by
@return SkRGBA4f as (fR * scale.fR, fG * scale.fG, fB * scale.fB, fA * scale.fA)
*/
SkRGBA4f operator*(const SkRGBA4f& scale) const {
return { fR * scale.fR, fG * scale.fG, fB * scale.fB, fA * scale.fA };
}
/** Returns a pointer to components of SkRGBA4f, for array access.
@return pointer to array [fR, fG, fB, fA]
*/
const float* vec() const { return &fR; }
/** Returns a pointer to components of SkRGBA4f, for array access.
@return pointer to array [fR, fG, fB, fA]
*/
float* vec() { return &fR; }
/** As a std::array<float, 4> */
std::array<float, 4> array() const { return {fR, fG, fB, fA}; }
/** Returns one component. Asserts if index is out of range and SK_DEBUG is defined.
@param index one of: 0 (fR), 1 (fG), 2 (fB), 3 (fA)
@return value corresponding to index
*/
float operator[](int index) const {
SkASSERT(index >= 0 && index < 4);
return this->vec()[index];
}
/** Returns one component. Asserts if index is out of range and SK_DEBUG is defined.
@param index one of: 0 (fR), 1 (fG), 2 (fB), 3 (fA)
@return value corresponding to index
*/
float& operator[](int index) {
SkASSERT(index >= 0 && index < 4);
return this->vec()[index];
}
/** Returns true if SkRGBA4f is an opaque color. Asserts if fA is out of range and
SK_DEBUG is defined.
@return true if SkRGBA4f is opaque
*/
bool isOpaque() const {
SkASSERT(fA <= 1.0f && fA >= 0.0f);
return fA == 1.0f;
}
/** Returns true if all channels are in [0, 1]. */
bool fitsInBytes() const {
SkASSERT(fA >= 0.0f && fA <= 1.0f);
return fR >= 0.0f && fR <= 1.0f &&
fG >= 0.0f && fG <= 1.0f &&
fB >= 0.0f && fB <= 1.0f;
}
/** Returns closest SkRGBA4f to SkColor. Only allowed if SkRGBA4f is unpremultiplied.
@param color Color with Alpha, red, blue, and green components
@return SkColor as SkRGBA4f
example: https://fiddle.skia.org/c/@RGBA4f_FromColor
*/
static SkRGBA4f FromColor(SkColor color); // impl. depends on kAT
/** Returns closest SkColor to SkRGBA4f. Only allowed if SkRGBA4f is unpremultiplied.
@return color as SkColor
example: https://fiddle.skia.org/c/@RGBA4f_toSkColor
*/
SkColor toSkColor() const; // impl. depends on kAT
/** Returns closest SkRGBA4f to SkPMColor. Only allowed if SkRGBA4f is premultiplied.
@return SkPMColor as SkRGBA4f
*/
static SkRGBA4f FromPMColor(SkPMColor); // impl. depends on kAT
/** Returns SkRGBA4f premultiplied by alpha. Asserts at compile time if SkRGBA4f is
already premultiplied.
@return premultiplied color
*/
SkRGBA4f<kPremul_SkAlphaType> premul() const {
static_assert(kAT == kUnpremul_SkAlphaType, "");
return { fR * fA, fG * fA, fB * fA, fA };
}
/** Returns SkRGBA4f unpremultiplied by alpha. Asserts at compile time if SkRGBA4f is
already unpremultiplied.
@return unpremultiplied color
*/
SkRGBA4f<kUnpremul_SkAlphaType> unpremul() const {
static_assert(kAT == kPremul_SkAlphaType, "");
if (fA == 0.0f) {
return { 0, 0, 0, 0 };
} else {
float invAlpha = 1 / fA;
return { fR * invAlpha, fG * invAlpha, fB * invAlpha, fA };
}
}
// This produces bytes in RGBA order (eg GrColor). Impl. is the same, regardless of kAT
uint32_t toBytes_RGBA() const;
static SkRGBA4f FromBytes_RGBA(uint32_t color);
/**
Returns a copy of the SkRGBA4f but with alpha component set to 1.0f.
@return opaque color
*/
SkRGBA4f makeOpaque() const {
return { fR, fG, fB, 1.0f };
}
};
/** \struct SkColor4f
RGBA color value, holding four floating point components. Color components are always in
a known order, and are unpremultiplied.
This is a specialization of SkRGBA4f. For details, @see SkRGBA4f.
*/
using SkColor4f = SkRGBA4f<kUnpremul_SkAlphaType>;
template <> SK_API SkColor4f SkColor4f::FromColor(SkColor);
template <> SK_API SkColor SkColor4f::toSkColor() const;
template <> SK_API uint32_t SkColor4f::toBytes_RGBA() const;
template <> SK_API SkColor4f SkColor4f::FromBytes_RGBA(uint32_t color);
namespace SkColors {
constexpr SkColor4f kTransparent = {0, 0, 0, 0};
constexpr SkColor4f kBlack = {0, 0, 0, 1};
constexpr SkColor4f kDkGray = {0.25f, 0.25f, 0.25f, 1};
constexpr SkColor4f kGray = {0.50f, 0.50f, 0.50f, 1};
constexpr SkColor4f kLtGray = {0.75f, 0.75f, 0.75f, 1};
constexpr SkColor4f kWhite = {1, 1, 1, 1};
constexpr SkColor4f kRed = {1, 0, 0, 1};
constexpr SkColor4f kGreen = {0, 1, 0, 1};
constexpr SkColor4f kBlue = {0, 0, 1, 1};
constexpr SkColor4f kYellow = {1, 1, 0, 1};
constexpr SkColor4f kCyan = {0, 1, 1, 1};
constexpr SkColor4f kMagenta = {1, 0, 1, 1};
} // namespace SkColors
#endif

View File

@ -0,0 +1,156 @@
/*
* Copyright 2006 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkColorFilter_DEFINED
#define SkColorFilter_DEFINED
#include "include/core/SkColor.h"
#include "include/core/SkFlattenable.h"
#include "include/core/SkRefCnt.h"
#include "include/private/base/SkAPI.h"
#include <cstddef>
#include <cstdint>
#include <utility>
class SkColorMatrix;
class SkColorSpace;
class SkColorTable;
enum class SkBlendMode;
struct SkDeserialProcs;
/**
* ColorFilters are optional objects in the drawing pipeline. When present in
* a paint, they are called with the "src" colors, and return new colors, which
* are then passed onto the next stage (either ImageFilter or Xfermode).
*
* All subclasses are required to be reentrant-safe : it must be legal to share
* the same instance between several threads.
*/
class SK_API SkColorFilter : public SkFlattenable {
public:
/** If the filter can be represented by a source color plus Mode, this
* returns true, and sets (if not NULL) the color and mode appropriately.
* If not, this returns false and ignores the parameters.
*/
bool asAColorMode(SkColor* color, SkBlendMode* mode) const;
/** If the filter can be represented by a 5x4 matrix, this
* returns true, and sets the matrix appropriately.
* If not, this returns false and ignores the parameter.
*/
bool asAColorMatrix(float matrix[20]) const;
// Returns true if the filter is guaranteed to never change the alpha of a color it filters.
bool isAlphaUnchanged() const;
/**
* Applies this filter to the input color. This function does no color management.
*
* DEPRECATED: Please use filterColor4f instead. That function supports higher precision,
* wide-gamut color, and is explicit about the color space of the input and output.
*/
SkColor filterColor(SkColor) const;
/**
* Converts the src color (in src colorspace), into the dst colorspace,
* then applies this filter to it, returning the filtered color in the dst colorspace.
*/
SkColor4f filterColor4f(const SkColor4f& srcColor, SkColorSpace* srcCS,
SkColorSpace* dstCS) const;
/** Construct a colorfilter whose effect is to first apply the inner filter and then apply
* this filter, applied to the output of the inner filter.
*
* result = this(inner(...))
*/
sk_sp<SkColorFilter> makeComposed(sk_sp<SkColorFilter> inner) const;
/** Return a colorfilter that will compute this filter in a specific color space. By default all
* filters operate in the destination (surface) color space. This allows filters like Blend and
* Matrix, or runtime color filters to perform their math in a known space.
*/
sk_sp<SkColorFilter> makeWithWorkingColorSpace(sk_sp<SkColorSpace>) const;
static sk_sp<SkColorFilter> Deserialize(const void* data, size_t size,
const SkDeserialProcs* procs = nullptr);
private:
SkColorFilter() = default;
friend class SkColorFilterBase;
using INHERITED = SkFlattenable;
};
class SK_API SkColorFilters {
public:
static sk_sp<SkColorFilter> Compose(const sk_sp<SkColorFilter>& outer,
sk_sp<SkColorFilter> inner) {
return outer ? outer->makeComposed(std::move(inner))
: std::move(inner);
}
// Blends between the constant color (src) and input color (dst) based on the SkBlendMode.
// If the color space is null, the constant color is assumed to be defined in sRGB.
static sk_sp<SkColorFilter> Blend(const SkColor4f& c, sk_sp<SkColorSpace>, SkBlendMode mode);
static sk_sp<SkColorFilter> Blend(SkColor c, SkBlendMode mode);
static sk_sp<SkColorFilter> Matrix(const SkColorMatrix&);
static sk_sp<SkColorFilter> Matrix(const float rowMajor[20]);
// A version of Matrix which operates in HSLA space instead of RGBA.
// I.e. HSLA-to-RGBA(Matrix(RGBA-to-HSLA(input))).
static sk_sp<SkColorFilter> HSLAMatrix(const SkColorMatrix&);
static sk_sp<SkColorFilter> HSLAMatrix(const float rowMajor[20]);
static sk_sp<SkColorFilter> LinearToSRGBGamma();
static sk_sp<SkColorFilter> SRGBToLinearGamma();
static sk_sp<SkColorFilter> Lerp(float t, sk_sp<SkColorFilter> dst, sk_sp<SkColorFilter> src);
/**
* Create a table colorfilter, copying the table into the filter, and
* applying it to all 4 components.
* a' = table[a];
* r' = table[r];
* g' = table[g];
* b' = table[b];
* Components are operated on in unpremultiplied space. If the incomming
* colors are premultiplied, they are temporarily unpremultiplied, then
* the table is applied, and then the result is remultiplied.
*/
static sk_sp<SkColorFilter> Table(const uint8_t table[256]);
/**
* Create a table colorfilter, with a different table for each
* component [A, R, G, B]. If a given table is NULL, then it is
* treated as identity, with the component left unchanged. If a table
* is not null, then its contents are copied into the filter.
*/
static sk_sp<SkColorFilter> TableARGB(const uint8_t tableA[256],
const uint8_t tableR[256],
const uint8_t tableG[256],
const uint8_t tableB[256]);
/**
* Create a table colorfilter that holds a ref to the shared color table.
*/
static sk_sp<SkColorFilter> Table(sk_sp<SkColorTable> table);
/**
* Create a colorfilter that multiplies the RGB channels by one color, and
* then adds a second color, pinning the result for each component to
* [0..255]. The alpha components of the mul and add arguments
* are ignored.
*/
static sk_sp<SkColorFilter> Lighting(SkColor mul, SkColor add);
private:
SkColorFilters() = delete;
};
#endif

View File

@ -0,0 +1,167 @@
/*
* Copyright 2006 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkColorPriv_DEFINED
#define SkColorPriv_DEFINED
#include "include/core/SkColor.h"
#include "include/private/base/SkMath.h"
#include "include/private/base/SkTPin.h"
#include "include/private/base/SkTo.h"
#include <algorithm>
/** Turn 0..255 into 0..256 by adding 1 at the half-way point. Used to turn a
byte into a scale value, so that we can say scale * value >> 8 instead of
alpha * value / 255.
In debugging, asserts that alpha is 0..255
*/
static inline unsigned SkAlpha255To256(U8CPU alpha) {
SkASSERT(SkToU8(alpha) == alpha);
// this one assues that blending on top of an opaque dst keeps it that way
// even though it is less accurate than a+(a>>7) for non-opaque dsts
return alpha + 1;
}
/** Multiplify value by 0..256, and shift the result down 8
(i.e. return (value * alpha256) >> 8)
*/
#define SkAlphaMul(value, alpha256) (((value) * (alpha256)) >> 8)
static inline U8CPU SkUnitScalarClampToByte(SkScalar x) {
return static_cast<U8CPU>(SkTPin(x, 0.0f, 1.0f) * 255 + 0.5);
}
#define SK_A32_BITS 8
#define SK_R32_BITS 8
#define SK_G32_BITS 8
#define SK_B32_BITS 8
#define SK_A32_MASK ((1 << SK_A32_BITS) - 1)
#define SK_R32_MASK ((1 << SK_R32_BITS) - 1)
#define SK_G32_MASK ((1 << SK_G32_BITS) - 1)
#define SK_B32_MASK ((1 << SK_B32_BITS) - 1)
/*
* Skia's 32bit backend only supports 1 swizzle order at a time (compile-time).
* This is specified by SK_R32_SHIFT=0 or SK_R32_SHIFT=16.
*
* For easier compatibility with Skia's GPU backend, we further restrict these
* to either (in memory-byte-order) RGBA or BGRA. Note that this "order" does
* not directly correspond to the same shift-order, since we have to take endianess
* into account.
*
* Here we enforce this constraint.
*/
#define SK_RGBA_R32_SHIFT 0
#define SK_RGBA_G32_SHIFT 8
#define SK_RGBA_B32_SHIFT 16
#define SK_RGBA_A32_SHIFT 24
#define SK_BGRA_B32_SHIFT 0
#define SK_BGRA_G32_SHIFT 8
#define SK_BGRA_R32_SHIFT 16
#define SK_BGRA_A32_SHIFT 24
#if defined(SK_PMCOLOR_IS_RGBA) || defined(SK_PMCOLOR_IS_BGRA)
#error "Configure PMCOLOR by setting SK_R32_SHIFT."
#endif
// Deduce which SK_PMCOLOR_IS_ to define from the _SHIFT defines
#if (SK_A32_SHIFT == SK_RGBA_A32_SHIFT && \
SK_R32_SHIFT == SK_RGBA_R32_SHIFT && \
SK_G32_SHIFT == SK_RGBA_G32_SHIFT && \
SK_B32_SHIFT == SK_RGBA_B32_SHIFT)
#define SK_PMCOLOR_IS_RGBA
#elif (SK_A32_SHIFT == SK_BGRA_A32_SHIFT && \
SK_R32_SHIFT == SK_BGRA_R32_SHIFT && \
SK_G32_SHIFT == SK_BGRA_G32_SHIFT && \
SK_B32_SHIFT == SK_BGRA_B32_SHIFT)
#define SK_PMCOLOR_IS_BGRA
#else
#error "need 32bit packing to be either RGBA or BGRA"
#endif
#define SkGetPackedA32(packed) ((uint32_t)((packed) << (24 - SK_A32_SHIFT)) >> 24)
#define SkGetPackedR32(packed) ((uint32_t)((packed) << (24 - SK_R32_SHIFT)) >> 24)
#define SkGetPackedG32(packed) ((uint32_t)((packed) << (24 - SK_G32_SHIFT)) >> 24)
#define SkGetPackedB32(packed) ((uint32_t)((packed) << (24 - SK_B32_SHIFT)) >> 24)
#define SkA32Assert(a) SkASSERT((unsigned)(a) <= SK_A32_MASK)
#define SkR32Assert(r) SkASSERT((unsigned)(r) <= SK_R32_MASK)
#define SkG32Assert(g) SkASSERT((unsigned)(g) <= SK_G32_MASK)
#define SkB32Assert(b) SkASSERT((unsigned)(b) <= SK_B32_MASK)
/**
* Pack the components into a SkPMColor, checking (in the debug version) that
* the components are 0..255, and are already premultiplied (i.e. alpha >= color)
*/
static inline SkPMColor SkPackARGB32(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
SkA32Assert(a);
SkASSERT(r <= a);
SkASSERT(g <= a);
SkASSERT(b <= a);
return (a << SK_A32_SHIFT) | (r << SK_R32_SHIFT) |
(g << SK_G32_SHIFT) | (b << SK_B32_SHIFT);
}
/**
* Same as SkPackARGB32, but this version guarantees to not check that the
* values are premultiplied in the debug version.
*/
static inline SkPMColor SkPackARGB32NoCheck(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
return (a << SK_A32_SHIFT) | (r << SK_R32_SHIFT) |
(g << SK_G32_SHIFT) | (b << SK_B32_SHIFT);
}
static inline
SkPMColor SkPremultiplyARGBInline(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
SkA32Assert(a);
SkR32Assert(r);
SkG32Assert(g);
SkB32Assert(b);
if (a != 255) {
r = SkMulDiv255Round(r, a);
g = SkMulDiv255Round(g, a);
b = SkMulDiv255Round(b, a);
}
return SkPackARGB32(a, r, g, b);
}
// When Android is compiled optimizing for size, SkAlphaMulQ doesn't get
// inlined; forcing inlining significantly improves performance.
static SK_ALWAYS_INLINE uint32_t SkAlphaMulQ(uint32_t c, unsigned scale) {
uint32_t mask = 0xFF00FF;
uint32_t rb = ((c & mask) * scale) >> 8;
uint32_t ag = ((c >> 8) & mask) * scale;
return (rb & mask) | (ag & ~mask);
}
static inline SkPMColor SkPMSrcOver(SkPMColor src, SkPMColor dst) {
uint32_t scale = SkAlpha255To256(255 - SkGetPackedA32(src));
uint32_t mask = 0xFF00FF;
uint32_t rb = (((dst & mask) * scale) >> 8) & mask;
uint32_t ag = (((dst >> 8) & mask) * scale) & ~mask;
rb += (src & mask);
ag += (src & ~mask);
// Color channels (but not alpha) can overflow, so we have to saturate to 0xFF in each lane.
return std::min(rb & 0x000001FF, 0x000000FFU) |
std::min(ag & 0x0001FF00, 0x0000FF00U) |
std::min(rb & 0x01FF0000, 0x00FF0000U) |
(ag & 0xFF000000);
}
#endif

View File

@ -0,0 +1,242 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkColorSpace_DEFINED
#define SkColorSpace_DEFINED
#include "include/core/SkRefCnt.h"
#include "include/core/SkTypes.h"
#include "include/private/base/SkFixed.h"
#include "include/private/base/SkOnce.h"
#include "modules/skcms/skcms.h"
#include <cstddef>
#include <cstdint>
class SkData;
/**
* Describes a color gamut with primaries and a white point.
*/
struct SK_API SkColorSpacePrimaries {
float fRX;
float fRY;
float fGX;
float fGY;
float fBX;
float fBY;
float fWX;
float fWY;
/**
* Convert primaries and a white point to a toXYZD50 matrix, the preferred color gamut
* representation of SkColorSpace.
*/
bool toXYZD50(skcms_Matrix3x3* toXYZD50) const;
};
namespace SkNamedTransferFn {
// Like SkNamedGamut::kSRGB, keeping this bitwise exactly the same as skcms makes things fastest.
static constexpr skcms_TransferFunction kSRGB =
{ 2.4f, (float)(1/1.055), (float)(0.055/1.055), (float)(1/12.92), 0.04045f, 0.0f, 0.0f };
static constexpr skcms_TransferFunction k2Dot2 =
{ 2.2f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
static constexpr skcms_TransferFunction kLinear =
{ 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
static constexpr skcms_TransferFunction kRec2020 =
{2.22222f, 0.909672f, 0.0903276f, 0.222222f, 0.0812429f, 0, 0};
static constexpr skcms_TransferFunction kPQ =
{-2.0f, -107/128.0f, 1.0f, 32/2523.0f, 2413/128.0f, -2392/128.0f, 8192/1305.0f };
static constexpr skcms_TransferFunction kHLG =
{-3.0f, 2.0f, 2.0f, 1/0.17883277f, 0.28466892f, 0.55991073f, 0.0f };
} // namespace SkNamedTransferFn
namespace SkNamedGamut {
static constexpr skcms_Matrix3x3 kSRGB = {{
// ICC fixed-point (16.16) representation, taken from skcms. Please keep them exactly in sync.
// 0.436065674f, 0.385147095f, 0.143066406f,
// 0.222488403f, 0.716873169f, 0.060607910f,
// 0.013916016f, 0.097076416f, 0.714096069f,
{ SkFixedToFloat(0x6FA2), SkFixedToFloat(0x6299), SkFixedToFloat(0x24A0) },
{ SkFixedToFloat(0x38F5), SkFixedToFloat(0xB785), SkFixedToFloat(0x0F84) },
{ SkFixedToFloat(0x0390), SkFixedToFloat(0x18DA), SkFixedToFloat(0xB6CF) },
}};
static constexpr skcms_Matrix3x3 kAdobeRGB = {{
// ICC fixed-point (16.16) repesentation of:
// 0.60974, 0.20528, 0.14919,
// 0.31111, 0.62567, 0.06322,
// 0.01947, 0.06087, 0.74457,
{ SkFixedToFloat(0x9c18), SkFixedToFloat(0x348d), SkFixedToFloat(0x2631) },
{ SkFixedToFloat(0x4fa5), SkFixedToFloat(0xa02c), SkFixedToFloat(0x102f) },
{ SkFixedToFloat(0x04fc), SkFixedToFloat(0x0f95), SkFixedToFloat(0xbe9c) },
}};
static constexpr skcms_Matrix3x3 kDisplayP3 = {{
{ 0.515102f, 0.291965f, 0.157153f },
{ 0.241182f, 0.692236f, 0.0665819f },
{ -0.00104941f, 0.0418818f, 0.784378f },
}};
static constexpr skcms_Matrix3x3 kRec2020 = {{
{ 0.673459f, 0.165661f, 0.125100f },
{ 0.279033f, 0.675338f, 0.0456288f },
{ -0.00193139f, 0.0299794f, 0.797162f },
}};
static constexpr skcms_Matrix3x3 kXYZ = {{
{ 1.0f, 0.0f, 0.0f },
{ 0.0f, 1.0f, 0.0f },
{ 0.0f, 0.0f, 1.0f },
}};
} // namespace SkNamedGamut
class SK_API SkColorSpace : public SkNVRefCnt<SkColorSpace> {
public:
/**
* Create the sRGB color space.
*/
static sk_sp<SkColorSpace> MakeSRGB();
/**
* Colorspace with the sRGB primaries, but a linear (1.0) gamma.
*/
static sk_sp<SkColorSpace> MakeSRGBLinear();
/**
* Create an SkColorSpace from a transfer function and a row-major 3x3 transformation to XYZ.
*/
static sk_sp<SkColorSpace> MakeRGB(const skcms_TransferFunction& transferFn,
const skcms_Matrix3x3& toXYZ);
/**
* Create an SkColorSpace from a parsed (skcms) ICC profile.
*/
static sk_sp<SkColorSpace> Make(const skcms_ICCProfile&);
/**
* Convert this color space to an skcms ICC profile struct.
*/
void toProfile(skcms_ICCProfile*) const;
/**
* Returns true if the color space gamma is near enough to be approximated as sRGB.
*/
bool gammaCloseToSRGB() const;
/**
* Returns true if the color space gamma is linear.
*/
bool gammaIsLinear() const;
/**
* Sets |fn| to the transfer function from this color space. Returns true if the transfer
* function can be represented as coefficients to the standard ICC 7-parameter equation.
* Returns false otherwise (eg, PQ, HLG).
*/
bool isNumericalTransferFn(skcms_TransferFunction* fn) const;
/**
* Returns true and sets |toXYZD50|.
*/
bool toXYZD50(skcms_Matrix3x3* toXYZD50) const;
/**
* Returns a hash of the gamut transformation to XYZ D50. Allows for fast equality checking
* of gamuts, at the (very small) risk of collision.
*/
uint32_t toXYZD50Hash() const { return fToXYZD50Hash; }
/**
* Returns a color space with the same gamut as this one, but with a linear gamma.
*/
sk_sp<SkColorSpace> makeLinearGamma() const;
/**
* Returns a color space with the same gamut as this one, but with the sRGB transfer
* function.
*/
sk_sp<SkColorSpace> makeSRGBGamma() const;
/**
* Returns a color space with the same transfer function as this one, but with the primary
* colors rotated. In other words, this produces a new color space that maps RGB to GBR
* (when applied to a source), and maps RGB to BRG (when applied to a destination).
*
* This is used for testing, to construct color spaces that have severe and testable behavior.
*/
sk_sp<SkColorSpace> makeColorSpin() const;
/**
* Returns true if the color space is sRGB.
* Returns false otherwise.
*
* This allows a little bit of tolerance, given that we might see small numerical error
* in some cases: converting ICC fixed point to float, converting white point to D50,
* rounding decisions on transfer function and matrix.
*
* This does not consider a 2.2f exponential transfer function to be sRGB. While these
* functions are similar (and it is sometimes useful to consider them together), this
* function checks for logical equality.
*/
bool isSRGB() const;
/**
* Returns a serialized representation of this color space.
*/
sk_sp<SkData> serialize() const;
/**
* If |memory| is nullptr, returns the size required to serialize.
* Otherwise, serializes into |memory| and returns the size.
*/
size_t writeToMemory(void* memory) const;
static sk_sp<SkColorSpace> Deserialize(const void* data, size_t length);
/**
* If both are null, we return true. If one is null and the other is not, we return false.
* If both are non-null, we do a deeper compare.
*/
static bool Equals(const SkColorSpace*, const SkColorSpace*);
void transferFn(float gabcdef[7]) const; // DEPRECATED: Remove when webview usage is gone
void transferFn(skcms_TransferFunction* fn) const;
void invTransferFn(skcms_TransferFunction* fn) const;
void gamutTransformTo(const SkColorSpace* dst, skcms_Matrix3x3* src_to_dst) const;
uint32_t transferFnHash() const { return fTransferFnHash; }
uint64_t hash() const { return (uint64_t)fTransferFnHash << 32 | fToXYZD50Hash; }
private:
friend class SkColorSpaceSingletonFactory;
SkColorSpace(const skcms_TransferFunction& transferFn, const skcms_Matrix3x3& toXYZ);
void computeLazyDstFields() const;
uint32_t fTransferFnHash;
uint32_t fToXYZD50Hash;
skcms_TransferFunction fTransferFn;
skcms_Matrix3x3 fToXYZD50;
mutable skcms_TransferFunction fInvTransferFn;
mutable skcms_Matrix3x3 fFromXYZD50;
mutable SkOnce fLazyDstFieldsOnce;
};
#endif

View File

@ -0,0 +1,62 @@
/*
* Copyright 2023 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkColorTable_DEFINED
#define SkColorTable_DEFINED
#include "include/core/SkBitmap.h"
#include "include/core/SkRefCnt.h"
#include "include/private/base/SkAPI.h"
#include <cstdint>
class SkReadBuffer;
class SkWriteBuffer;
/**
* SkColorTable holds the lookup tables for each channel (ARGB) used to define the filter behavior
* of `SkColorFilters::Table`, and provides a way to share the table data between client code and
* the returned SkColorFilter. Once created, an SkColorTable is immutable.
*/
class SK_API SkColorTable : public SkRefCnt {
public:
// Creates a new SkColorTable with 'table' used for all four channels. The table is copied into
// the SkColorTable.
static sk_sp<SkColorTable> Make(const uint8_t table[256]) {
return Make(table, table, table, table);
}
// Creates a new SkColorTable with the per-channel lookup tables. Each non-null table is copied
// into the SkColorTable. Null parameters are interpreted as the identity table.
static sk_sp<SkColorTable> Make(const uint8_t tableA[256],
const uint8_t tableR[256],
const uint8_t tableG[256],
const uint8_t tableB[256]);
// Per-channel constant value lookup (0-255).
const uint8_t* alphaTable() const { return fTable.getAddr8(0, 0); }
const uint8_t* redTable() const { return fTable.getAddr8(0, 1); }
const uint8_t* greenTable() const { return fTable.getAddr8(0, 2); }
const uint8_t* blueTable() const { return fTable.getAddr8(0, 3); }
void flatten(SkWriteBuffer& buffer) const;
static sk_sp<SkColorTable> Deserialize(SkReadBuffer& buffer);
private:
friend class SkTableColorFilter; // for bitmap()
SkColorTable(const SkBitmap& table) : fTable(table) {}
// The returned SkBitmap is immutable; attempting to modify its pixel data will trigger asserts
// in debug builds and cause undefined behavior in release builds.
const SkBitmap& bitmap() const { return fTable; }
SkBitmap fTable; // A 256x4 A8 image
};
#endif // SkColorTable_DEFINED

View File

@ -0,0 +1,70 @@
/*
* Copyright 2022 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkColorType_DEFINED
#define SkColorType_DEFINED
#include "include/core/SkTypes.h"
/** \enum SkColorType
Describes how pixel bits encode color. A pixel may be an alpha mask, a grayscale, RGB, or ARGB.
kN32_SkColorType selects the native 32-bit ARGB format for the current configuration. This can
lead to inconsistent results across platforms, so use with caution.
*/
enum SkColorType : int {
kUnknown_SkColorType, //!< uninitialized
kAlpha_8_SkColorType, //!< pixel with alpha in 8-bit byte
kRGB_565_SkColorType, //!< pixel with 5 bits red, 6 bits green, 5 bits blue, in 16-bit word
kARGB_4444_SkColorType, //!< pixel with 4 bits for alpha, red, green, blue; in 16-bit word
kRGBA_8888_SkColorType, //!< pixel with 8 bits for red, green, blue, alpha; in 32-bit word
kRGB_888x_SkColorType, //!< pixel with 8 bits each for red, green, blue; in 32-bit word
kBGRA_8888_SkColorType, //!< pixel with 8 bits for blue, green, red, alpha; in 32-bit word
kRGBA_1010102_SkColorType, //!< 10 bits for red, green, blue; 2 bits for alpha; in 32-bit word
kBGRA_1010102_SkColorType, //!< 10 bits for blue, green, red; 2 bits for alpha; in 32-bit word
kRGB_101010x_SkColorType, //!< pixel with 10 bits each for red, green, blue; in 32-bit word
kBGR_101010x_SkColorType, //!< pixel with 10 bits each for blue, green, red; in 32-bit word
kBGR_101010x_XR_SkColorType, //!< pixel with 10 bits each for blue, green, red; in 32-bit word, extended range
kBGRA_10101010_XR_SkColorType, //!< pixel with 10 bits each for blue, green, red, alpha; in 64-bit word, extended range
kRGBA_10x6_SkColorType, //!< pixel with 10 used bits (most significant) followed by 6 unused
// bits for red, green, blue, alpha; in 64-bit word
kGray_8_SkColorType, //!< pixel with grayscale level in 8-bit byte
kRGBA_F16Norm_SkColorType, //!< pixel with half floats in [0,1] for red, green, blue, alpha;
// in 64-bit word
kRGBA_F16_SkColorType, //!< pixel with half floats for red, green, blue, alpha;
// in 64-bit word
kRGBA_F32_SkColorType, //!< pixel using C float for red, green, blue, alpha; in 128-bit word
// The following 6 colortypes are just for reading from - not for rendering to
kR8G8_unorm_SkColorType, //!< pixel with a uint8_t for red and green
kA16_float_SkColorType, //!< pixel with a half float for alpha
kR16G16_float_SkColorType, //!< pixel with a half float for red and green
kA16_unorm_SkColorType, //!< pixel with a little endian uint16_t for alpha
kR16G16_unorm_SkColorType, //!< pixel with a little endian uint16_t for red and green
kR16G16B16A16_unorm_SkColorType, //!< pixel with a little endian uint16_t for red, green, blue
// and alpha
kSRGBA_8888_SkColorType,
kR8_unorm_SkColorType,
kLastEnum_SkColorType = kR8_unorm_SkColorType, //!< last valid value
#if SK_PMCOLOR_BYTE_ORDER(B,G,R,A)
kN32_SkColorType = kBGRA_8888_SkColorType,//!< native 32-bit BGRA encoding
#elif SK_PMCOLOR_BYTE_ORDER(R,G,B,A)
kN32_SkColorType = kRGBA_8888_SkColorType,//!< native 32-bit RGBA encoding
#else
#error "SK_*32_SHIFT values must correspond to BGRA or RGBA byte order"
#endif
};
static constexpr int kSkColorTypeCnt = static_cast<int>(kLastEnum_SkColorType) + 1;
#endif

View File

@ -0,0 +1,139 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkContourMeasure_DEFINED
#define SkContourMeasure_DEFINED
#include "include/core/SkPoint.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/private/base/SkAPI.h"
#include "include/private/base/SkTDArray.h"
#include <memory>
class SkMatrix;
class SkPath;
class SK_API SkContourMeasure : public SkRefCnt {
public:
/** Return the length of the contour.
*/
SkScalar length() const { return fLength; }
/** Pins distance to 0 <= distance <= length(), and then computes the corresponding
* position and tangent.
*/
[[nodiscard]] bool getPosTan(SkScalar distance, SkPoint* position, SkVector* tangent) const;
enum MatrixFlags {
kGetPosition_MatrixFlag = 0x01,
kGetTangent_MatrixFlag = 0x02,
kGetPosAndTan_MatrixFlag = kGetPosition_MatrixFlag | kGetTangent_MatrixFlag
};
/** Pins distance to 0 <= distance <= getLength(), and then computes
the corresponding matrix (by calling getPosTan).
Returns false if there is no path, or a zero-length path was specified, in which case
matrix is unchanged.
*/
[[nodiscard]] bool getMatrix(SkScalar distance, SkMatrix* matrix,
MatrixFlags flags = kGetPosAndTan_MatrixFlag) const;
/** Given a start and stop distance, return in dst the intervening segment(s).
If the segment is zero-length, return false, else return true.
startD and stopD are pinned to legal values (0..getLength()). If startD > stopD
then return false (and leave dst untouched).
Begin the segment with a moveTo if startWithMoveTo is true
*/
[[nodiscard]] bool getSegment(SkScalar startD, SkScalar stopD, SkPath* dst,
bool startWithMoveTo) const;
/** Return true if the contour is closed()
*/
bool isClosed() const { return fIsClosed; }
private:
struct Segment {
SkScalar fDistance; // total distance up to this point
unsigned fPtIndex; // index into the fPts array
unsigned fTValue : 30;
unsigned fType : 2; // actually the enum SkSegType
// See SkPathMeasurePriv.h
SkScalar getScalarT() const;
static const Segment* Next(const Segment* seg) {
unsigned ptIndex = seg->fPtIndex;
do {
++seg;
} while (seg->fPtIndex == ptIndex);
return seg;
}
};
const SkTDArray<Segment> fSegments;
const SkTDArray<SkPoint> fPts; // Points used to define the segments
const SkScalar fLength;
const bool fIsClosed;
SkContourMeasure(SkTDArray<Segment>&& segs, SkTDArray<SkPoint>&& pts,
SkScalar length, bool isClosed);
~SkContourMeasure() override {}
const Segment* distanceToSegment(SkScalar distance, SkScalar* t) const;
friend class SkContourMeasureIter;
friend class SkPathMeasurePriv;
};
class SK_API SkContourMeasureIter {
public:
SkContourMeasureIter();
/**
* Initialize the Iter with a path.
* The parts of the path that are needed are copied, so the client is free to modify/delete
* the path after this call.
*
* resScale controls the precision of the measure. values > 1 increase the
* precision (and possibly slow down the computation).
*/
SkContourMeasureIter(const SkPath& path, bool forceClosed, SkScalar resScale = 1);
~SkContourMeasureIter();
SkContourMeasureIter(SkContourMeasureIter&&);
SkContourMeasureIter& operator=(SkContourMeasureIter&&);
/**
* Reset the Iter with a path.
* The parts of the path that are needed are copied, so the client is free to modify/delete
* the path after this call.
*/
void reset(const SkPath& path, bool forceClosed, SkScalar resScale = 1);
/**
* Iterates through contours in path, returning a contour-measure object for each contour
* in the path. Returns null when it is done.
*
* This only returns non-zero length contours, where a contour is the segments between
* a kMove_Verb and either ...
* - the next kMove_Verb
* - kClose_Verb (1 or more)
* - kDone_Verb
* If it encounters a zero-length contour, it is skipped.
*/
sk_sp<SkContourMeasure> next();
private:
class Impl;
std::unique_ptr<Impl> fImpl;
};
#endif

View File

@ -0,0 +1,28 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkCoverageMode_DEFINED
#define SkCoverageMode_DEFINED
/**
* Describes geometric operations (ala SkRegion::Op) that can be applied to coverage bytes.
* These can be thought of as variants of porter-duff (SkBlendMode) modes, but only applied
* to the alpha channel.
*
* See SkMaskFilter for ways to use these when combining two different masks.
*/
enum class SkCoverageMode {
kUnion, // A B A+B-A*B
kIntersect, // A ∩ B A*B
kDifference, // A - B A*(1-B)
kReverseDifference, // B - A B*(1-A)
kXor, // A ⊕ B A+B-2*A*B
kLast = kXor,
};
#endif

View File

@ -0,0 +1,47 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkCubicMap_DEFINED
#define SkCubicMap_DEFINED
#include "include/core/SkPoint.h"
#include "include/core/SkScalar.h"
#include "include/core/SkTypes.h"
/**
* Fast evaluation of a cubic ease-in / ease-out curve. This is defined as a parametric cubic
* curve inside the unit square.
*
* pt[0] is implicitly { 0, 0 }
* pt[3] is implicitly { 1, 1 }
* pts[1,2].X are inside the unit [0..1]
*/
class SK_API SkCubicMap {
public:
SkCubicMap(SkPoint p1, SkPoint p2);
static bool IsLinear(SkPoint p1, SkPoint p2) {
return SkScalarNearlyEqual(p1.fX, p1.fY) && SkScalarNearlyEqual(p2.fX, p2.fY);
}
float computeYFromX(float x) const;
SkPoint computeFromT(float t) const;
private:
enum Type {
kLine_Type, // x == y
kCubeRoot_Type, // At^3 == x
kSolver_Type, // general monotonic cubic solver
};
SkPoint fCoeff[3];
Type fType;
};
#endif

View File

@ -0,0 +1,191 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkData_DEFINED
#define SkData_DEFINED
#include "include/core/SkRefCnt.h"
#include "include/private/base/SkAPI.h"
#include "include/private/base/SkAssert.h"
#include <cstdint>
#include <cstdio>
class SkStream;
/**
* SkData holds an immutable data buffer. Not only is the data immutable,
* but the actual ptr that is returned (by data() or bytes()) is guaranteed
* to always be the same for the life of this instance.
*/
class SK_API SkData final : public SkNVRefCnt<SkData> {
public:
/**
* Returns the number of bytes stored.
*/
size_t size() const { return fSize; }
bool isEmpty() const { return 0 == fSize; }
/**
* Returns the ptr to the data.
*/
const void* data() const { return fPtr; }
/**
* Like data(), returns a read-only ptr into the data, but in this case
* it is cast to uint8_t*, to make it easy to add an offset to it.
*/
const uint8_t* bytes() const {
return reinterpret_cast<const uint8_t*>(fPtr);
}
/**
* USE WITH CAUTION.
* This call will assert that the refcnt is 1, as a precaution against modifying the
* contents when another client/thread has access to the data.
*/
void* writable_data() {
if (fSize) {
// only assert we're unique if we're not empty
SkASSERT(this->unique());
}
return const_cast<void*>(fPtr);
}
/**
* Helper to copy a range of the data into a caller-provided buffer.
* Returns the actual number of bytes copied, after clamping offset and
* length to the size of the data. If buffer is NULL, it is ignored, and
* only the computed number of bytes is returned.
*/
size_t copyRange(size_t offset, size_t length, void* buffer) const;
/**
* Returns true if these two objects have the same length and contents,
* effectively returning 0 == memcmp(...)
*/
bool equals(const SkData* other) const;
/**
* Function that, if provided, will be called when the SkData goes out
* of scope, allowing for custom allocation/freeing of the data's contents.
*/
typedef void (*ReleaseProc)(const void* ptr, void* context);
/**
* Create a new dataref by copying the specified data
*/
static sk_sp<SkData> MakeWithCopy(const void* data, size_t length);
/**
* Create a new data with uninitialized contents. The caller should call writable_data()
* to write into the buffer, but this must be done before another ref() is made.
*/
static sk_sp<SkData> MakeUninitialized(size_t length);
/**
* Create a new data with zero-initialized contents. The caller should call writable_data()
* to write into the buffer, but this must be done before another ref() is made.
*/
static sk_sp<SkData> MakeZeroInitialized(size_t length);
/**
* Create a new dataref by copying the specified c-string
* (a null-terminated array of bytes). The returned SkData will have size()
* equal to strlen(cstr) + 1. If cstr is NULL, it will be treated the same
* as "".
*/
static sk_sp<SkData> MakeWithCString(const char cstr[]);
/**
* Create a new dataref, taking the ptr as is, and using the
* releaseproc to free it. The proc may be NULL.
*/
static sk_sp<SkData> MakeWithProc(const void* ptr, size_t length, ReleaseProc proc, void* ctx);
/**
* Call this when the data parameter is already const and will outlive the lifetime of the
* SkData. Suitable for with const globals.
*/
static sk_sp<SkData> MakeWithoutCopy(const void* data, size_t length) {
return MakeWithProc(data, length, NoopReleaseProc, nullptr);
}
/**
* Create a new dataref from a pointer allocated by malloc. The Data object
* takes ownership of that allocation, and will handling calling sk_free.
*/
static sk_sp<SkData> MakeFromMalloc(const void* data, size_t length);
/**
* Create a new dataref the file with the specified path.
* If the file cannot be opened, this returns NULL.
*/
static sk_sp<SkData> MakeFromFileName(const char path[]);
/**
* Create a new dataref from a stdio FILE.
* This does not take ownership of the FILE, nor close it.
* The caller is free to close the FILE at its convenience.
* The FILE must be open for reading only.
* Returns NULL on failure.
*/
static sk_sp<SkData> MakeFromFILE(FILE* f);
/**
* Create a new dataref from a file descriptor.
* This does not take ownership of the file descriptor, nor close it.
* The caller is free to close the file descriptor at its convenience.
* The file descriptor must be open for reading only.
* Returns NULL on failure.
*/
static sk_sp<SkData> MakeFromFD(int fd);
/**
* Attempt to read size bytes into a SkData. If the read succeeds, return the data,
* else return NULL. Either way the stream's cursor may have been changed as a result
* of calling read().
*/
static sk_sp<SkData> MakeFromStream(SkStream*, size_t size);
/**
* Create a new dataref using a subset of the data in the specified
* src dataref.
*/
static sk_sp<SkData> MakeSubset(const SkData* src, size_t offset, size_t length);
/**
* Returns a new empty dataref (or a reference to a shared empty dataref).
* New or shared, the caller must see that unref() is eventually called.
*/
static sk_sp<SkData> MakeEmpty();
private:
friend class SkNVRefCnt<SkData>;
ReleaseProc fReleaseProc;
void* fReleaseProcContext;
const void* fPtr;
size_t fSize;
SkData(const void* ptr, size_t size, ReleaseProc, void* context);
explicit SkData(size_t size); // inplace new/delete
~SkData();
// Ensure the unsized delete is called.
void operator delete(void* p);
// shared internal factory
static sk_sp<SkData> PrivateNewWithCopy(const void* srcOrNull, size_t length);
static void NoopReleaseProc(const void*, void*); // {}
using INHERITED = SkRefCnt;
};
#endif

View File

@ -0,0 +1,122 @@
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkDataTable_DEFINED
#define SkDataTable_DEFINED
#include "include/core/SkRefCnt.h"
#include "include/private/base/SkAPI.h"
#include "include/private/base/SkAssert.h"
#include <cstdint>
#include <cstring>
/**
* Like SkData, SkDataTable holds an immutable data buffer. The data buffer is
* organized into a table of entries, each with a length, so the entries are
* not required to all be the same size.
*/
class SK_API SkDataTable : public SkRefCnt {
public:
/**
* Returns true if the table is empty (i.e. has no entries).
*/
bool isEmpty() const { return 0 == fCount; }
/**
* Return the number of entries in the table. 0 for an empty table
*/
int count() const { return fCount; }
/**
* Return the size of the index'th entry in the table. The caller must
* ensure that index is valid for this table.
*/
size_t atSize(int index) const;
/**
* Return a pointer to the data of the index'th entry in the table.
* The caller must ensure that index is valid for this table.
*
* @param size If non-null, this returns the byte size of this entry. This
* will be the same value that atSize(index) would return.
*/
const void* at(int index, size_t* size = nullptr) const;
template <typename T>
const T* atT(int index, size_t* size = nullptr) const {
return reinterpret_cast<const T*>(this->at(index, size));
}
/**
* Returns the index'th entry as a c-string, and assumes that the trailing
* null byte had been copied into the table as well.
*/
const char* atStr(int index) const {
size_t size;
const char* str = this->atT<const char>(index, &size);
SkASSERT(strlen(str) + 1 == size);
return str;
}
typedef void (*FreeProc)(void* context);
static sk_sp<SkDataTable> MakeEmpty();
/**
* Return a new DataTable that contains a copy of the data stored in each
* "array".
*
* @param ptrs array of points to each element to be copied into the table.
* @param sizes array of byte-lengths for each entry in the corresponding
* ptrs[] array.
* @param count the number of array elements in ptrs[] and sizes[] to copy.
*/
static sk_sp<SkDataTable> MakeCopyArrays(const void * const * ptrs,
const size_t sizes[], int count);
/**
* Return a new table that contains a copy of the data in array.
*
* @param array contiguous array of data for all elements to be copied.
* @param elemSize byte-length for a given element.
* @param count the number of entries to be copied out of array. The number
* of bytes that will be copied is count * elemSize.
*/
static sk_sp<SkDataTable> MakeCopyArray(const void* array, size_t elemSize, int count);
static sk_sp<SkDataTable> MakeArrayProc(const void* array, size_t elemSize, int count,
FreeProc proc, void* context);
private:
struct Dir {
const void* fPtr;
uintptr_t fSize;
};
int fCount;
size_t fElemSize;
union {
const Dir* fDir;
const char* fElems;
} fU;
FreeProc fFreeProc;
void* fFreeProcContext;
SkDataTable();
SkDataTable(const void* array, size_t elemSize, int count,
FreeProc, void* context);
SkDataTable(const Dir*, int count, FreeProc, void* context);
~SkDataTable() override;
friend class SkDataTableBuilder; // access to Dir
using INHERITED = SkRefCnt;
};
#endif

View File

@ -0,0 +1,93 @@
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkDocument_DEFINED
#define SkDocument_DEFINED
#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/private/base/SkAPI.h"
class SkCanvas;
class SkWStream;
struct SkRect;
/** SK_ScalarDefaultDPI is 72 dots per inch. */
static constexpr SkScalar SK_ScalarDefaultRasterDPI = 72.0f;
/**
* High-level API for creating a document-based canvas. To use..
*
* 1. Create a document, specifying a stream to store the output.
* 2. For each "page" of content:
* a. canvas = doc->beginPage(...)
* b. draw_my_content(canvas);
* c. doc->endPage();
* 3. Close the document with doc->close().
*/
class SK_API SkDocument : public SkRefCnt {
public:
/**
* Begin a new page for the document, returning the canvas that will draw
* into the page. The document owns this canvas, and it will go out of
* scope when endPage() or close() is called, or the document is deleted.
* This will call endPage() if there is a currently active page.
*/
SkCanvas* beginPage(SkScalar width, SkScalar height, const SkRect* content = nullptr);
/**
* Call endPage() when the content for the current page has been drawn
* (into the canvas returned by beginPage()). After this call the canvas
* returned by beginPage() will be out-of-scope.
*/
void endPage();
/**
* Call close() when all pages have been drawn. This will close the file
* or stream holding the document's contents. After close() the document
* can no longer add new pages. Deleting the document will automatically
* call close() if need be.
*/
void close();
/**
* Call abort() to stop producing the document immediately.
* The stream output must be ignored, and should not be trusted.
*/
void abort();
protected:
SkDocument(SkWStream*);
// note: subclasses must call close() in their destructor, as the base class
// cannot do this for them.
~SkDocument() override;
virtual SkCanvas* onBeginPage(SkScalar width, SkScalar height) = 0;
virtual void onEndPage() = 0;
virtual void onClose(SkWStream*) = 0;
virtual void onAbort() = 0;
// Allows subclasses to write to the stream as pages are written.
SkWStream* getStream() { return fStream; }
enum State {
kBetweenPages_State,
kInPage_State,
kClosed_State
};
State getState() const { return fState; }
private:
SkWStream* fStream;
State fState;
using INHERITED = SkRefCnt;
};
#endif

View File

@ -0,0 +1,178 @@
/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkDrawable_DEFINED
#define SkDrawable_DEFINED
#include "include/core/SkFlattenable.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/private/base/SkAPI.h"
#include <cstddef>
#include <cstdint>
#include <memory>
class GrBackendDrawableInfo;
class SkCanvas;
class SkMatrix;
class SkPicture;
enum class GrBackendApi : unsigned int;
struct SkDeserialProcs;
struct SkIRect;
struct SkImageInfo;
struct SkRect;
/**
* Base-class for objects that draw into SkCanvas.
*
* The object has a generation ID, which is guaranteed to be unique across all drawables. To
* allow for clients of the drawable that may want to cache the results, the drawable must
* change its generation ID whenever its internal state changes such that it will draw differently.
*/
class SK_API SkDrawable : public SkFlattenable {
public:
/**
* Draws into the specified content. The drawing sequence will be balanced upon return
* (i.e. the saveLevel() on the canvas will match what it was when draw() was called,
* and the current matrix and clip settings will not be changed.
*/
void draw(SkCanvas*, const SkMatrix* = nullptr);
void draw(SkCanvas*, SkScalar x, SkScalar y);
/**
* When using the GPU backend it is possible for a drawable to execute using the underlying 3D
* API rather than the SkCanvas API. It does so by creating a GpuDrawHandler. The GPU backend
* is deferred so the handler will be given access to the 3D API at the correct point in the
* drawing stream as the GPU backend flushes. Since the drawable may mutate, each time it is
* drawn to a GPU-backed canvas a new handler is snapped, representing the drawable's state at
* the time of the snap.
*
* When the GPU backend flushes to the 3D API it will call the draw method on the
* GpuDrawHandler. At this time the drawable may add commands to the stream of GPU commands for
* the unerlying 3D API. The draw function takes a GrBackendDrawableInfo which contains
* information about the current state of 3D API which the caller must respect. See
* GrBackendDrawableInfo for more specific details on what information is sent and the
* requirements for different 3D APIs.
*
* Additionaly there may be a slight delay from when the drawable adds its commands to when
* those commands are actually submitted to the GPU. Thus the drawable or GpuDrawHandler is
* required to keep any resources that are used by its added commands alive and valid until
* those commands are submitted to the GPU. The GpuDrawHandler will be kept alive and then
* deleted once the commands are submitted to the GPU. The dtor of the GpuDrawHandler is the
* signal to the drawable that the commands have all been submitted. Different 3D APIs may have
* additional requirements for certain resources which require waiting for the GPU to finish
* all work on those resources before reusing or deleting them. In this case, the drawable can
* use the dtor call of the GpuDrawHandler to add a fence to the GPU to track when the GPU work
* has completed.
*
* Currently this is only supported for the GPU Vulkan backend.
*/
class GpuDrawHandler {
public:
virtual ~GpuDrawHandler() {}
virtual void draw(const GrBackendDrawableInfo&) {}
};
/**
* Snaps off a GpuDrawHandler to represent the state of the SkDrawable at the time the snap is
* called. This is used for executing GPU backend specific draws intermixed with normal Skia GPU
* draws. The GPU API, which will be used for the draw, as well as the full matrix, device clip
* bounds and imageInfo of the target buffer are passed in as inputs.
*/
std::unique_ptr<GpuDrawHandler> snapGpuDrawHandler(GrBackendApi backendApi,
const SkMatrix& matrix,
const SkIRect& clipBounds,
const SkImageInfo& bufferInfo) {
return this->onSnapGpuDrawHandler(backendApi, matrix, clipBounds, bufferInfo);
}
/**
* Returns an SkPicture with the contents of this SkDrawable.
*/
sk_sp<SkPicture> makePictureSnapshot();
/**
* Return a unique value for this instance. If two calls to this return the same value,
* it is presumed that calling the draw() method will render the same thing as well.
*
* Subclasses that change their state should call notifyDrawingChanged() to ensure that
* a new value will be returned the next time it is called.
*/
uint32_t getGenerationID();
/**
* Return the (conservative) bounds of what the drawable will draw. If the drawable can
* change what it draws (e.g. animation or in response to some external change), then this
* must return a bounds that is always valid for all possible states.
*/
SkRect getBounds();
/**
* Return approximately how many bytes would be freed if this drawable is destroyed.
* The base implementation returns 0 to indicate that this is unknown.
*/
size_t approximateBytesUsed();
/**
* Calling this invalidates the previous generation ID, and causes a new one to be computed
* the next time getGenerationID() is called. Typically this is called by the object itself,
* in response to its internal state changing.
*/
void notifyDrawingChanged();
static SkFlattenable::Type GetFlattenableType() {
return kSkDrawable_Type;
}
SkFlattenable::Type getFlattenableType() const override {
return kSkDrawable_Type;
}
static sk_sp<SkDrawable> Deserialize(const void* data, size_t size,
const SkDeserialProcs* procs = nullptr) {
return sk_sp<SkDrawable>(static_cast<SkDrawable*>(
SkFlattenable::Deserialize(
kSkDrawable_Type, data, size, procs).release()));
}
Factory getFactory() const override { return nullptr; }
const char* getTypeName() const override { return nullptr; }
protected:
SkDrawable();
virtual SkRect onGetBounds() = 0;
virtual size_t onApproximateBytesUsed();
virtual void onDraw(SkCanvas*) = 0;
virtual std::unique_ptr<GpuDrawHandler> onSnapGpuDrawHandler(GrBackendApi, const SkMatrix&,
const SkIRect& /*clipBounds*/,
const SkImageInfo&) {
return nullptr;
}
// TODO: Delete this once Android gets updated to take the clipBounds version above.
virtual std::unique_ptr<GpuDrawHandler> onSnapGpuDrawHandler(GrBackendApi, const SkMatrix&) {
return nullptr;
}
/**
* Default implementation calls onDraw() with a canvas that records into a picture. Subclasses
* may override if they have a more efficient way to return a picture for the current state
* of their drawable. Note: this picture must draw the same as what would be drawn from
* onDraw().
*/
virtual sk_sp<SkPicture> onMakePictureSnapshot();
private:
int32_t fGenerationID;
};
#endif

View File

@ -0,0 +1,41 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkExecutor_DEFINED
#define SkExecutor_DEFINED
#include <functional>
#include <memory>
#include "include/core/SkTypes.h"
class SK_API SkExecutor {
public:
virtual ~SkExecutor();
// Create a thread pool SkExecutor with a fixed thread count, by default the number of cores.
static std::unique_ptr<SkExecutor> MakeFIFOThreadPool(int threads = 0,
bool allowBorrowing = true);
static std::unique_ptr<SkExecutor> MakeLIFOThreadPool(int threads = 0,
bool allowBorrowing = true);
// There is always a default SkExecutor available by calling SkExecutor::GetDefault().
static SkExecutor& GetDefault();
static void SetDefault(SkExecutor*); // Does not take ownership. Not thread safe.
// Add work to execute.
virtual void add(std::function<void(void)>) = 0;
// If it makes sense for this executor, use this thread to execute work for a little while.
virtual void borrow() {}
protected:
SkExecutor() = default;
SkExecutor(const SkExecutor&) = delete;
SkExecutor& operator=(const SkExecutor&) = delete;
};
#endif//SkExecutor_DEFINED

View File

@ -0,0 +1,115 @@
/*
* Copyright 2006 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkFlattenable_DEFINED
#define SkFlattenable_DEFINED
#include "include/core/SkRefCnt.h"
#include "include/core/SkTypes.h"
#include <cstddef>
class SkData;
class SkReadBuffer;
class SkWriteBuffer;
struct SkDeserialProcs;
struct SkSerialProcs;
/** \class SkFlattenable
SkFlattenable is the base class for objects that need to be flattened
into a data stream for either transport or as part of the key to the
font cache.
*/
class SK_API SkFlattenable : public SkRefCnt {
public:
enum Type {
kSkColorFilter_Type,
kSkBlender_Type,
kSkDrawable_Type,
kSkDrawLooper_Type, // no longer supported by Skia
kSkImageFilter_Type,
kSkMaskFilter_Type,
kSkPathEffect_Type,
kSkShader_Type,
};
typedef sk_sp<SkFlattenable> (*Factory)(SkReadBuffer&);
SkFlattenable() {}
/** Implement this to return a factory function pointer that can be called
to recreate your class given a buffer (previously written to by your
override of flatten().
*/
virtual Factory getFactory() const = 0;
/**
* Returns the name of the object's class.
*/
virtual const char* getTypeName() const = 0;
static Factory NameToFactory(const char name[]);
static const char* FactoryToName(Factory);
static void Register(const char name[], Factory);
/**
* Override this if your subclass needs to record data that it will need to recreate itself
* from its CreateProc (returned by getFactory()).
*
* DEPRECATED public : will move to protected ... use serialize() instead
*/
virtual void flatten(SkWriteBuffer&) const {}
virtual Type getFlattenableType() const = 0;
//
// public ways to serialize / deserialize
//
sk_sp<SkData> serialize(const SkSerialProcs* = nullptr) const;
size_t serialize(void* memory, size_t memory_size,
const SkSerialProcs* = nullptr) const;
static sk_sp<SkFlattenable> Deserialize(Type, const void* data, size_t length,
const SkDeserialProcs* procs = nullptr);
protected:
class PrivateInitializer {
public:
static void InitEffects();
static void InitImageFilters();
};
private:
static void RegisterFlattenablesIfNeeded();
static void Finalize();
friend class SkGraphics;
using INHERITED = SkRefCnt;
};
#if defined(SK_DISABLE_EFFECT_DESERIALIZATION)
#define SK_REGISTER_FLATTENABLE(type) do{}while(false)
#define SK_FLATTENABLE_HOOKS(type) \
static sk_sp<SkFlattenable> CreateProc(SkReadBuffer&); \
friend class SkFlattenable::PrivateInitializer; \
Factory getFactory() const override { return nullptr; } \
const char* getTypeName() const override { return #type; }
#else
#define SK_REGISTER_FLATTENABLE(type) \
SkFlattenable::Register(#type, type::CreateProc)
#define SK_FLATTENABLE_HOOKS(type) \
static sk_sp<SkFlattenable> CreateProc(SkReadBuffer&); \
friend class SkFlattenable::PrivateInitializer; \
Factory getFactory() const override { return type::CreateProc; } \
const char* getTypeName() const override { return #type; }
#endif
#endif

View File

@ -0,0 +1,539 @@
/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkFont_DEFINED
#define SkFont_DEFINED
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/core/SkTypeface.h"
#include "include/core/SkTypes.h"
#include "include/private/base/SkTo.h"
#include "include/private/base/SkTypeTraits.h"
#include <cstddef>
#include <cstdint>
#include <type_traits>
#include <vector>
class SkMatrix;
class SkPaint;
class SkPath;
enum class SkFontHinting;
enum class SkTextEncoding;
struct SkFontMetrics;
struct SkPoint;
/** \class SkFont
SkFont controls options applied when drawing and measuring text.
*/
class SK_API SkFont {
public:
/** Whether edge pixels draw opaque or with partial transparency.
*/
enum class Edging {
kAlias, //!< no transparent pixels on glyph edges
kAntiAlias, //!< may have transparent pixels on glyph edges
kSubpixelAntiAlias, //!< glyph positioned in pixel using transparency
};
/** Constructs SkFont with default values.
@return default initialized SkFont
*/
SkFont();
/** Constructs SkFont with default values with SkTypeface and size in points.
@param typeface font and style used to draw and measure text
@param size typographic height of text
@return initialized SkFont
*/
SkFont(sk_sp<SkTypeface> typeface, SkScalar size);
/** Constructs SkFont with default values with SkTypeface.
@param typeface font and style used to draw and measure text
@return initialized SkFont
*/
explicit SkFont(sk_sp<SkTypeface> typeface);
/** Constructs SkFont with default values with SkTypeface and size in points,
horizontal scale, and horizontal skew. Horizontal scale emulates condensed
and expanded fonts. Horizontal skew emulates oblique fonts.
@param typeface font and style used to draw and measure text
@param size typographic height of text
@param scaleX text horizontal scale
@param skewX additional shear on x-axis relative to y-axis
@return initialized SkFont
*/
SkFont(sk_sp<SkTypeface> typeface, SkScalar size, SkScalar scaleX, SkScalar skewX);
/** Compares SkFont and font, and returns true if they are equivalent.
May return false if SkTypeface has identical contents but different pointers.
@param font font to compare
@return true if SkFont pair are equivalent
*/
bool operator==(const SkFont& font) const;
/** Compares SkFont and font, and returns true if they are not equivalent.
May return true if SkTypeface has identical contents but different pointers.
@param font font to compare
@return true if SkFont pair are not equivalent
*/
bool operator!=(const SkFont& font) const { return !(*this == font); }
/** If true, instructs the font manager to always hint glyphs.
Returned value is only meaningful if platform uses FreeType as the font manager.
@return true if all glyphs are hinted
*/
bool isForceAutoHinting() const { return SkToBool(fFlags & kForceAutoHinting_PrivFlag); }
/** Returns true if font engine may return glyphs from font bitmaps instead of from outlines.
@return true if glyphs may be font bitmaps
*/
bool isEmbeddedBitmaps() const { return SkToBool(fFlags & kEmbeddedBitmaps_PrivFlag); }
/** Returns true if glyphs may be drawn at sub-pixel offsets.
@return true if glyphs may be drawn at sub-pixel offsets.
*/
bool isSubpixel() const { return SkToBool(fFlags & kSubpixel_PrivFlag); }
/** Returns true if font and glyph metrics are requested to be linearly scalable.
@return true if font and glyph metrics are requested to be linearly scalable.
*/
bool isLinearMetrics() const { return SkToBool(fFlags & kLinearMetrics_PrivFlag); }
/** Returns true if bold is approximated by increasing the stroke width when creating glyph
bitmaps from outlines.
@return bold is approximated through stroke width
*/
bool isEmbolden() const { return SkToBool(fFlags & kEmbolden_PrivFlag); }
/** Returns true if baselines will be snapped to pixel positions when the current transformation
matrix is axis aligned.
@return baselines may be snapped to pixels
*/
bool isBaselineSnap() const { return SkToBool(fFlags & kBaselineSnap_PrivFlag); }
/** Sets whether to always hint glyphs.
If forceAutoHinting is set, instructs the font manager to always hint glyphs.
Only affects platforms that use FreeType as the font manager.
@param forceAutoHinting setting to always hint glyphs
*/
void setForceAutoHinting(bool forceAutoHinting);
/** Requests, but does not require, to use bitmaps in fonts instead of outlines.
@param embeddedBitmaps setting to use bitmaps in fonts
*/
void setEmbeddedBitmaps(bool embeddedBitmaps);
/** Requests, but does not require, that glyphs respect sub-pixel positioning.
@param subpixel setting for sub-pixel positioning
*/
void setSubpixel(bool subpixel);
/** Requests, but does not require, linearly scalable font and glyph metrics.
For outline fonts 'true' means font and glyph metrics should ignore hinting and rounding.
Note that some bitmap formats may not be able to scale linearly and will ignore this flag.
@param linearMetrics setting for linearly scalable font and glyph metrics.
*/
void setLinearMetrics(bool linearMetrics);
/** Increases stroke width when creating glyph bitmaps to approximate a bold typeface.
@param embolden setting for bold approximation
*/
void setEmbolden(bool embolden);
/** Requests that baselines be snapped to pixels when the current transformation matrix is axis
aligned.
@param baselineSnap setting for baseline snapping to pixels
*/
void setBaselineSnap(bool baselineSnap);
/** Whether edge pixels draw opaque or with partial transparency.
*/
Edging getEdging() const { return (Edging)fEdging; }
/** Requests, but does not require, that edge pixels draw opaque or with
partial transparency.
*/
void setEdging(Edging edging);
/** Sets level of glyph outline adjustment.
Does not check for valid values of hintingLevel.
*/
void setHinting(SkFontHinting hintingLevel);
/** Returns level of glyph outline adjustment.
*/
SkFontHinting getHinting() const { return (SkFontHinting)fHinting; }
/** Returns a font with the same attributes of this font, but with the specified size.
Returns nullptr if size is less than zero, infinite, or NaN.
@param size typographic height of text
@return initialized SkFont
*/
SkFont makeWithSize(SkScalar size) const;
/** Does not alter SkTypeface SkRefCnt.
@return non-null SkTypeface
*/
SkTypeface* getTypeface() const {
SkASSERT(fTypeface);
return fTypeface.get();
}
/** Returns text size in points.
@return typographic height of text
*/
SkScalar getSize() const { return fSize; }
/** Returns text scale on x-axis.
Default value is 1.
@return text horizontal scale
*/
SkScalar getScaleX() const { return fScaleX; }
/** Returns text skew on x-axis.
Default value is zero.
@return additional shear on x-axis relative to y-axis
*/
SkScalar getSkewX() const { return fSkewX; }
/** Increases SkTypeface SkRefCnt by one.
@return A non-null SkTypeface.
*/
sk_sp<SkTypeface> refTypeface() const {
SkASSERT(fTypeface);
return fTypeface;
}
/** Sets SkTypeface to typeface, decreasing SkRefCnt of the previous SkTypeface.
Pass nullptr to clear SkTypeface and use an empty typeface (which draws nothing).
Increments tf SkRefCnt by one.
@param tf font and style used to draw text
*/
void setTypeface(sk_sp<SkTypeface> tf);
/** Sets text size in points.
Has no effect if textSize is not greater than or equal to zero.
@param textSize typographic height of text
*/
void setSize(SkScalar textSize);
/** Sets text scale on x-axis.
Default value is 1.
@param scaleX text horizontal scale
*/
void setScaleX(SkScalar scaleX);
/** Sets text skew on x-axis.
Default value is zero.
@param skewX additional shear on x-axis relative to y-axis
*/
void setSkewX(SkScalar skewX);
/** Converts text into glyph indices.
Returns the number of glyph indices represented by text.
SkTextEncoding specifies how text represents characters or glyphs.
glyphs may be nullptr, to compute the glyph count.
Does not check text for valid character codes or valid glyph indices.
If byteLength equals zero, returns zero.
If byteLength includes a partial character, the partial character is ignored.
If encoding is SkTextEncoding::kUTF8 and text contains an invalid UTF-8 sequence,
zero is returned.
When encoding is SkTextEncoding::kUTF8, SkTextEncoding::kUTF16, or
SkTextEncoding::kUTF32; then each Unicode codepoint is mapped to a
single glyph. This function uses the default character-to-glyph
mapping from the SkTypeface and maps characters not found in the
SkTypeface to zero.
If maxGlyphCount is not sufficient to store all the glyphs, no glyphs are copied.
The total glyph count is returned for subsequent buffer reallocation.
@param text character storage encoded with SkTextEncoding
@param byteLength length of character storage in bytes
@param glyphs storage for glyph indices; may be nullptr
@param maxGlyphCount storage capacity
@return number of glyphs represented by text of length byteLength
*/
int textToGlyphs(const void* text, size_t byteLength, SkTextEncoding encoding,
SkGlyphID glyphs[], int maxGlyphCount) const;
/** Returns glyph index for Unicode character.
If the character is not supported by the SkTypeface, returns 0.
@param uni Unicode character
@return glyph index
*/
SkGlyphID unicharToGlyph(SkUnichar uni) const;
void unicharsToGlyphs(const SkUnichar uni[], int count, SkGlyphID glyphs[]) const;
/** Returns number of glyphs represented by text.
If encoding is SkTextEncoding::kUTF8, SkTextEncoding::kUTF16, or
SkTextEncoding::kUTF32; then each Unicode codepoint is mapped to a
single glyph.
@param text character storage encoded with SkTextEncoding
@param byteLength length of character storage in bytes
@return number of glyphs represented by text of length byteLength
*/
int countText(const void* text, size_t byteLength, SkTextEncoding encoding) const {
return this->textToGlyphs(text, byteLength, encoding, nullptr, 0);
}
/** Returns the advance width of text.
The advance is the normal distance to move before drawing additional text.
Returns the bounding box of text if bounds is not nullptr.
@param text character storage encoded with SkTextEncoding
@param byteLength length of character storage in bytes
@param bounds returns bounding box relative to (0, 0) if not nullptr
@return the sum of the default advance widths
*/
SkScalar measureText(const void* text, size_t byteLength, SkTextEncoding encoding,
SkRect* bounds = nullptr) const {
return this->measureText(text, byteLength, encoding, bounds, nullptr);
}
/** Returns the advance width of text.
The advance is the normal distance to move before drawing additional text.
Returns the bounding box of text if bounds is not nullptr. The paint
stroke settings, mask filter, or path effect may modify the bounds.
@param text character storage encoded with SkTextEncoding
@param byteLength length of character storage in bytes
@param bounds returns bounding box relative to (0, 0) if not nullptr
@param paint optional; may be nullptr
@return the sum of the default advance widths
*/
SkScalar measureText(const void* text, size_t byteLength, SkTextEncoding encoding,
SkRect* bounds, const SkPaint* paint) const;
/** DEPRECATED
Retrieves the advance and bounds for each glyph in glyphs.
Both widths and bounds may be nullptr.
If widths is not nullptr, widths must be an array of count entries.
if bounds is not nullptr, bounds must be an array of count entries.
@param glyphs array of glyph indices to be measured
@param count number of glyphs
@param widths returns text advances for each glyph; may be nullptr
@param bounds returns bounds for each glyph relative to (0, 0); may be nullptr
*/
void getWidths(const SkGlyphID glyphs[], int count, SkScalar widths[], SkRect bounds[]) const {
this->getWidthsBounds(glyphs, count, widths, bounds, nullptr);
}
// DEPRECATED
void getWidths(const SkGlyphID glyphs[], int count, SkScalar widths[], std::nullptr_t) const {
this->getWidths(glyphs, count, widths);
}
/** Retrieves the advance and bounds for each glyph in glyphs.
Both widths and bounds may be nullptr.
If widths is not nullptr, widths must be an array of count entries.
if bounds is not nullptr, bounds must be an array of count entries.
@param glyphs array of glyph indices to be measured
@param count number of glyphs
@param widths returns text advances for each glyph
*/
void getWidths(const SkGlyphID glyphs[], int count, SkScalar widths[]) const {
this->getWidthsBounds(glyphs, count, widths, nullptr, nullptr);
}
/** Retrieves the advance and bounds for each glyph in glyphs.
Both widths and bounds may be nullptr.
If widths is not nullptr, widths must be an array of count entries.
if bounds is not nullptr, bounds must be an array of count entries.
@param glyphs array of glyph indices to be measured
@param count number of glyphs
@param widths returns text advances for each glyph; may be nullptr
@param bounds returns bounds for each glyph relative to (0, 0); may be nullptr
@param paint optional, specifies stroking, SkPathEffect and SkMaskFilter
*/
void getWidthsBounds(const SkGlyphID glyphs[], int count, SkScalar widths[], SkRect bounds[],
const SkPaint* paint) const;
/** Retrieves the bounds for each glyph in glyphs.
bounds must be an array of count entries.
If paint is not nullptr, its stroking, SkPathEffect, and SkMaskFilter fields are respected.
@param glyphs array of glyph indices to be measured
@param count number of glyphs
@param bounds returns bounds for each glyph relative to (0, 0); may be nullptr
@param paint optional, specifies stroking, SkPathEffect, and SkMaskFilter
*/
void getBounds(const SkGlyphID glyphs[], int count, SkRect bounds[],
const SkPaint* paint) const {
this->getWidthsBounds(glyphs, count, nullptr, bounds, paint);
}
/** Retrieves the positions for each glyph, beginning at the specified origin. The caller
must allocated at least count number of elements in the pos[] array.
@param glyphs array of glyph indices to be positioned
@param count number of glyphs
@param pos returns glyphs positions
@param origin location of the first glyph. Defaults to {0, 0}.
*/
void getPos(const SkGlyphID glyphs[], int count, SkPoint pos[], SkPoint origin = {0, 0}) const;
/** Retrieves the x-positions for each glyph, beginning at the specified origin. The caller
must allocated at least count number of elements in the xpos[] array.
@param glyphs array of glyph indices to be positioned
@param count number of glyphs
@param xpos returns glyphs x-positions
@param origin x-position of the first glyph. Defaults to 0.
*/
void getXPos(const SkGlyphID glyphs[], int count, SkScalar xpos[], SkScalar origin = 0) const;
/** Returns intervals [start, end] describing lines parallel to the advance that intersect
* with the glyphs.
*
* @param glyphs the glyphs to intersect
* @param count the number of glyphs and positions
* @param pos the position of each glyph
* @param top the top of the line intersecting
* @param bottom the bottom of the line intersecting
@return array of pairs of x values [start, end]. May be empty.
*/
std::vector<SkScalar> getIntercepts(const SkGlyphID glyphs[], int count, const SkPoint pos[],
SkScalar top, SkScalar bottom,
const SkPaint* = nullptr) const;
/** Modifies path to be the outline of the glyph.
If the glyph has an outline, modifies path to be the glyph's outline and returns true.
The glyph outline may be empty. Degenerate contours in the glyph outline will be skipped.
If glyph is described by a bitmap, returns false and ignores path parameter.
@param glyphID index of glyph
@param path pointer to existing SkPath
@return true if glyphID is described by path
*/
bool getPath(SkGlyphID glyphID, SkPath* path) const;
/** Returns path corresponding to glyph array.
@param glyphIDs array of glyph indices
@param count number of glyphs
@param glyphPathProc function returning one glyph description as path
@param ctx function context
*/
void getPaths(const SkGlyphID glyphIDs[], int count,
void (*glyphPathProc)(const SkPath* pathOrNull, const SkMatrix& mx, void* ctx),
void* ctx) const;
/** Returns SkFontMetrics associated with SkTypeface.
The return value is the recommended spacing between lines: the sum of metrics
descent, ascent, and leading.
If metrics is not nullptr, SkFontMetrics is copied to metrics.
Results are scaled by text size but does not take into account
dimensions required by text scale, text skew, fake bold,
style stroke, and SkPathEffect.
@param metrics storage for SkFontMetrics; may be nullptr
@return recommended spacing between lines
*/
SkScalar getMetrics(SkFontMetrics* metrics) const;
/** Returns the recommended spacing between lines: the sum of metrics
descent, ascent, and leading.
Result is scaled by text size but does not take into account
dimensions required by stroking and SkPathEffect.
Returns the same result as getMetrics().
@return recommended spacing between lines
*/
SkScalar getSpacing() const { return this->getMetrics(nullptr); }
/** Dumps fields of the font to SkDebugf. May change its output over time, so clients should
* not rely on this for anything specific. Used to aid in debugging.
*/
void dump() const;
using sk_is_trivially_relocatable = std::true_type;
private:
enum PrivFlags {
kForceAutoHinting_PrivFlag = 1 << 0,
kEmbeddedBitmaps_PrivFlag = 1 << 1,
kSubpixel_PrivFlag = 1 << 2,
kLinearMetrics_PrivFlag = 1 << 3,
kEmbolden_PrivFlag = 1 << 4,
kBaselineSnap_PrivFlag = 1 << 5,
};
static constexpr unsigned kAllFlags = kForceAutoHinting_PrivFlag
| kEmbeddedBitmaps_PrivFlag
| kSubpixel_PrivFlag
| kLinearMetrics_PrivFlag
| kEmbolden_PrivFlag
| kBaselineSnap_PrivFlag;
sk_sp<SkTypeface> fTypeface;
SkScalar fSize;
SkScalar fScaleX;
SkScalar fSkewX;
uint8_t fFlags;
uint8_t fEdging;
uint8_t fHinting;
static_assert(::sk_is_trivially_relocatable<decltype(fTypeface)>::value);
SkScalar setupForAsPaths(SkPaint*);
bool hasSomeAntiAliasing() const;
friend class SkFontPriv;
friend class SkGlyphRunListPainterCPU;
friend class SkStrikeSpec;
friend class SkRemoteGlyphCacheTest;
};
#endif

View File

@ -0,0 +1,94 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkFontArguments_DEFINED
#define SkFontArguments_DEFINED
#include "include/core/SkColor.h"
#include "include/core/SkScalar.h"
#include "include/core/SkTypes.h"
/** Represents a set of actual arguments for a font. */
struct SkFontArguments {
struct VariationPosition {
struct Coordinate {
SkFourByteTag axis;
float value;
};
const Coordinate* coordinates;
int coordinateCount;
};
/** Specify a palette to use and overrides for palette entries.
*
* `overrides` is a list of pairs of palette entry index and color.
* The overriden palette entries will use the associated color.
* Override pairs with palette entry indices out of range will not be applied.
* Later override entries override earlier ones.
*/
struct Palette {
struct Override {
uint16_t index;
SkColor color;
};
int index;
const Override* overrides;
int overrideCount;
};
SkFontArguments()
: fCollectionIndex(0)
, fVariationDesignPosition{nullptr, 0}
, fPalette{0, nullptr, 0} {}
/** Specify the index of the desired font.
*
* Font formats like ttc, dfont, cff, cid, pfr, t42, t1, and fon may actually be indexed
* collections of fonts.
*/
SkFontArguments& setCollectionIndex(int collectionIndex) {
fCollectionIndex = collectionIndex;
return *this;
}
/** Specify a position in the variation design space.
*
* Any axis not specified will use the default value.
* Any specified axis not actually present in the font will be ignored.
*
* @param position not copied. The value must remain valid for life of SkFontArguments.
*/
SkFontArguments& setVariationDesignPosition(VariationPosition position) {
fVariationDesignPosition.coordinates = position.coordinates;
fVariationDesignPosition.coordinateCount = position.coordinateCount;
return *this;
}
int getCollectionIndex() const {
return fCollectionIndex;
}
VariationPosition getVariationDesignPosition() const {
return fVariationDesignPosition;
}
SkFontArguments& setPalette(Palette palette) {
fPalette.index = palette.index;
fPalette.overrides = palette.overrides;
fPalette.overrideCount = palette.overrideCount;
return *this;
}
Palette getPalette() const { return fPalette; }
private:
int fCollectionIndex;
VariationPosition fVariationDesignPosition;
Palette fPalette;
};
#endif

View File

@ -0,0 +1,139 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkFontMetrics_DEFINED
#define SkFontMetrics_DEFINED
#include "include/core/SkScalar.h"
#include "include/private/base/SkTo.h"
/** \class SkFontMetrics
The metrics of an SkFont.
The metric values are consistent with the Skia y-down coordinate system.
*/
struct SK_API SkFontMetrics {
bool operator==(const SkFontMetrics& that) const {
return
this->fFlags == that.fFlags &&
this->fTop == that.fTop &&
this->fAscent == that.fAscent &&
this->fDescent == that.fDescent &&
this->fBottom == that.fBottom &&
this->fLeading == that.fLeading &&
this->fAvgCharWidth == that.fAvgCharWidth &&
this->fMaxCharWidth == that.fMaxCharWidth &&
this->fXMin == that.fXMin &&
this->fXMax == that.fXMax &&
this->fXHeight == that.fXHeight &&
this->fCapHeight == that.fCapHeight &&
this->fUnderlineThickness == that.fUnderlineThickness &&
this->fUnderlinePosition == that.fUnderlinePosition &&
this->fStrikeoutThickness == that.fStrikeoutThickness &&
this->fStrikeoutPosition == that.fStrikeoutPosition;
}
/** \enum FontMetricsFlags
FontMetricsFlags indicate when certain metrics are valid;
the underline or strikeout metrics may be valid and zero.
Fonts with embedded bitmaps may not have valid underline or strikeout metrics.
*/
enum FontMetricsFlags {
kUnderlineThicknessIsValid_Flag = 1 << 0, //!< set if fUnderlineThickness is valid
kUnderlinePositionIsValid_Flag = 1 << 1, //!< set if fUnderlinePosition is valid
kStrikeoutThicknessIsValid_Flag = 1 << 2, //!< set if fStrikeoutThickness is valid
kStrikeoutPositionIsValid_Flag = 1 << 3, //!< set if fStrikeoutPosition is valid
kBoundsInvalid_Flag = 1 << 4, //!< set if fTop, fBottom, fXMin, fXMax invalid
};
uint32_t fFlags; //!< FontMetricsFlags indicating which metrics are valid
SkScalar fTop; //!< greatest extent above origin of any glyph bounding box, typically negative; deprecated with variable fonts
SkScalar fAscent; //!< distance to reserve above baseline, typically negative
SkScalar fDescent; //!< distance to reserve below baseline, typically positive
SkScalar fBottom; //!< greatest extent below origin of any glyph bounding box, typically positive; deprecated with variable fonts
SkScalar fLeading; //!< distance to add between lines, typically positive or zero
SkScalar fAvgCharWidth; //!< average character width, zero if unknown
SkScalar fMaxCharWidth; //!< maximum character width, zero if unknown
SkScalar fXMin; //!< greatest extent to left of origin of any glyph bounding box, typically negative; deprecated with variable fonts
SkScalar fXMax; //!< greatest extent to right of origin of any glyph bounding box, typically positive; deprecated with variable fonts
SkScalar fXHeight; //!< height of lower-case 'x', zero if unknown, typically negative
SkScalar fCapHeight; //!< height of an upper-case letter, zero if unknown, typically negative
SkScalar fUnderlineThickness; //!< underline thickness
SkScalar fUnderlinePosition; //!< distance from baseline to top of stroke, typically positive
SkScalar fStrikeoutThickness; //!< strikeout thickness
SkScalar fStrikeoutPosition; //!< distance from baseline to bottom of stroke, typically negative
/** Returns true if SkFontMetrics has a valid underline thickness, and sets
thickness to that value. If the underline thickness is not valid,
return false, and ignore thickness.
@param thickness storage for underline width
@return true if font specifies underline width
*/
bool hasUnderlineThickness(SkScalar* thickness) const {
if (SkToBool(fFlags & kUnderlineThicknessIsValid_Flag)) {
*thickness = fUnderlineThickness;
return true;
}
return false;
}
/** Returns true if SkFontMetrics has a valid underline position, and sets
position to that value. If the underline position is not valid,
return false, and ignore position.
@param position storage for underline position
@return true if font specifies underline position
*/
bool hasUnderlinePosition(SkScalar* position) const {
if (SkToBool(fFlags & kUnderlinePositionIsValid_Flag)) {
*position = fUnderlinePosition;
return true;
}
return false;
}
/** Returns true if SkFontMetrics has a valid strikeout thickness, and sets
thickness to that value. If the underline thickness is not valid,
return false, and ignore thickness.
@param thickness storage for strikeout width
@return true if font specifies strikeout width
*/
bool hasStrikeoutThickness(SkScalar* thickness) const {
if (SkToBool(fFlags & kStrikeoutThicknessIsValid_Flag)) {
*thickness = fStrikeoutThickness;
return true;
}
return false;
}
/** Returns true if SkFontMetrics has a valid strikeout position, and sets
position to that value. If the underline position is not valid,
return false, and ignore position.
@param position storage for strikeout position
@return true if font specifies strikeout position
*/
bool hasStrikeoutPosition(SkScalar* position) const {
if (SkToBool(fFlags & kStrikeoutPositionIsValid_Flag)) {
*position = fStrikeoutPosition;
return true;
}
return false;
}
/** Returns true if SkFontMetrics has a valid fTop, fBottom, fXMin, and fXMax.
If the bounds are not valid, return false.
@return true if font specifies maximum glyph bounds
*/
bool hasBounds() const {
return !SkToBool(fFlags & kBoundsInvalid_Flag);
}
};
#endif

View File

@ -0,0 +1,143 @@
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkFontMgr_DEFINED
#define SkFontMgr_DEFINED
#include "include/core/SkRefCnt.h"
#include "include/core/SkTypes.h"
#include <memory>
class SkData;
class SkFontStyle;
class SkStreamAsset;
class SkString;
class SkTypeface;
struct SkFontArguments;
class SK_API SkFontStyleSet : public SkRefCnt {
public:
virtual int count() = 0;
virtual void getStyle(int index, SkFontStyle*, SkString* style) = 0;
virtual sk_sp<SkTypeface> createTypeface(int index) = 0;
virtual sk_sp<SkTypeface> matchStyle(const SkFontStyle& pattern) = 0;
static sk_sp<SkFontStyleSet> CreateEmpty();
protected:
sk_sp<SkTypeface> matchStyleCSS3(const SkFontStyle& pattern);
};
class SK_API SkFontMgr : public SkRefCnt {
public:
int countFamilies() const;
void getFamilyName(int index, SkString* familyName) const;
sk_sp<SkFontStyleSet> createStyleSet(int index) const;
/**
* The caller must call unref() on the returned object.
* Never returns NULL; will return an empty set if the name is not found.
*
* Passing nullptr as the parameter will return the default system family.
* Note that most systems don't have a default system family, so passing nullptr will often
* result in the empty set.
*
* It is possible that this will return a style set not accessible from
* createStyleSet(int) due to hidden or auto-activated fonts.
*/
sk_sp<SkFontStyleSet> matchFamily(const char familyName[]) const;
/**
* Find the closest matching typeface to the specified familyName and style
* and return a ref to it. The caller must call unref() on the returned
* object. Will return nullptr if no 'good' match is found.
*
* Passing |nullptr| as the parameter for |familyName| will return the
* default system font.
*
* It is possible that this will return a style set not accessible from
* createStyleSet(int) or matchFamily(const char[]) due to hidden or
* auto-activated fonts.
*/
sk_sp<SkTypeface> matchFamilyStyle(const char familyName[], const SkFontStyle&) const;
/**
* Use the system fallback to find a typeface for the given character.
* Note that bcp47 is a combination of ISO 639, 15924, and 3166-1 codes,
* so it is fine to just pass a ISO 639 here.
*
* Will return NULL if no family can be found for the character
* in the system fallback.
*
* Passing |nullptr| as the parameter for |familyName| will return the
* default system font.
*
* bcp47[0] is the least significant fallback, bcp47[bcp47Count-1] is the
* most significant. If no specified bcp47 codes match, any font with the
* requested character will be matched.
*/
sk_sp<SkTypeface> matchFamilyStyleCharacter(const char familyName[], const SkFontStyle&,
const char* bcp47[], int bcp47Count,
SkUnichar character) const;
/**
* Create a typeface for the specified data and TTC index (pass 0 for none)
* or NULL if the data is not recognized. The caller must call unref() on
* the returned object if it is not null.
*/
sk_sp<SkTypeface> makeFromData(sk_sp<SkData>, int ttcIndex = 0) const;
/**
* Create a typeface for the specified stream and TTC index
* (pass 0 for none) or NULL if the stream is not recognized. The caller
* must call unref() on the returned object if it is not null.
*/
sk_sp<SkTypeface> makeFromStream(std::unique_ptr<SkStreamAsset>, int ttcIndex = 0) const;
/* Experimental, API subject to change. */
sk_sp<SkTypeface> makeFromStream(std::unique_ptr<SkStreamAsset>, const SkFontArguments&) const;
/**
* Create a typeface for the specified fileName and TTC index
* (pass 0 for none) or NULL if the file is not found, or its contents are
* not recognized. The caller must call unref() on the returned object
* if it is not null.
*/
sk_sp<SkTypeface> makeFromFile(const char path[], int ttcIndex = 0) const;
sk_sp<SkTypeface> legacyMakeTypeface(const char familyName[], SkFontStyle style) const;
/* Returns an empty font manager without any typeface dependencies */
static sk_sp<SkFontMgr> RefEmpty();
protected:
virtual int onCountFamilies() const = 0;
virtual void onGetFamilyName(int index, SkString* familyName) const = 0;
virtual sk_sp<SkFontStyleSet> onCreateStyleSet(int index)const = 0;
/** May return NULL if the name is not found. */
virtual sk_sp<SkFontStyleSet> onMatchFamily(const char familyName[]) const = 0;
virtual sk_sp<SkTypeface> onMatchFamilyStyle(const char familyName[],
const SkFontStyle&) const = 0;
virtual sk_sp<SkTypeface> onMatchFamilyStyleCharacter(const char familyName[],
const SkFontStyle&,
const char* bcp47[], int bcp47Count,
SkUnichar character) const = 0;
virtual sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData>, int ttcIndex) const = 0;
virtual sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset>,
int ttcIndex) const = 0;
virtual sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset>,
const SkFontArguments&) const = 0;
virtual sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const = 0;
virtual sk_sp<SkTypeface> onLegacyMakeTypeface(const char familyName[], SkFontStyle) const = 0;
};
#endif

View File

@ -0,0 +1,42 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkFontParameters_DEFINED
#define SkFontParameters_DEFINED
#include "include/core/SkScalar.h"
#include "include/core/SkTypes.h"
struct SkFontParameters {
struct Variation {
// Parameters in a variation font axis.
struct Axis {
constexpr Axis() : tag(0), min(0), def(0), max(0), flags(0) {}
constexpr Axis(SkFourByteTag tag, float min, float def, float max, bool hidden) :
tag(tag), min(min), def(def), max(max), flags(hidden ? HIDDEN : 0) {}
// Four character identifier of the font axis (weight, width, slant, italic...).
SkFourByteTag tag;
// Minimum value supported by this axis.
float min;
// Default value set by this axis.
float def;
// Maximum value supported by this axis. The maximum can equal the minimum.
float max;
// Return whether this axis is recommended to be remain hidden in user interfaces.
bool isHidden() const { return flags & HIDDEN; }
// Set this axis to be remain hidden in user interfaces.
void setHidden(bool hidden) { flags = hidden ? (flags | HIDDEN) : (flags & ~HIDDEN); }
private:
static constexpr uint16_t HIDDEN = 0x0001;
// Attributes for a font axis.
uint16_t flags;
};
};
};
#endif

View File

@ -0,0 +1,84 @@
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkFontStyle_DEFINED
#define SkFontStyle_DEFINED
#include "include/core/SkTypes.h"
#include "include/private/base/SkTPin.h"
#include <cstdint>
class SK_API SkFontStyle {
public:
enum Weight {
kInvisible_Weight = 0,
kThin_Weight = 100,
kExtraLight_Weight = 200,
kLight_Weight = 300,
kNormal_Weight = 400,
kMedium_Weight = 500,
kSemiBold_Weight = 600,
kBold_Weight = 700,
kExtraBold_Weight = 800,
kBlack_Weight = 900,
kExtraBlack_Weight = 1000,
};
enum Width {
kUltraCondensed_Width = 1,
kExtraCondensed_Width = 2,
kCondensed_Width = 3,
kSemiCondensed_Width = 4,
kNormal_Width = 5,
kSemiExpanded_Width = 6,
kExpanded_Width = 7,
kExtraExpanded_Width = 8,
kUltraExpanded_Width = 9,
};
enum Slant {
kUpright_Slant,
kItalic_Slant,
kOblique_Slant,
};
constexpr SkFontStyle(int weight, int width, Slant slant) : fValue(
(SkTPin<int>(weight, kInvisible_Weight, kExtraBlack_Weight)) +
(SkTPin<int>(width, kUltraCondensed_Width, kUltraExpanded_Width) << 16) +
(SkTPin<int>(slant, kUpright_Slant, kOblique_Slant) << 24)
) { }
constexpr SkFontStyle() : SkFontStyle{kNormal_Weight, kNormal_Width, kUpright_Slant} { }
bool operator==(const SkFontStyle& rhs) const {
return fValue == rhs.fValue;
}
int weight() const { return fValue & 0xFFFF; }
int width() const { return (fValue >> 16) & 0xFF; }
Slant slant() const { return (Slant)((fValue >> 24) & 0xFF); }
static constexpr SkFontStyle Normal() {
return SkFontStyle(kNormal_Weight, kNormal_Width, kUpright_Slant);
}
static constexpr SkFontStyle Bold() {
return SkFontStyle(kBold_Weight, kNormal_Width, kUpright_Slant);
}
static constexpr SkFontStyle Italic() {
return SkFontStyle(kNormal_Weight, kNormal_Width, kItalic_Slant );
}
static constexpr SkFontStyle BoldItalic() {
return SkFontStyle(kBold_Weight, kNormal_Width, kItalic_Slant );
}
private:
friend class SkTypefaceProxyPrototype; // To serialize fValue
int32_t fValue;
};
#endif

View File

@ -0,0 +1,25 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkFontTypes_DEFINED
#define SkFontTypes_DEFINED
enum class SkTextEncoding {
kUTF8, //!< uses bytes to represent UTF-8 or ASCII
kUTF16, //!< uses two byte words to represent most of Unicode
kUTF32, //!< uses four byte words to represent all of Unicode
kGlyphID, //!< uses two byte words to represent glyph indices
};
enum class SkFontHinting {
kNone, //!< glyph outlines unchanged
kSlight, //!< minimal modification to improve constrast
kNormal, //!< glyph outlines modified to improve constrast
kFull, //!< modifies glyph outlines for maximum constrast
};
#endif

View File

@ -0,0 +1,169 @@
/*
* Copyright 2006 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkGraphics_DEFINED
#define SkGraphics_DEFINED
#include "include/core/SkRefCnt.h"
#include "include/private/base/SkAPI.h"
#include <cstddef>
#include <cstdint>
#include <memory>
class SkData;
class SkImageGenerator;
class SkOpenTypeSVGDecoder;
class SkTraceMemoryDump;
class SK_API SkGraphics {
public:
/**
* Call this at process initialization time if your environment does not
* permit static global initializers that execute code.
* Init() is thread-safe and idempotent.
*/
static void Init();
/**
* Return the max number of bytes that should be used by the font cache.
* If the cache needs to allocate more, it will purge previous entries.
* This max can be changed by calling SetFontCacheLimit().
*/
static size_t GetFontCacheLimit();
/**
* Specify the max number of bytes that should be used by the font cache.
* If the cache needs to allocate more, it will purge previous entries.
*
* This function returns the previous setting, as if GetFontCacheLimit()
* had be called before the new limit was set.
*/
static size_t SetFontCacheLimit(size_t bytes);
/**
* Return the number of bytes currently used by the font cache.
*/
static size_t GetFontCacheUsed();
/**
* Return the number of entries in the font cache.
* A cache "entry" is associated with each typeface + pointSize + matrix.
*/
static int GetFontCacheCountUsed();
/**
* Return the current limit to the number of entries in the font cache.
* A cache "entry" is associated with each typeface + pointSize + matrix.
*/
static int GetFontCacheCountLimit();
/**
* Set the limit to the number of entries in the font cache, and return
* the previous value. If this new value is lower than the previous,
* it will automatically try to purge entries to meet the new limit.
*/
static int SetFontCacheCountLimit(int count);
/**
* Return the current limit to the number of entries in the typeface cache.
* A cache "entry" is associated with each typeface.
*/
static int GetTypefaceCacheCountLimit();
/**
* Set the limit to the number of entries in the typeface cache, and return
* the previous value. Changes to this only take effect the next time
* each cache object is modified.
*/
static int SetTypefaceCacheCountLimit(int count);
/**
* For debugging purposes, this will attempt to purge the font cache. It
* does not change the limit, but will cause subsequent font measures and
* draws to be recreated, since they will no longer be in the cache.
*/
static void PurgeFontCache();
/**
* If the strike cache is above the cache limit, attempt to purge strikes
* with pinners. This should be called after clients release locks on
* pinned strikes.
*/
static void PurgePinnedFontCache();
/**
* This function returns the memory used for temporary images and other resources.
*/
static size_t GetResourceCacheTotalBytesUsed();
/**
* These functions get/set the memory usage limit for the resource cache, used for temporary
* bitmaps and other resources. Entries are purged from the cache when the memory useage
* exceeds this limit.
*/
static size_t GetResourceCacheTotalByteLimit();
static size_t SetResourceCacheTotalByteLimit(size_t newLimit);
/**
* For debugging purposes, this will attempt to purge the resource cache. It
* does not change the limit.
*/
static void PurgeResourceCache();
/**
* When the cachable entry is very lage (e.g. a large scaled bitmap), adding it to the cache
* can cause most/all of the existing entries to be purged. To avoid the, the client can set
* a limit for a single allocation. If a cacheable entry would have been cached, but its size
* exceeds this limit, then we do not attempt to cache it at all.
*
* Zero is the default value, meaning we always attempt to cache entries.
*/
static size_t GetResourceCacheSingleAllocationByteLimit();
static size_t SetResourceCacheSingleAllocationByteLimit(size_t newLimit);
/**
* Dumps memory usage of caches using the SkTraceMemoryDump interface. See SkTraceMemoryDump
* for usage of this method.
*/
static void DumpMemoryStatistics(SkTraceMemoryDump* dump);
/**
* Free as much globally cached memory as possible. This will purge all private caches in Skia,
* including font and image caches.
*
* If there are caches associated with GPU context, those will not be affected by this call.
*/
static void PurgeAllCaches();
typedef std::unique_ptr<SkImageGenerator>
(*ImageGeneratorFromEncodedDataFactory)(sk_sp<SkData>);
/**
* To instantiate images from encoded data, first looks at this runtime function-ptr. If it
* exists, it is called to create an SkImageGenerator from SkData. If there is no function-ptr
* or there is, but it returns NULL, then skia will call its internal default implementation.
*
* Returns the previous factory (which could be NULL).
*/
static ImageGeneratorFromEncodedDataFactory
SetImageGeneratorFromEncodedDataFactory(ImageGeneratorFromEncodedDataFactory);
/**
* To draw OpenType SVG data, Skia will look at this runtime function pointer. If this function
* pointer is set, the SkTypeface implementations which support OpenType SVG will call this
* function to create an SkOpenTypeSVGDecoder to decode the OpenType SVG and draw it as needed.
* If this function is not set, the SkTypeface implementations will generally not support
* OpenType SVG and attempt to use other glyph representations if available.
*/
using OpenTypeSVGDecoderFactory =
std::unique_ptr<SkOpenTypeSVGDecoder> (*)(const uint8_t* svg, size_t length);
static OpenTypeSVGDecoderFactory SetOpenTypeSVGDecoderFactory(OpenTypeSVGDecoderFactory);
static OpenTypeSVGDecoderFactory GetOpenTypeSVGDecoderFactory();
};
#endif

View File

@ -0,0 +1,948 @@
/*
* Copyright 2012 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkImage_DEFINED
#define SkImage_DEFINED
#include "include/core/SkAlphaType.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkSize.h"
#include "include/private/base/SkAPI.h"
#include <cstddef>
#include <cstdint>
#include <memory>
#include <optional>
class GrDirectContext;
class GrRecordingContext;
class SkBitmap;
class SkColorSpace;
class SkData;
class SkImage;
class SkImageFilter;
class SkImageGenerator;
class SkMatrix;
class SkMipmap;
class SkPaint;
class SkPicture;
class SkPixmap;
class SkShader;
class SkSurfaceProps;
enum SkColorType : int;
enum class SkTextureCompressionType;
enum class SkTileMode;
struct SkIPoint;
struct SkSamplingOptions;
namespace skgpu::graphite { class Recorder; }
namespace SkImages {
/** Caller data passed to RasterReleaseProc; may be nullptr. */
using ReleaseContext = void*;
/** Function called when SkImage no longer shares pixels. ReleaseContext is
provided by caller when SkImage is created, and may be nullptr.
*/
using RasterReleaseProc = void(const void* pixels, ReleaseContext);
/** Creates a CPU-backed SkImage from bitmap, sharing or copying bitmap pixels. If the bitmap
is marked immutable, and its pixel memory is shareable, it may be shared
instead of copied.
SkImage is returned if bitmap is valid. Valid SkBitmap parameters include:
dimensions are greater than zero;
each dimension fits in 29 bits;
SkColorType and SkAlphaType are valid, and SkColorType is not kUnknown_SkColorType;
row bytes are large enough to hold one row of pixels;
pixel address is not nullptr.
@param bitmap SkImageInfo, row bytes, and pixels
@return created SkImage, or nullptr
*/
SK_API sk_sp<SkImage> RasterFromBitmap(const SkBitmap& bitmap);
/** Creates a CPU-backed SkImage from compressed data.
This method will decompress the compressed data and create an image wrapping
it. Any mipmap levels present in the compressed data are discarded.
@param data compressed data to store in SkImage
@param width width of full SkImage
@param height height of full SkImage
@param type type of compression used
@return created SkImage, or nullptr
*/
SK_API sk_sp<SkImage> RasterFromCompressedTextureData(sk_sp<SkData> data,
int width,
int height,
SkTextureCompressionType type);
/**
* Return a SkImage using the encoded data, but attempts to defer decoding until the
* image is actually used/drawn. This deferral allows the system to cache the result, either on the
* CPU or on the GPU, depending on where the image is drawn. If memory is low, the cache may
* be purged, causing the next draw of the image to have to re-decode.
*
* If alphaType is nullopt, the image's alpha type will be chosen automatically based on the
* image format. Transparent images will default to kPremul_SkAlphaType. If alphaType contains
* kPremul_SkAlphaType or kUnpremul_SkAlphaType, that alpha type will be used. Forcing opaque
* (passing kOpaque_SkAlphaType) is not allowed, and will return nullptr.
*
* If the encoded format is not supported, nullptr is returned.
*
* If possible, clients should use SkCodecs::DeferredImage instead.
*
* @param encoded the encoded data
* @return created SkImage, or nullptr
example: https://fiddle.skia.org/c/@Image_DeferredFromEncodedData
*/
SK_API sk_sp<SkImage> DeferredFromEncodedData(sk_sp<SkData> encoded,
std::optional<SkAlphaType> alphaType = std::nullopt);
/** Creates SkImage from data returned by imageGenerator. The image data will not be created
(on either the CPU or GPU) until the image is actually drawn.
Generated data is owned by SkImage and may not be shared or accessed.
SkImage is returned if generator data is valid. Valid data parameters vary by type of data
and platform.
imageGenerator may wrap SkPicture data, codec data, or custom data.
@param imageGenerator stock or custom routines to retrieve SkImage
@return created SkImage, or nullptr
*/
SK_API sk_sp<SkImage> DeferredFromGenerator(std::unique_ptr<SkImageGenerator> imageGenerator);
enum class BitDepth {
kU8, //!< uses 8-bit unsigned int per color component
kF16, //!< uses 16-bit float per color component
};
/** Creates SkImage from picture. Returned SkImage width and height are set by dimensions.
SkImage draws picture with matrix and paint, set to bitDepth and colorSpace.
The Picture data is not turned into an image (CPU or GPU) until it is drawn.
If matrix is nullptr, draws with identity SkMatrix. If paint is nullptr, draws
with default SkPaint. colorSpace may be nullptr.
@param picture stream of drawing commands
@param dimensions width and height
@param matrix SkMatrix to rotate, scale, translate, and so on; may be nullptr
@param paint SkPaint to apply transparency, filtering, and so on; may be nullptr
@param bitDepth 8-bit integer or 16-bit float: per component
@param colorSpace range of colors; may be nullptr
@param props props to use when rasterizing the picture
@return created SkImage, or nullptr
*/
SK_API sk_sp<SkImage> DeferredFromPicture(sk_sp<SkPicture> picture,
const SkISize& dimensions,
const SkMatrix* matrix,
const SkPaint* paint,
BitDepth bitDepth,
sk_sp<SkColorSpace> colorSpace,
SkSurfaceProps props);
SK_API sk_sp<SkImage> DeferredFromPicture(sk_sp<SkPicture> picture,
const SkISize& dimensions,
const SkMatrix* matrix,
const SkPaint* paint,
BitDepth bitDepth,
sk_sp<SkColorSpace> colorSpace);
/** Creates a CPU-backed SkImage from pixmap, copying the pixel data.
As a result, pixmap pixels may be modified or deleted without affecting SkImage.
SkImage is returned if SkPixmap is valid. Valid SkPixmap parameters include:
dimensions are greater than zero;
each dimension fits in 29 bits;
SkColorType and SkAlphaType are valid, and SkColorType is not kUnknown_SkColorType;
row bytes are large enough to hold one row of pixels;
pixel address is not nullptr.
@param pixmap SkImageInfo, pixel address, and row bytes
@return copy of SkPixmap pixels, or nullptr
example: https://fiddle.skia.org/c/@Image_RasterFromPixmapCopy
*/
SK_API sk_sp<SkImage> RasterFromPixmapCopy(const SkPixmap& pixmap);
/** Creates CPU-backed SkImage from pixmap, sharing SkPixmap pixels. Pixels must remain valid and
unchanged until rasterReleaseProc is called. rasterReleaseProc is passed
releaseContext when SkImage is deleted or no longer refers to pixmap pixels.
Pass nullptr for rasterReleaseProc to share SkPixmap without requiring a callback
when SkImage is released. Pass nullptr for releaseContext if rasterReleaseProc
does not require state.
SkImage is returned if pixmap is valid. Valid SkPixmap parameters include:
dimensions are greater than zero;
each dimension fits in 29 bits;
SkColorType and SkAlphaType are valid, and SkColorType is not kUnknown_SkColorType;
row bytes are large enough to hold one row of pixels;
pixel address is not nullptr.
@param pixmap SkImageInfo, pixel address, and row bytes
@param rasterReleaseProc function called when pixels can be released; or nullptr
@param releaseContext state passed to rasterReleaseProc; or nullptr
@return SkImage sharing pixmap
*/
SK_API sk_sp<SkImage> RasterFromPixmap(const SkPixmap& pixmap,
RasterReleaseProc rasterReleaseProc,
ReleaseContext releaseContext);
/** Creates CPU-backed SkImage from pixel data described by info.
The pixels data will *not* be copied.
SkImage is returned if SkImageInfo is valid. Valid SkImageInfo parameters include:
dimensions are greater than zero;
each dimension fits in 29 bits;
SkColorType and SkAlphaType are valid, and SkColorType is not kUnknown_SkColorType;
rowBytes are large enough to hold one row of pixels;
pixels is not nullptr, and contains enough data for SkImage.
@param info contains width, height, SkAlphaType, SkColorType, SkColorSpace
@param pixels address or pixel storage
@param rowBytes size of pixel row or larger
@return SkImage sharing pixels, or nullptr
*/
SK_API sk_sp<SkImage> RasterFromData(const SkImageInfo& info,
sk_sp<SkData> pixels,
size_t rowBytes);
/** Creates a filtered SkImage on the CPU. filter processes the src image, potentially changing
the color, position, and size. subset is the bounds of src that are processed
by filter. clipBounds is the expected bounds of the filtered SkImage. outSubset
is required storage for the actual bounds of the filtered SkImage. offset is
required storage for translation of returned SkImage.
Returns nullptr a filtered result could not be created. If nullptr is returned, outSubset
and offset are undefined.
Useful for animation of SkImageFilter that varies size from frame to frame.
outSubset describes the valid bounds of returned image. offset translates the returned SkImage
to keep subsequent animation frames aligned with respect to each other.
@param src the image to be filtered
@param filter the image filter to be applied
@param subset bounds of SkImage processed by filter
@param clipBounds expected bounds of filtered SkImage
@param outSubset storage for returned SkImage bounds
@param offset storage for returned SkImage translation
@return filtered SkImage, or nullptr
*/
SK_API sk_sp<SkImage> MakeWithFilter(sk_sp<SkImage> src,
const SkImageFilter* filter,
const SkIRect& subset,
const SkIRect& clipBounds,
SkIRect* outSubset,
SkIPoint* offset);
} // namespace SkImages
/** \class SkImage
SkImage describes a two dimensional array of pixels to draw. The pixels may be
decoded in a raster bitmap, encoded in a SkPicture or compressed data stream,
or located in GPU memory as a GPU texture.
SkImage cannot be modified after it is created. SkImage may allocate additional
storage as needed; for instance, an encoded SkImage may decode when drawn.
SkImage width and height are greater than zero. Creating an SkImage with zero width
or height returns SkImage equal to nullptr.
SkImage may be created from SkBitmap, SkPixmap, SkSurface, SkPicture, encoded streams,
GPU texture, YUV_ColorSpace data, or hardware buffer. Encoded streams supported
include BMP, GIF, HEIF, ICO, JPEG, PNG, WBMP, WebP. Supported encoding details
vary with platform.
See SkImages namespace for the static factory methods to make SkImages.
Clients should *not* subclass SkImage as there is a lot of internal machinery that is
not publicly accessible.
*/
class SK_API SkImage : public SkRefCnt {
public:
/** Returns a SkImageInfo describing the width, height, color type, alpha type, and color space
of the SkImage.
@return image info of SkImage.
*/
const SkImageInfo& imageInfo() const { return fInfo; }
/** Returns pixel count in each row.
@return pixel width in SkImage
*/
int width() const { return fInfo.width(); }
/** Returns pixel row count.
@return pixel height in SkImage
*/
int height() const { return fInfo.height(); }
/** Returns SkISize { width(), height() }.
@return integral size of width() and height()
*/
SkISize dimensions() const { return SkISize::Make(fInfo.width(), fInfo.height()); }
/** Returns SkIRect { 0, 0, width(), height() }.
@return integral rectangle from origin to width() and height()
*/
SkIRect bounds() const { return SkIRect::MakeWH(fInfo.width(), fInfo.height()); }
/** Returns value unique to image. SkImage contents cannot change after SkImage is
created. Any operation to create a new SkImage will receive generate a new
unique number.
@return unique identifier
*/
uint32_t uniqueID() const { return fUniqueID; }
/** Returns SkAlphaType.
SkAlphaType returned was a parameter to an SkImage constructor,
or was parsed from encoded data.
@return SkAlphaType in SkImage
example: https://fiddle.skia.org/c/@Image_alphaType
*/
SkAlphaType alphaType() const;
/** Returns SkColorType if known; otherwise, returns kUnknown_SkColorType.
@return SkColorType of SkImage
example: https://fiddle.skia.org/c/@Image_colorType
*/
SkColorType colorType() const;
/** Returns SkColorSpace, the range of colors, associated with SkImage. The
reference count of SkColorSpace is unchanged. The returned SkColorSpace is
immutable.
SkColorSpace returned was passed to an SkImage constructor,
or was parsed from encoded data. SkColorSpace returned may be ignored when SkImage
is drawn, depending on the capabilities of the SkSurface receiving the drawing.
@return SkColorSpace in SkImage, or nullptr
example: https://fiddle.skia.org/c/@Image_colorSpace
*/
SkColorSpace* colorSpace() const;
/** Returns a smart pointer to SkColorSpace, the range of colors, associated with
SkImage. The smart pointer tracks the number of objects sharing this
SkColorSpace reference so the memory is released when the owners destruct.
The returned SkColorSpace is immutable.
SkColorSpace returned was passed to an SkImage constructor,
or was parsed from encoded data. SkColorSpace returned may be ignored when SkImage
is drawn, depending on the capabilities of the SkSurface receiving the drawing.
@return SkColorSpace in SkImage, or nullptr, wrapped in a smart pointer
example: https://fiddle.skia.org/c/@Image_refColorSpace
*/
sk_sp<SkColorSpace> refColorSpace() const;
/** Returns true if SkImage pixels represent transparency only. If true, each pixel
is packed in 8 bits as defined by kAlpha_8_SkColorType.
@return true if pixels represent a transparency mask
example: https://fiddle.skia.org/c/@Image_isAlphaOnly
*/
bool isAlphaOnly() const;
/** Returns true if pixels ignore their alpha value and are treated as fully opaque.
@return true if SkAlphaType is kOpaque_SkAlphaType
*/
bool isOpaque() const { return SkAlphaTypeIsOpaque(this->alphaType()); }
/**
* Make a shader with the specified tiling and mipmap sampling.
*/
sk_sp<SkShader> makeShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions&,
const SkMatrix* localMatrix = nullptr) const;
sk_sp<SkShader> makeShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions& sampling,
const SkMatrix& lm) const;
/** Defaults to clamp in both X and Y. */
sk_sp<SkShader> makeShader(const SkSamplingOptions& sampling, const SkMatrix& lm) const;
sk_sp<SkShader> makeShader(const SkSamplingOptions& sampling,
const SkMatrix* lm = nullptr) const;
/**
* makeRawShader functions like makeShader, but for images that contain non-color data.
* This includes images encoding things like normals, material properties (eg, roughness),
* heightmaps, or any other purely mathematical data that happens to be stored in an image.
* These types of images are useful with some programmable shaders (see: SkRuntimeEffect).
*
* Raw image shaders work like regular image shaders (including filtering and tiling), with
* a few major differences:
* - No color space transformation is ever applied (the color space of the image is ignored).
* - Images with an alpha type of kUnpremul are *not* automatically premultiplied.
* - Bicubic filtering is not supported. If SkSamplingOptions::useCubic is true, these
* factories will return nullptr.
*/
sk_sp<SkShader> makeRawShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions&,
const SkMatrix* localMatrix = nullptr) const;
sk_sp<SkShader> makeRawShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions& sampling,
const SkMatrix& lm) const;
/** Defaults to clamp in both X and Y. */
sk_sp<SkShader> makeRawShader(const SkSamplingOptions& sampling, const SkMatrix& lm) const;
sk_sp<SkShader> makeRawShader(const SkSamplingOptions& sampling,
const SkMatrix* lm = nullptr) const;
/** Copies SkImage pixel address, row bytes, and SkImageInfo to pixmap, if address
is available, and returns true. If pixel address is not available, return
false and leave pixmap unchanged.
@param pixmap storage for pixel state if pixels are readable; otherwise, ignored
@return true if SkImage has direct access to pixels
example: https://fiddle.skia.org/c/@Image_peekPixels
*/
bool peekPixels(SkPixmap* pixmap) const;
/** Returns true if the contents of SkImage was created on or uploaded to GPU memory,
and is available as a GPU texture.
@return true if SkImage is a GPU texture
example: https://fiddle.skia.org/c/@Image_isTextureBacked
*/
virtual bool isTextureBacked() const = 0;
/** Returns an approximation of the amount of texture memory used by the image. Returns
zero if the image is not texture backed or if the texture has an external format.
*/
virtual size_t textureSize() const = 0;
/** Returns true if SkImage can be drawn on either raster surface or GPU surface.
If context is nullptr, tests if SkImage draws on raster surface;
otherwise, tests if SkImage draws on GPU surface associated with context.
SkImage backed by GPU texture may become invalid if associated context is
invalid. lazy image may be invalid and may not draw to raster surface or
GPU surface or both.
@param context GPU context
@return true if SkImage can be drawn
example: https://fiddle.skia.org/c/@Image_isValid
*/
virtual bool isValid(GrRecordingContext* context) const = 0;
/** \enum SkImage::CachingHint
CachingHint selects whether Skia may internally cache SkBitmap generated by
decoding SkImage, or by copying SkImage from GPU to CPU. The default behavior
allows caching SkBitmap.
Choose kDisallow_CachingHint if SkImage pixels are to be used only once, or
if SkImage pixels reside in a cache outside of Skia, or to reduce memory pressure.
Choosing kAllow_CachingHint does not ensure that pixels will be cached.
SkImage pixels may not be cached if memory requirements are too large or
pixels are not accessible.
*/
enum CachingHint {
kAllow_CachingHint, //!< allows internally caching decoded and copied pixels
kDisallow_CachingHint, //!< disallows internally caching decoded and copied pixels
};
/** Copies SkRect of pixels from SkImage to dstPixels. Copy starts at offset (srcX, srcY),
and does not exceed SkImage (width(), height()).
dstInfo specifies width, height, SkColorType, SkAlphaType, and SkColorSpace of
destination. dstRowBytes specifies the gap from one destination row to the next.
Returns true if pixels are copied. Returns false if:
- dstInfo.addr() equals nullptr
- dstRowBytes is less than dstInfo.minRowBytes()
- SkPixelRef is nullptr
Pixels are copied only if pixel conversion is possible. If SkImage SkColorType is
kGray_8_SkColorType, or kAlpha_8_SkColorType; dstInfo.colorType() must match.
If SkImage SkColorType is kGray_8_SkColorType, dstInfo.colorSpace() must match.
If SkImage SkAlphaType is kOpaque_SkAlphaType, dstInfo.alphaType() must
match. If SkImage SkColorSpace is nullptr, dstInfo.colorSpace() must match. Returns
false if pixel conversion is not possible.
srcX and srcY may be negative to copy only top or left of source. Returns
false if width() or height() is zero or negative.
Returns false if abs(srcX) >= Image width(), or if abs(srcY) >= Image height().
If cachingHint is kAllow_CachingHint, pixels may be retained locally.
If cachingHint is kDisallow_CachingHint, pixels are not added to the local cache.
@param context the GrDirectContext in play, if it exists
@param dstInfo destination width, height, SkColorType, SkAlphaType, SkColorSpace
@param dstPixels destination pixel storage
@param dstRowBytes destination row length
@param srcX column index whose absolute value is less than width()
@param srcY row index whose absolute value is less than height()
@param cachingHint whether the pixels should be cached locally
@return true if pixels are copied to dstPixels
*/
bool readPixels(GrDirectContext* context,
const SkImageInfo& dstInfo,
void* dstPixels,
size_t dstRowBytes,
int srcX, int srcY,
CachingHint cachingHint = kAllow_CachingHint) const;
/** Copies a SkRect of pixels from SkImage to dst. Copy starts at (srcX, srcY), and
does not exceed SkImage (width(), height()).
dst specifies width, height, SkColorType, SkAlphaType, SkColorSpace, pixel storage,
and row bytes of destination. dst.rowBytes() specifics the gap from one destination
row to the next. Returns true if pixels are copied. Returns false if:
- dst pixel storage equals nullptr
- dst.rowBytes is less than SkImageInfo::minRowBytes
- SkPixelRef is nullptr
Pixels are copied only if pixel conversion is possible. If SkImage SkColorType is
kGray_8_SkColorType, or kAlpha_8_SkColorType; dst.colorType() must match.
If SkImage SkColorType is kGray_8_SkColorType, dst.colorSpace() must match.
If SkImage SkAlphaType is kOpaque_SkAlphaType, dst.alphaType() must
match. If SkImage SkColorSpace is nullptr, dst.colorSpace() must match. Returns
false if pixel conversion is not possible.
srcX and srcY may be negative to copy only top or left of source. Returns
false if width() or height() is zero or negative.
Returns false if abs(srcX) >= Image width(), or if abs(srcY) >= Image height().
If cachingHint is kAllow_CachingHint, pixels may be retained locally.
If cachingHint is kDisallow_CachingHint, pixels are not added to the local cache.
@param context the GrDirectContext in play, if it exists
@param dst destination SkPixmap: SkImageInfo, pixels, row bytes
@param srcX column index whose absolute value is less than width()
@param srcY row index whose absolute value is less than height()
@param cachingHint whether the pixels should be cached locallyZ
@return true if pixels are copied to dst
*/
bool readPixels(GrDirectContext* context,
const SkPixmap& dst,
int srcX,
int srcY,
CachingHint cachingHint = kAllow_CachingHint) const;
#if defined(GRAPHITE_TEST_UTILS)
bool readPixelsGraphite(skgpu::graphite::Recorder*,
const SkPixmap& dst,
int srcX,
int srcY) const;
#endif
#ifndef SK_IMAGE_READ_PIXELS_DISABLE_LEGACY_API
/** Deprecated. Use the variants that accept a GrDirectContext. */
bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
int srcX, int srcY, CachingHint cachingHint = kAllow_CachingHint) const;
bool readPixels(const SkPixmap& dst, int srcX, int srcY,
CachingHint cachingHint = kAllow_CachingHint) const;
#endif
/** The result from asyncRescaleAndReadPixels() or asyncRescaleAndReadPixelsYUV420(). */
class AsyncReadResult {
public:
AsyncReadResult(const AsyncReadResult&) = delete;
AsyncReadResult(AsyncReadResult&&) = delete;
AsyncReadResult& operator=(const AsyncReadResult&) = delete;
AsyncReadResult& operator=(AsyncReadResult&&) = delete;
virtual ~AsyncReadResult() = default;
virtual int count() const = 0;
virtual const void* data(int i) const = 0;
virtual size_t rowBytes(int i) const = 0;
protected:
AsyncReadResult() = default;
};
/** Client-provided context that is passed to client-provided ReadPixelsContext. */
using ReadPixelsContext = void*;
/** Client-provided callback to asyncRescaleAndReadPixels() or
asyncRescaleAndReadPixelsYUV420() that is called when read result is ready or on failure.
*/
using ReadPixelsCallback = void(ReadPixelsContext, std::unique_ptr<const AsyncReadResult>);
enum class RescaleGamma : bool { kSrc, kLinear };
enum class RescaleMode {
kNearest,
kLinear,
kRepeatedLinear,
kRepeatedCubic,
};
/** Makes image pixel data available to caller, possibly asynchronously. It can also rescale
the image pixels.
Currently asynchronous reads are only supported on the GPU backend and only when the
underlying 3D API supports transfer buffers and CPU/GPU synchronization primitives. In all
other cases this operates synchronously.
Data is read from the source sub-rectangle, is optionally converted to a linear gamma, is
rescaled to the size indicated by 'info', is then converted to the color space, color type,
and alpha type of 'info'. A 'srcRect' that is not contained by the bounds of the image
causes failure.
When the pixel data is ready the caller's ReadPixelsCallback is called with a
AsyncReadResult containing pixel data in the requested color type, alpha type, and color
space. The AsyncReadResult will have count() == 1. Upon failure the callback is called with
nullptr for AsyncReadResult. For a GPU image this flushes work but a submit must occur to
guarantee a finite time before the callback is called.
The data is valid for the lifetime of AsyncReadResult with the exception that if the SkImage
is GPU-backed the data is immediately invalidated if the context is abandoned or
destroyed.
@param info info of the requested pixels
@param srcRect subrectangle of image to read
@param rescaleGamma controls whether rescaling is done in the image's gamma or whether
the source data is transformed to a linear gamma before rescaling.
@param rescaleMode controls the technique (and cost) of the rescaling
@param callback function to call with result of the read
@param context passed to callback
*/
void asyncRescaleAndReadPixels(const SkImageInfo& info,
const SkIRect& srcRect,
RescaleGamma rescaleGamma,
RescaleMode rescaleMode,
ReadPixelsCallback callback,
ReadPixelsContext context) const;
/**
Similar to asyncRescaleAndReadPixels but performs an additional conversion to YUV. The
RGB->YUV conversion is controlled by 'yuvColorSpace'. The YUV data is returned as three
planes ordered y, u, v. The u and v planes are half the width and height of the resized
rectangle. The y, u, and v values are single bytes. Currently this fails if 'dstSize'
width and height are not even. A 'srcRect' that is not contained by the bounds of the
image causes failure.
When the pixel data is ready the caller's ReadPixelsCallback is called with a
AsyncReadResult containing the planar data. The AsyncReadResult will have count() == 3.
Upon failure the callback is called with nullptr for AsyncReadResult. For a GPU image this
flushes work but a submit must occur to guarantee a finite time before the callback is
called.
The data is valid for the lifetime of AsyncReadResult with the exception that if the SkImage
is GPU-backed the data is immediately invalidated if the context is abandoned or
destroyed.
@param yuvColorSpace The transformation from RGB to YUV. Applied to the resized image
after it is converted to dstColorSpace.
@param dstColorSpace The color space to convert the resized image to, after rescaling.
@param srcRect The portion of the image to rescale and convert to YUV planes.
@param dstSize The size to rescale srcRect to
@param rescaleGamma controls whether rescaling is done in the image's gamma or whether
the source data is transformed to a linear gamma before rescaling.
@param rescaleMode controls the technique (and cost) of the rescaling
@param callback function to call with the planar read result
@param context passed to callback
*/
void asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,
sk_sp<SkColorSpace> dstColorSpace,
const SkIRect& srcRect,
const SkISize& dstSize,
RescaleGamma rescaleGamma,
RescaleMode rescaleMode,
ReadPixelsCallback callback,
ReadPixelsContext context) const;
/**
* Identical to asyncRescaleAndReadPixelsYUV420 but a fourth plane is returned in the
* AsyncReadResult passed to 'callback'. The fourth plane contains the alpha chanel at the
* same full resolution as the Y plane.
*/
void asyncRescaleAndReadPixelsYUVA420(SkYUVColorSpace yuvColorSpace,
sk_sp<SkColorSpace> dstColorSpace,
const SkIRect& srcRect,
const SkISize& dstSize,
RescaleGamma rescaleGamma,
RescaleMode rescaleMode,
ReadPixelsCallback callback,
ReadPixelsContext context) const;
/** Copies SkImage to dst, scaling pixels to fit dst.width() and dst.height(), and
converting pixels to match dst.colorType() and dst.alphaType(). Returns true if
pixels are copied. Returns false if dst.addr() is nullptr, or dst.rowBytes() is
less than dst SkImageInfo::minRowBytes.
Pixels are copied only if pixel conversion is possible. If SkImage SkColorType is
kGray_8_SkColorType, or kAlpha_8_SkColorType; dst.colorType() must match.
If SkImage SkColorType is kGray_8_SkColorType, dst.colorSpace() must match.
If SkImage SkAlphaType is kOpaque_SkAlphaType, dst.alphaType() must
match. If SkImage SkColorSpace is nullptr, dst.colorSpace() must match. Returns
false if pixel conversion is not possible.
If cachingHint is kAllow_CachingHint, pixels may be retained locally.
If cachingHint is kDisallow_CachingHint, pixels are not added to the local cache.
@param dst destination SkPixmap: SkImageInfo, pixels, row bytes
@return true if pixels are scaled to fit dst
*/
bool scalePixels(const SkPixmap& dst, const SkSamplingOptions&,
CachingHint cachingHint = kAllow_CachingHint) const;
/** Returns encoded SkImage pixels as SkData, if SkImage was created from supported
encoded stream format. Platform support for formats vary and may require building
with one or more of: SK_ENCODE_JPEG, SK_ENCODE_PNG, SK_ENCODE_WEBP.
Returns nullptr if SkImage contents are not encoded.
@return encoded SkImage, or nullptr
example: https://fiddle.skia.org/c/@Image_refEncodedData
*/
sk_sp<SkData> refEncodedData() const;
/** Returns subset of this image.
Returns nullptr if any of the following are true:
- Subset is empty
- Subset is not contained inside the image's bounds
- Pixels in the source image could not be read or copied
- This image is texture-backed and the provided context is null or does not match
the source image's context.
If the source image was texture-backed, the resulting image will be texture-backed also.
Otherwise, the returned image will be raster-backed.
@param direct the GrDirectContext of the source image (nullptr is ok if the source image
is not texture-backed).
@param subset bounds of returned SkImage
@return the subsetted image, or nullptr
example: https://fiddle.skia.org/c/@Image_makeSubset
*/
virtual sk_sp<SkImage> makeSubset(GrDirectContext* direct, const SkIRect& subset) const = 0;
struct RequiredProperties {
bool fMipmapped;
bool operator==(const RequiredProperties& other) const {
return fMipmapped == other.fMipmapped;
}
bool operator!=(const RequiredProperties& other) const { return !(*this == other); }
bool operator<(const RequiredProperties& other) const {
return fMipmapped < other.fMipmapped;
}
};
/** Returns subset of this image.
Returns nullptr if any of the following are true:
- Subset is empty
- Subset is not contained inside the image's bounds
- Pixels in the image could not be read or copied
- This image is texture-backed and the provided context is null or does not match
the source image's context.
If the source image was texture-backed, the resulting image will be texture-backed also.
Otherwise, the returned image will be raster-backed.
@param recorder the recorder of the source image (nullptr is ok if the
source image was texture-backed).
@param subset bounds of returned SkImage
@param RequiredProperties properties the returned SkImage must possess (e.g. mipmaps)
@return the subsetted image, or nullptr
*/
virtual sk_sp<SkImage> makeSubset(skgpu::graphite::Recorder*,
const SkIRect& subset,
RequiredProperties) const = 0;
/**
* Returns true if the image has mipmap levels.
*/
bool hasMipmaps() const;
/**
* Returns true if the image holds protected content.
*/
bool isProtected() const;
/**
* Returns an image with the same "base" pixels as the this image, but with mipmap levels
* automatically generated and attached.
*/
sk_sp<SkImage> withDefaultMipmaps() const;
/** Returns raster image or lazy image. Copies SkImage backed by GPU texture into
CPU memory if needed. Returns original SkImage if decoded in raster bitmap,
or if encoded in a stream.
Returns nullptr if backed by GPU texture and copy fails.
@return raster image, lazy image, or nullptr
example: https://fiddle.skia.org/c/@Image_makeNonTextureImage
*/
sk_sp<SkImage> makeNonTextureImage(GrDirectContext* = nullptr) const;
/** Returns raster image. Copies SkImage backed by GPU texture into CPU memory,
or decodes SkImage from lazy image. Returns original SkImage if decoded in
raster bitmap.
Returns nullptr if copy, decode, or pixel read fails.
If cachingHint is kAllow_CachingHint, pixels may be retained locally.
If cachingHint is kDisallow_CachingHint, pixels are not added to the local cache.
@return raster image, or nullptr
example: https://fiddle.skia.org/c/@Image_makeRasterImage
*/
sk_sp<SkImage> makeRasterImage(GrDirectContext*,
CachingHint cachingHint = kDisallow_CachingHint) const;
#if !defined(SK_IMAGE_READ_PIXELS_DISABLE_LEGACY_API)
sk_sp<SkImage> makeRasterImage(CachingHint cachingHint = kDisallow_CachingHint) const {
return this->makeRasterImage(nullptr, cachingHint);
}
#endif
/** Deprecated.
*/
enum LegacyBitmapMode {
kRO_LegacyBitmapMode, //!< returned bitmap is read-only and immutable
};
/** Deprecated.
Creates raster SkBitmap with same pixels as SkImage. If legacyBitmapMode is
kRO_LegacyBitmapMode, returned bitmap is read-only and immutable.
Returns true if SkBitmap is stored in bitmap. Returns false and resets bitmap if
SkBitmap write did not succeed.
@param bitmap storage for legacy SkBitmap
@param legacyBitmapMode bitmap is read-only and immutable
@return true if SkBitmap was created
*/
bool asLegacyBitmap(SkBitmap* bitmap,
LegacyBitmapMode legacyBitmapMode = kRO_LegacyBitmapMode) const;
/** Returns true if SkImage is backed by an image-generator or other service that creates
and caches its pixels or texture on-demand.
@return true if SkImage is created as needed
example: https://fiddle.skia.org/c/@Image_isLazyGenerated_a
example: https://fiddle.skia.org/c/@Image_isLazyGenerated_b
*/
virtual bool isLazyGenerated() const = 0;
/** Creates SkImage in target SkColorSpace.
Returns nullptr if SkImage could not be created.
Returns original SkImage if it is in target SkColorSpace.
Otherwise, converts pixels from SkImage SkColorSpace to target SkColorSpace.
If SkImage colorSpace() returns nullptr, SkImage SkColorSpace is assumed to be sRGB.
If this image is texture-backed, the context parameter is required and must match the
context of the source image.
@param direct The GrDirectContext in play, if it exists
@param target SkColorSpace describing color range of returned SkImage
@return created SkImage in target SkColorSpace
example: https://fiddle.skia.org/c/@Image_makeColorSpace
*/
virtual sk_sp<SkImage> makeColorSpace(GrDirectContext* direct,
sk_sp<SkColorSpace> target) const = 0;
/** Creates SkImage in target SkColorSpace.
Returns nullptr if SkImage could not be created.
Returns original SkImage if it is in target SkColorSpace.
Otherwise, converts pixels from SkImage SkColorSpace to target SkColorSpace.
If SkImage colorSpace() returns nullptr, SkImage SkColorSpace is assumed to be sRGB.
If this image is graphite-backed, the recorder parameter is required.
@param targetColorSpace SkColorSpace describing color range of returned SkImage
@param recorder The Recorder in which to create the new image
@param RequiredProperties properties the returned SkImage must possess (e.g. mipmaps)
@return created SkImage in target SkColorSpace
*/
virtual sk_sp<SkImage> makeColorSpace(skgpu::graphite::Recorder*,
sk_sp<SkColorSpace> targetColorSpace,
RequiredProperties) const = 0;
/** Experimental.
Creates SkImage in target SkColorType and SkColorSpace.
Returns nullptr if SkImage could not be created.
Returns original SkImage if it is in target SkColorType and SkColorSpace.
If this image is texture-backed, the context parameter is required and must match the
context of the source image.
@param direct The GrDirectContext in play, if it exists
@param targetColorType SkColorType of returned SkImage
@param targetColorSpace SkColorSpace of returned SkImage
@return created SkImage in target SkColorType and SkColorSpace
*/
virtual sk_sp<SkImage> makeColorTypeAndColorSpace(GrDirectContext* direct,
SkColorType targetColorType,
sk_sp<SkColorSpace> targetCS) const = 0;
/** Experimental.
Creates SkImage in target SkColorType and SkColorSpace.
Returns nullptr if SkImage could not be created.
Returns original SkImage if it is in target SkColorType and SkColorSpace.
If this image is graphite-backed, the recorder parameter is required.
@param targetColorType SkColorType of returned SkImage
@param targetColorSpace SkColorSpace of returned SkImage
@param recorder The Recorder in which to create the new image
@param RequiredProperties properties the returned SkImage must possess (e.g. mipmaps)
@return created SkImage in target SkColorType and SkColorSpace
*/
virtual sk_sp<SkImage> makeColorTypeAndColorSpace(skgpu::graphite::Recorder*,
SkColorType targetColorType,
sk_sp<SkColorSpace> targetColorSpace,
RequiredProperties) const = 0;
/** Creates a new SkImage identical to this one, but with a different SkColorSpace.
This does not convert the underlying pixel data, so the resulting image will draw
differently.
*/
sk_sp<SkImage> reinterpretColorSpace(sk_sp<SkColorSpace> newColorSpace) const;
private:
SkImage(const SkImageInfo& info, uint32_t uniqueID);
friend class SkBitmap;
friend class SkImage_Base; // for private ctor
friend class SkImage_Raster; // for withMipmaps
friend class SkMipmapBuilder;
SkImageInfo fInfo;
const uint32_t fUniqueID;
sk_sp<SkImage> withMipmaps(sk_sp<SkMipmap>) const;
using INHERITED = SkRefCnt;
};
#endif

View File

@ -0,0 +1,119 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkImageFilter_DEFINED
#define SkImageFilter_DEFINED
#include "include/core/SkFlattenable.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/private/base/SkAPI.h"
#include <cstddef>
class SkColorFilter;
class SkMatrix;
struct SkDeserialProcs;
/**
* Base class for image filters. If one is installed in the paint, then all drawing occurs as
* usual, but it is as if the drawing happened into an offscreen (before the xfermode is applied).
* This offscreen bitmap will then be handed to the imagefilter, who in turn creates a new bitmap
* which is what will finally be drawn to the device (using the original xfermode).
*
* The local space of image filters matches the local space of the drawn geometry. For instance if
* there is rotation on the canvas, the blur will be computed along those rotated axes and not in
* the device space. In order to achieve this result, the actual drawing of the geometry may happen
* in an unrotated coordinate system so that the filtered image can be computed more easily, and
* then it will be post transformed to match what would have been produced if the geometry were
* drawn with the total canvas matrix to begin with.
*/
class SK_API SkImageFilter : public SkFlattenable {
public:
enum MapDirection {
kForward_MapDirection,
kReverse_MapDirection,
};
/**
* Map a device-space rect recursively forward or backward through the filter DAG.
* kForward_MapDirection is used to determine which pixels of the destination canvas a source
* image rect would touch after filtering. kReverse_MapDirection is used to determine which rect
* of the source image would be required to fill the given rect (typically, clip bounds). Used
* for clipping and temp-buffer allocations, so the result need not be exact, but should never
* be smaller than the real answer. The default implementation recursively unions all input
* bounds, or returns the source rect if no inputs.
*
* In kReverse mode, 'inputRect' is the device-space bounds of the input pixels. In kForward
* mode it should always be null. If 'inputRect' is null in kReverse mode the resulting answer
* may be incorrect.
*/
SkIRect filterBounds(const SkIRect& src, const SkMatrix& ctm,
MapDirection, const SkIRect* inputRect = nullptr) const;
/**
* Returns whether this image filter is a color filter and puts the color filter into the
* "filterPtr" parameter if it can. Does nothing otherwise.
* If this returns false, then the filterPtr is unchanged.
* If this returns true, then if filterPtr is not null, it must be set to a ref'd colorfitler
* (i.e. it may not be set to NULL).
*/
bool isColorFilterNode(SkColorFilter** filterPtr) const;
// DEPRECATED : use isColorFilterNode() instead
bool asColorFilter(SkColorFilter** filterPtr) const {
return this->isColorFilterNode(filterPtr);
}
/**
* Returns true (and optionally returns a ref'd filter) if this imagefilter can be completely
* replaced by the returned colorfilter. i.e. the two effects will affect drawing in the same
* way.
*/
bool asAColorFilter(SkColorFilter** filterPtr) const;
/**
* Returns the number of inputs this filter will accept (some inputs can be NULL).
*/
int countInputs() const;
/**
* Returns the input filter at a given index, or NULL if no input is connected. The indices
* used are filter-specific.
*/
const SkImageFilter* getInput(int i) const;
// Default impl returns union of all input bounds.
virtual SkRect computeFastBounds(const SkRect& bounds) const;
// Can this filter DAG compute the resulting bounds of an object-space rectangle?
bool canComputeFastBounds() const;
/**
* If this filter can be represented by another filter + a localMatrix, return that filter,
* else return null.
*/
sk_sp<SkImageFilter> makeWithLocalMatrix(const SkMatrix& matrix) const;
static sk_sp<SkImageFilter> Deserialize(const void* data, size_t size,
const SkDeserialProcs* procs = nullptr) {
return sk_sp<SkImageFilter>(static_cast<SkImageFilter*>(
SkFlattenable::Deserialize(kSkImageFilter_Type, data, size, procs).release()));
}
protected:
sk_sp<SkImageFilter> refMe() const {
return sk_ref_sp(const_cast<SkImageFilter*>(this));
}
private:
friend class SkImageFilter_Base;
using INHERITED = SkFlattenable;
};
#endif

View File

@ -0,0 +1,148 @@
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkImageGenerator_DEFINED
#define SkImageGenerator_DEFINED
#include "include/core/SkData.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkPixmap.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkYUVAPixmaps.h"
#include "include/private/base/SkAPI.h"
#if defined(SK_GRAPHITE)
#include "include/core/SkImage.h"
#include "include/gpu/graphite/Recorder.h"
#endif
#include <cstddef>
#include <cstdint>
class GrRecordingContext;
class SK_API SkImageGenerator {
public:
/**
* The PixelRef which takes ownership of this SkImageGenerator
* will call the image generator's destructor.
*/
virtual ~SkImageGenerator() { }
uint32_t uniqueID() const { return fUniqueID; }
/**
* Return a ref to the encoded (i.e. compressed) representation
* of this data.
*
* If non-NULL is returned, the caller is responsible for calling
* unref() on the data when it is finished.
*/
sk_sp<SkData> refEncodedData() {
return this->onRefEncodedData();
}
/**
* Return the ImageInfo associated with this generator.
*/
const SkImageInfo& getInfo() const { return fInfo; }
/**
* Can this generator be used to produce images that will be drawable to the specified context
* (or to CPU, if context is nullptr)?
*/
bool isValid(GrRecordingContext* context) const {
return this->onIsValid(context);
}
/**
* Will this generator produce protected content
*/
bool isProtected() const {
return this->onIsProtected();
}
/**
* Decode into the given pixels, a block of memory of size at
* least (info.fHeight - 1) * rowBytes + (info.fWidth *
* bytesPerPixel)
*
* Repeated calls to this function should give the same results,
* allowing the PixelRef to be immutable.
*
* @param info A description of the format
* expected by the caller. This can simply be identical
* to the info returned by getInfo().
*
* This contract also allows the caller to specify
* different output-configs, which the implementation can
* decide to support or not.
*
* A size that does not match getInfo() implies a request
* to scale. If the generator cannot perform this scale,
* it will return false.
*
* @return true on success.
*/
bool getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes);
bool getPixels(const SkPixmap& pm) {
return this->getPixels(pm.info(), pm.writable_addr(), pm.rowBytes());
}
/**
* If decoding to YUV is supported, this returns true. Otherwise, this
* returns false and the caller will ignore output parameter yuvaPixmapInfo.
*
* @param supportedDataTypes Indicates the data type/planar config combinations that are
* supported by the caller. If the generator supports decoding to
* YUV(A), but not as a type in supportedDataTypes, this method
* returns false.
* @param yuvaPixmapInfo Output parameter that specifies the planar configuration, subsampling,
* orientation, chroma siting, plane color types, and row bytes.
*/
bool queryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes& supportedDataTypes,
SkYUVAPixmapInfo* yuvaPixmapInfo) const;
/**
* Returns true on success and false on failure.
* This always attempts to perform a full decode. To get the planar
* configuration without decoding use queryYUVAInfo().
*
* @param yuvaPixmaps Contains preallocated pixmaps configured according to a successful call
* to queryYUVAInfo().
*/
bool getYUVAPlanes(const SkYUVAPixmaps& yuvaPixmaps);
virtual bool isTextureGenerator() const { return false; }
protected:
static constexpr int kNeedNewImageUniqueID = 0;
SkImageGenerator(const SkImageInfo& info, uint32_t uniqueId = kNeedNewImageUniqueID);
virtual sk_sp<SkData> onRefEncodedData() { return nullptr; }
struct Options {};
virtual bool onGetPixels(const SkImageInfo&, void*, size_t, const Options&) { return false; }
virtual bool onIsValid(GrRecordingContext*) const { return true; }
virtual bool onIsProtected() const { return false; }
virtual bool onQueryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes&,
SkYUVAPixmapInfo*) const { return false; }
virtual bool onGetYUVAPlanes(const SkYUVAPixmaps&) { return false; }
const SkImageInfo fInfo;
private:
const uint32_t fUniqueID;
SkImageGenerator(SkImageGenerator&&) = delete;
SkImageGenerator(const SkImageGenerator&) = delete;
SkImageGenerator& operator=(SkImageGenerator&&) = delete;
SkImageGenerator& operator=(const SkImageGenerator&) = delete;
};
#endif // SkImageGenerator_DEFINED

View File

@ -0,0 +1,628 @@
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkImageInfo_DEFINED
#define SkImageInfo_DEFINED
#include "include/core/SkAlphaType.h"
#include "include/core/SkColorType.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkSize.h"
#include "include/private/base/SkAPI.h"
#include "include/private/base/SkDebug.h"
#include "include/private/base/SkMath.h"
#include "include/private/base/SkTFitsIn.h"
#include <cstddef>
#include <cstdint>
#include <utility>
class SkColorSpace;
/** Returns the number of bytes required to store a pixel, including unused padding.
Returns zero if ct is kUnknown_SkColorType or invalid.
@return bytes per pixel
*/
SK_API int SkColorTypeBytesPerPixel(SkColorType ct);
/** Returns true if SkColorType always decodes alpha to 1.0, making the pixel
fully opaque. If true, SkColorType does not reserve bits to encode alpha.
@return true if alpha is always set to 1.0
*/
SK_API bool SkColorTypeIsAlwaysOpaque(SkColorType ct);
/** Returns true if canonical can be set to a valid SkAlphaType for colorType. If
there is more than one valid canonical SkAlphaType, set to alphaType, if valid.
If true is returned and canonical is not nullptr, store valid SkAlphaType.
Returns false only if alphaType is kUnknown_SkAlphaType, color type is not
kUnknown_SkColorType, and SkColorType is not always opaque. If false is returned,
canonical is ignored.
@param canonical storage for SkAlphaType
@return true if valid SkAlphaType can be associated with colorType
*/
SK_API bool SkColorTypeValidateAlphaType(SkColorType colorType, SkAlphaType alphaType,
SkAlphaType* canonical = nullptr);
/** \enum SkImageInfo::SkYUVColorSpace
Describes color range of YUV pixels. The color mapping from YUV to RGB varies
depending on the source. YUV pixels may be generated by JPEG images, standard
video streams, or high definition video streams. Each has its own mapping from
YUV to RGB.
JPEG YUV values encode the full range of 0 to 255 for all three components.
Video YUV values often range from 16 to 235 for Y and from 16 to 240 for U and V (limited).
Details of encoding and conversion to RGB are described in YCbCr color space.
The identity colorspace exists to provide a utility mapping from Y to R, U to G and V to B.
It can be used to visualize the YUV planes or to explicitly post process the YUV channels.
*/
enum SkYUVColorSpace : int {
kJPEG_Full_SkYUVColorSpace, //!< describes full range
kRec601_Limited_SkYUVColorSpace, //!< describes SDTV range
kRec709_Full_SkYUVColorSpace, //!< describes HDTV range
kRec709_Limited_SkYUVColorSpace,
kBT2020_8bit_Full_SkYUVColorSpace, //!< describes UHDTV range, non-constant-luminance
kBT2020_8bit_Limited_SkYUVColorSpace,
kBT2020_10bit_Full_SkYUVColorSpace,
kBT2020_10bit_Limited_SkYUVColorSpace,
kBT2020_12bit_Full_SkYUVColorSpace,
kBT2020_12bit_Limited_SkYUVColorSpace,
kFCC_Full_SkYUVColorSpace, //!< describes FCC range
kFCC_Limited_SkYUVColorSpace,
kSMPTE240_Full_SkYUVColorSpace, //!< describes SMPTE240M range
kSMPTE240_Limited_SkYUVColorSpace,
kYDZDX_Full_SkYUVColorSpace, //!< describes YDZDX range
kYDZDX_Limited_SkYUVColorSpace,
kGBR_Full_SkYUVColorSpace, //!< describes GBR range
kGBR_Limited_SkYUVColorSpace,
kYCgCo_8bit_Full_SkYUVColorSpace, //!< describes YCgCo matrix
kYCgCo_8bit_Limited_SkYUVColorSpace,
kYCgCo_10bit_Full_SkYUVColorSpace,
kYCgCo_10bit_Limited_SkYUVColorSpace,
kYCgCo_12bit_Full_SkYUVColorSpace,
kYCgCo_12bit_Limited_SkYUVColorSpace,
kIdentity_SkYUVColorSpace, //!< maps Y->R, U->G, V->B
kLastEnum_SkYUVColorSpace = kIdentity_SkYUVColorSpace, //!< last valid value
// Legacy (deprecated) names:
kJPEG_SkYUVColorSpace = kJPEG_Full_SkYUVColorSpace,
kRec601_SkYUVColorSpace = kRec601_Limited_SkYUVColorSpace,
kRec709_SkYUVColorSpace = kRec709_Limited_SkYUVColorSpace,
kBT2020_SkYUVColorSpace = kBT2020_8bit_Limited_SkYUVColorSpace,
};
/** \struct SkColorInfo
Describes pixel and encoding. SkImageInfo can be created from SkColorInfo by
providing dimensions.
It encodes how pixel bits describe alpha, transparency; color components red, blue,
and green; and SkColorSpace, the range and linearity of colors.
*/
class SK_API SkColorInfo {
public:
/** Creates an SkColorInfo with kUnknown_SkColorType, kUnknown_SkAlphaType,
and no SkColorSpace.
@return empty SkImageInfo
*/
SkColorInfo();
~SkColorInfo();
/** Creates SkColorInfo from SkColorType ct, SkAlphaType at, and optionally SkColorSpace cs.
If SkColorSpace cs is nullptr and SkColorInfo is part of drawing source: SkColorSpace
defaults to sRGB, mapping into SkSurface SkColorSpace.
Parameters are not validated to see if their values are legal, or that the
combination is supported.
@return created SkColorInfo
*/
SkColorInfo(SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs);
SkColorInfo(const SkColorInfo&);
SkColorInfo(SkColorInfo&&);
SkColorInfo& operator=(const SkColorInfo&);
SkColorInfo& operator=(SkColorInfo&&);
SkColorSpace* colorSpace() const;
sk_sp<SkColorSpace> refColorSpace() const;
SkColorType colorType() const { return fColorType; }
SkAlphaType alphaType() const { return fAlphaType; }
bool isOpaque() const {
return SkAlphaTypeIsOpaque(fAlphaType)
|| SkColorTypeIsAlwaysOpaque(fColorType);
}
bool gammaCloseToSRGB() const;
/** Does other represent the same color type, alpha type, and color space? */
bool operator==(const SkColorInfo& other) const;
/** Does other represent a different color type, alpha type, or color space? */
bool operator!=(const SkColorInfo& other) const;
/** Creates SkColorInfo with same SkColorType, SkColorSpace, with SkAlphaType set
to newAlphaType.
Created SkColorInfo contains newAlphaType even if it is incompatible with
SkColorType, in which case SkAlphaType in SkColorInfo is ignored.
*/
SkColorInfo makeAlphaType(SkAlphaType newAlphaType) const;
/** Creates new SkColorInfo with same SkAlphaType, SkColorSpace, with SkColorType
set to newColorType.
*/
SkColorInfo makeColorType(SkColorType newColorType) const;
/** Creates SkColorInfo with same SkAlphaType, SkColorType, with SkColorSpace
set to cs. cs may be nullptr.
*/
SkColorInfo makeColorSpace(sk_sp<SkColorSpace> cs) const;
/** Returns number of bytes per pixel required by SkColorType.
Returns zero if colorType() is kUnknown_SkColorType.
@return bytes in pixel
example: https://fiddle.skia.org/c/@ImageInfo_bytesPerPixel
*/
int bytesPerPixel() const;
/** Returns bit shift converting row bytes to row pixels.
Returns zero for kUnknown_SkColorType.
@return one of: 0, 1, 2, 3, 4; left shift to convert pixels to bytes
example: https://fiddle.skia.org/c/@ImageInfo_shiftPerPixel
*/
int shiftPerPixel() const;
private:
sk_sp<SkColorSpace> fColorSpace;
SkColorType fColorType = kUnknown_SkColorType;
SkAlphaType fAlphaType = kUnknown_SkAlphaType;
};
/** \struct SkImageInfo
Describes pixel dimensions and encoding. SkBitmap, SkImage, PixMap, and SkSurface
can be created from SkImageInfo. SkImageInfo can be retrieved from SkBitmap and
SkPixmap, but not from SkImage and SkSurface. For example, SkImage and SkSurface
implementations may defer pixel depth, so may not completely specify SkImageInfo.
SkImageInfo contains dimensions, the pixel integral width and height. It encodes
how pixel bits describe alpha, transparency; color components red, blue,
and green; and SkColorSpace, the range and linearity of colors.
*/
struct SK_API SkImageInfo {
public:
/** Creates an empty SkImageInfo with kUnknown_SkColorType, kUnknown_SkAlphaType,
a width and height of zero, and no SkColorSpace.
@return empty SkImageInfo
*/
SkImageInfo() = default;
/** Creates SkImageInfo from integral dimensions width and height, SkColorType ct,
SkAlphaType at, and optionally SkColorSpace cs.
If SkColorSpace cs is nullptr and SkImageInfo is part of drawing source: SkColorSpace
defaults to sRGB, mapping into SkSurface SkColorSpace.
Parameters are not validated to see if their values are legal, or that the
combination is supported.
@param width pixel column count; must be zero or greater
@param height pixel row count; must be zero or greater
@param cs range of colors; may be nullptr
@return created SkImageInfo
*/
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at);
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at,
sk_sp<SkColorSpace> cs);
static SkImageInfo Make(SkISize dimensions, SkColorType ct, SkAlphaType at);
static SkImageInfo Make(SkISize dimensions, SkColorType ct, SkAlphaType at,
sk_sp<SkColorSpace> cs);
/** Creates SkImageInfo from integral dimensions and SkColorInfo colorInfo,
Parameters are not validated to see if their values are legal, or that the
combination is supported.
@param dimensions pixel column and row count; must be zeros or greater
@param SkColorInfo the pixel encoding consisting of SkColorType, SkAlphaType, and
SkColorSpace (which may be nullptr)
@return created SkImageInfo
*/
static SkImageInfo Make(SkISize dimensions, const SkColorInfo& colorInfo) {
return SkImageInfo(dimensions, colorInfo);
}
static SkImageInfo Make(SkISize dimensions, SkColorInfo&& colorInfo) {
return SkImageInfo(dimensions, std::move(colorInfo));
}
/** Creates SkImageInfo from integral dimensions width and height, kN32_SkColorType,
SkAlphaType at, and optionally SkColorSpace cs. kN32_SkColorType will equal either
kBGRA_8888_SkColorType or kRGBA_8888_SkColorType, whichever is optimal.
If SkColorSpace cs is nullptr and SkImageInfo is part of drawing source: SkColorSpace
defaults to sRGB, mapping into SkSurface SkColorSpace.
Parameters are not validated to see if their values are legal, or that the
combination is supported.
@param width pixel column count; must be zero or greater
@param height pixel row count; must be zero or greater
@param cs range of colors; may be nullptr
@return created SkImageInfo
*/
static SkImageInfo MakeN32(int width, int height, SkAlphaType at);
static SkImageInfo MakeN32(int width, int height, SkAlphaType at, sk_sp<SkColorSpace> cs);
/** Creates SkImageInfo from integral dimensions width and height, kN32_SkColorType,
SkAlphaType at, with sRGB SkColorSpace.
Parameters are not validated to see if their values are legal, or that the
combination is supported.
@param width pixel column count; must be zero or greater
@param height pixel row count; must be zero or greater
@return created SkImageInfo
example: https://fiddle.skia.org/c/@ImageInfo_MakeS32
*/
static SkImageInfo MakeS32(int width, int height, SkAlphaType at);
/** Creates SkImageInfo from integral dimensions width and height, kN32_SkColorType,
kPremul_SkAlphaType, with optional SkColorSpace.
If SkColorSpace cs is nullptr and SkImageInfo is part of drawing source: SkColorSpace
defaults to sRGB, mapping into SkSurface SkColorSpace.
Parameters are not validated to see if their values are legal, or that the
combination is supported.
@param width pixel column count; must be zero or greater
@param height pixel row count; must be zero or greater
@param cs range of colors; may be nullptr
@return created SkImageInfo
*/
static SkImageInfo MakeN32Premul(int width, int height);
static SkImageInfo MakeN32Premul(int width, int height, sk_sp<SkColorSpace> cs);
/** Creates SkImageInfo from integral dimensions width and height, kN32_SkColorType,
kPremul_SkAlphaType, with SkColorSpace set to nullptr.
If SkImageInfo is part of drawing source: SkColorSpace defaults to sRGB, mapping
into SkSurface SkColorSpace.
Parameters are not validated to see if their values are legal, or that the
combination is supported.
@param dimensions width and height, each must be zero or greater
@param cs range of colors; may be nullptr
@return created SkImageInfo
*/
static SkImageInfo MakeN32Premul(SkISize dimensions);
static SkImageInfo MakeN32Premul(SkISize dimensions, sk_sp<SkColorSpace> cs);
/** Creates SkImageInfo from integral dimensions width and height, kAlpha_8_SkColorType,
kPremul_SkAlphaType, with SkColorSpace set to nullptr.
@param width pixel column count; must be zero or greater
@param height pixel row count; must be zero or greater
@return created SkImageInfo
*/
static SkImageInfo MakeA8(int width, int height);
/** Creates SkImageInfo from integral dimensions, kAlpha_8_SkColorType,
kPremul_SkAlphaType, with SkColorSpace set to nullptr.
@param dimensions pixel row and column count; must be zero or greater
@return created SkImageInfo
*/
static SkImageInfo MakeA8(SkISize dimensions);
/** Creates SkImageInfo from integral dimensions width and height, kUnknown_SkColorType,
kUnknown_SkAlphaType, with SkColorSpace set to nullptr.
Returned SkImageInfo as part of source does not draw, and as part of destination
can not be drawn to.
@param width pixel column count; must be zero or greater
@param height pixel row count; must be zero or greater
@return created SkImageInfo
*/
static SkImageInfo MakeUnknown(int width, int height);
/** Creates SkImageInfo from integral dimensions width and height set to zero,
kUnknown_SkColorType, kUnknown_SkAlphaType, with SkColorSpace set to nullptr.
Returned SkImageInfo as part of source does not draw, and as part of destination
can not be drawn to.
@return created SkImageInfo
*/
static SkImageInfo MakeUnknown() {
return MakeUnknown(0, 0);
}
/** Returns pixel count in each row.
@return pixel width
*/
int width() const { return fDimensions.width(); }
/** Returns pixel row count.
@return pixel height
*/
int height() const { return fDimensions.height(); }
SkColorType colorType() const { return fColorInfo.colorType(); }
SkAlphaType alphaType() const { return fColorInfo.alphaType(); }
/** Returns SkColorSpace, the range of colors. The reference count of
SkColorSpace is unchanged. The returned SkColorSpace is immutable.
@return SkColorSpace, or nullptr
*/
SkColorSpace* colorSpace() const;
/** Returns smart pointer to SkColorSpace, the range of colors. The smart pointer
tracks the number of objects sharing this SkColorSpace reference so the memory
is released when the owners destruct.
The returned SkColorSpace is immutable.
@return SkColorSpace wrapped in a smart pointer
*/
sk_sp<SkColorSpace> refColorSpace() const;
/** Returns if SkImageInfo describes an empty area of pixels by checking if either
width or height is zero or smaller.
@return true if either dimension is zero or smaller
*/
bool isEmpty() const { return fDimensions.isEmpty(); }
/** Returns the dimensionless SkColorInfo that represents the same color type,
alpha type, and color space as this SkImageInfo.
*/
const SkColorInfo& colorInfo() const { return fColorInfo; }
/** Returns true if SkAlphaType is set to hint that all pixels are opaque; their
alpha value is implicitly or explicitly 1.0. If true, and all pixels are
not opaque, Skia may draw incorrectly.
Does not check if SkColorType allows alpha, or if any pixel value has
transparency.
@return true if SkAlphaType is kOpaque_SkAlphaType
*/
bool isOpaque() const { return fColorInfo.isOpaque(); }
/** Returns SkISize { width(), height() }.
@return integral size of width() and height()
*/
SkISize dimensions() const { return fDimensions; }
/** Returns SkIRect { 0, 0, width(), height() }.
@return integral rectangle from origin to width() and height()
*/
SkIRect bounds() const { return SkIRect::MakeSize(fDimensions); }
/** Returns true if associated SkColorSpace is not nullptr, and SkColorSpace gamma
is approximately the same as sRGB.
This includes the
@return true if SkColorSpace gamma is approximately the same as sRGB
*/
bool gammaCloseToSRGB() const { return fColorInfo.gammaCloseToSRGB(); }
/** Creates SkImageInfo with the same SkColorType, SkColorSpace, and SkAlphaType,
with dimensions set to width and height.
@param newWidth pixel column count; must be zero or greater
@param newHeight pixel row count; must be zero or greater
@return created SkImageInfo
*/
SkImageInfo makeWH(int newWidth, int newHeight) const {
return Make({newWidth, newHeight}, fColorInfo);
}
/** Creates SkImageInfo with the same SkColorType, SkColorSpace, and SkAlphaType,
with dimensions set to newDimensions.
@param newSize pixel column and row count; must be zero or greater
@return created SkImageInfo
*/
SkImageInfo makeDimensions(SkISize newSize) const {
return Make(newSize, fColorInfo);
}
/** Creates SkImageInfo with same SkColorType, SkColorSpace, width, and height,
with SkAlphaType set to newAlphaType.
Created SkImageInfo contains newAlphaType even if it is incompatible with
SkColorType, in which case SkAlphaType in SkImageInfo is ignored.
@return created SkImageInfo
*/
SkImageInfo makeAlphaType(SkAlphaType newAlphaType) const {
return Make(fDimensions, fColorInfo.makeAlphaType(newAlphaType));
}
/** Creates SkImageInfo with same SkAlphaType, SkColorSpace, width, and height,
with SkColorType set to newColorType.
@return created SkImageInfo
*/
SkImageInfo makeColorType(SkColorType newColorType) const {
return Make(fDimensions, fColorInfo.makeColorType(newColorType));
}
/** Creates SkImageInfo with same SkAlphaType, SkColorType, width, and height,
with SkColorSpace set to cs.
@param cs range of colors; may be nullptr
@return created SkImageInfo
*/
SkImageInfo makeColorSpace(sk_sp<SkColorSpace> cs) const;
/** Returns number of bytes per pixel required by SkColorType.
Returns zero if colorType( is kUnknown_SkColorType.
@return bytes in pixel
*/
int bytesPerPixel() const { return fColorInfo.bytesPerPixel(); }
/** Returns bit shift converting row bytes to row pixels.
Returns zero for kUnknown_SkColorType.
@return one of: 0, 1, 2, 3; left shift to convert pixels to bytes
*/
int shiftPerPixel() const { return fColorInfo.shiftPerPixel(); }
/** Returns minimum bytes per row, computed from pixel width() and SkColorType, which
specifies bytesPerPixel(). SkBitmap maximum value for row bytes must fit
in 31 bits.
@return width() times bytesPerPixel() as unsigned 64-bit integer
*/
uint64_t minRowBytes64() const {
return (uint64_t)sk_64_mul(this->width(), this->bytesPerPixel());
}
/** Returns minimum bytes per row, computed from pixel width() and SkColorType, which
specifies bytesPerPixel(). SkBitmap maximum value for row bytes must fit
in 31 bits.
@return width() times bytesPerPixel() as size_t
*/
size_t minRowBytes() const {
uint64_t minRowBytes = this->minRowBytes64();
if (!SkTFitsIn<int32_t>(minRowBytes)) {
return 0;
}
return (size_t)minRowBytes;
}
/** Returns byte offset of pixel from pixel base address.
Asserts in debug build if x or y is outside of bounds. Does not assert if
rowBytes is smaller than minRowBytes(), even though result may be incorrect.
@param x column index, zero or greater, and less than width()
@param y row index, zero or greater, and less than height()
@param rowBytes size of pixel row or larger
@return offset within pixel array
example: https://fiddle.skia.org/c/@ImageInfo_computeOffset
*/
size_t computeOffset(int x, int y, size_t rowBytes) const;
/** Compares SkImageInfo with other, and returns true if width, height, SkColorType,
SkAlphaType, and SkColorSpace are equivalent.
@param other SkImageInfo to compare
@return true if SkImageInfo equals other
*/
bool operator==(const SkImageInfo& other) const {
return fDimensions == other.fDimensions && fColorInfo == other.fColorInfo;
}
/** Compares SkImageInfo with other, and returns true if width, height, SkColorType,
SkAlphaType, and SkColorSpace are not equivalent.
@param other SkImageInfo to compare
@return true if SkImageInfo is not equal to other
*/
bool operator!=(const SkImageInfo& other) const {
return !(*this == other);
}
/** Returns storage required by pixel array, given SkImageInfo dimensions, SkColorType,
and rowBytes. rowBytes is assumed to be at least as large as minRowBytes().
Returns zero if height is zero.
Returns SIZE_MAX if answer exceeds the range of size_t.
@param rowBytes size of pixel row or larger
@return memory required by pixel buffer
*/
size_t computeByteSize(size_t rowBytes) const;
/** Returns storage required by pixel array, given SkImageInfo dimensions, and
SkColorType. Uses minRowBytes() to compute bytes for pixel row.
Returns zero if height is zero.
Returns SIZE_MAX if answer exceeds the range of size_t.
@return least memory required by pixel buffer
*/
size_t computeMinByteSize() const {
return this->computeByteSize(this->minRowBytes());
}
/** Returns true if byteSize equals SIZE_MAX. computeByteSize() and
computeMinByteSize() return SIZE_MAX if size_t can not hold buffer size.
@param byteSize result of computeByteSize() or computeMinByteSize()
@return true if computeByteSize() or computeMinByteSize() result exceeds size_t
*/
static bool ByteSizeOverflowed(size_t byteSize) {
return SIZE_MAX == byteSize;
}
/** Returns true if rowBytes is valid for this SkImageInfo.
@param rowBytes size of pixel row including padding
@return true if rowBytes is large enough to contain pixel row and is properly
aligned
*/
bool validRowBytes(size_t rowBytes) const {
if (rowBytes < this->minRowBytes64()) {
return false;
}
int shift = this->shiftPerPixel();
size_t alignedRowBytes = rowBytes >> shift << shift;
return alignedRowBytes == rowBytes;
}
/** Creates an empty SkImageInfo with kUnknown_SkColorType, kUnknown_SkAlphaType,
a width and height of zero, and no SkColorSpace.
*/
void reset() { *this = {}; }
/** Asserts if internal values are illegal or inconsistent. Only available if
SK_DEBUG is defined at compile time.
*/
SkDEBUGCODE(void validate() const;)
private:
SkColorInfo fColorInfo;
SkISize fDimensions = {0, 0};
SkImageInfo(SkISize dimensions, const SkColorInfo& colorInfo)
: fColorInfo(colorInfo), fDimensions(dimensions) {}
SkImageInfo(SkISize dimensions, SkColorInfo&& colorInfo)
: fColorInfo(std::move(colorInfo)), fDimensions(dimensions) {}
};
#endif

View File

@ -0,0 +1,442 @@
/*
* Copyright 2020 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkM44_DEFINED
#define SkM44_DEFINED
#include "include/core/SkMatrix.h"
#include "include/core/SkScalar.h"
#include "include/core/SkTypes.h"
#include <cstring>
struct SkRect;
struct SK_API SkV2 {
float x, y;
bool operator==(const SkV2 v) const { return x == v.x && y == v.y; }
bool operator!=(const SkV2 v) const { return !(*this == v); }
static SkScalar Dot(SkV2 a, SkV2 b) { return a.x * b.x + a.y * b.y; }
static SkScalar Cross(SkV2 a, SkV2 b) { return a.x * b.y - a.y * b.x; }
static SkV2 Normalize(SkV2 v) { return v * (1.0f / v.length()); }
SkV2 operator-() const { return {-x, -y}; }
SkV2 operator+(SkV2 v) const { return {x+v.x, y+v.y}; }
SkV2 operator-(SkV2 v) const { return {x-v.x, y-v.y}; }
SkV2 operator*(SkV2 v) const { return {x*v.x, y*v.y}; }
friend SkV2 operator*(SkV2 v, SkScalar s) { return {v.x*s, v.y*s}; }
friend SkV2 operator*(SkScalar s, SkV2 v) { return {v.x*s, v.y*s}; }
friend SkV2 operator/(SkV2 v, SkScalar s) { return {v.x/s, v.y/s}; }
friend SkV2 operator/(SkScalar s, SkV2 v) { return {s/v.x, s/v.y}; }
void operator+=(SkV2 v) { *this = *this + v; }
void operator-=(SkV2 v) { *this = *this - v; }
void operator*=(SkV2 v) { *this = *this * v; }
void operator*=(SkScalar s) { *this = *this * s; }
void operator/=(SkScalar s) { *this = *this / s; }
SkScalar lengthSquared() const { return Dot(*this, *this); }
SkScalar length() const { return SkScalarSqrt(this->lengthSquared()); }
SkScalar dot(SkV2 v) const { return Dot(*this, v); }
SkScalar cross(SkV2 v) const { return Cross(*this, v); }
SkV2 normalize() const { return Normalize(*this); }
const float* ptr() const { return &x; }
float* ptr() { return &x; }
};
struct SK_API SkV3 {
float x, y, z;
bool operator==(const SkV3& v) const {
return x == v.x && y == v.y && z == v.z;
}
bool operator!=(const SkV3& v) const { return !(*this == v); }
static SkScalar Dot(const SkV3& a, const SkV3& b) { return a.x*b.x + a.y*b.y + a.z*b.z; }
static SkV3 Cross(const SkV3& a, const SkV3& b) {
return { a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x };
}
static SkV3 Normalize(const SkV3& v) { return v * (1.0f / v.length()); }
SkV3 operator-() const { return {-x, -y, -z}; }
SkV3 operator+(const SkV3& v) const { return { x + v.x, y + v.y, z + v.z }; }
SkV3 operator-(const SkV3& v) const { return { x - v.x, y - v.y, z - v.z }; }
SkV3 operator*(const SkV3& v) const {
return { x*v.x, y*v.y, z*v.z };
}
friend SkV3 operator*(const SkV3& v, SkScalar s) {
return { v.x*s, v.y*s, v.z*s };
}
friend SkV3 operator*(SkScalar s, const SkV3& v) { return v*s; }
void operator+=(SkV3 v) { *this = *this + v; }
void operator-=(SkV3 v) { *this = *this - v; }
void operator*=(SkV3 v) { *this = *this * v; }
void operator*=(SkScalar s) { *this = *this * s; }
SkScalar lengthSquared() const { return Dot(*this, *this); }
SkScalar length() const { return SkScalarSqrt(Dot(*this, *this)); }
SkScalar dot(const SkV3& v) const { return Dot(*this, v); }
SkV3 cross(const SkV3& v) const { return Cross(*this, v); }
SkV3 normalize() const { return Normalize(*this); }
const float* ptr() const { return &x; }
float* ptr() { return &x; }
};
struct SK_API SkV4 {
float x, y, z, w;
bool operator==(const SkV4& v) const {
return x == v.x && y == v.y && z == v.z && w == v.w;
}
bool operator!=(const SkV4& v) const { return !(*this == v); }
static SkScalar Dot(const SkV4& a, const SkV4& b) {
return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w;
}
static SkV4 Normalize(const SkV4& v) { return v * (1.0f / v.length()); }
SkV4 operator-() const { return {-x, -y, -z, -w}; }
SkV4 operator+(const SkV4& v) const { return { x + v.x, y + v.y, z + v.z, w + v.w }; }
SkV4 operator-(const SkV4& v) const { return { x - v.x, y - v.y, z - v.z, w - v.w }; }
SkV4 operator*(const SkV4& v) const {
return { x*v.x, y*v.y, z*v.z, w*v.w };
}
friend SkV4 operator*(const SkV4& v, SkScalar s) {
return { v.x*s, v.y*s, v.z*s, v.w*s };
}
friend SkV4 operator*(SkScalar s, const SkV4& v) { return v*s; }
SkScalar lengthSquared() const { return Dot(*this, *this); }
SkScalar length() const { return SkScalarSqrt(Dot(*this, *this)); }
SkScalar dot(const SkV4& v) const { return Dot(*this, v); }
SkV4 normalize() const { return Normalize(*this); }
const float* ptr() const { return &x; }
float* ptr() { return &x; }
float operator[](int i) const {
SkASSERT(i >= 0 && i < 4);
return this->ptr()[i];
}
float& operator[](int i) {
SkASSERT(i >= 0 && i < 4);
return this->ptr()[i];
}
};
/**
* 4x4 matrix used by SkCanvas and other parts of Skia.
*
* Skia assumes a right-handed coordinate system:
* +X goes to the right
* +Y goes down
* +Z goes into the screen (away from the viewer)
*/
class SK_API SkM44 {
public:
SkM44(const SkM44& src) = default;
SkM44& operator=(const SkM44& src) = default;
constexpr SkM44()
: fMat{1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1}
{}
SkM44(const SkM44& a, const SkM44& b) {
this->setConcat(a, b);
}
enum Uninitialized_Constructor {
kUninitialized_Constructor
};
SkM44(Uninitialized_Constructor) {}
enum NaN_Constructor {
kNaN_Constructor
};
constexpr SkM44(NaN_Constructor)
: fMat{SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN,
SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN,
SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN,
SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN}
{}
/**
* The constructor parameters are in row-major order.
*/
constexpr SkM44(SkScalar m0, SkScalar m4, SkScalar m8, SkScalar m12,
SkScalar m1, SkScalar m5, SkScalar m9, SkScalar m13,
SkScalar m2, SkScalar m6, SkScalar m10, SkScalar m14,
SkScalar m3, SkScalar m7, SkScalar m11, SkScalar m15)
// fMat is column-major order in memory.
: fMat{m0, m1, m2, m3,
m4, m5, m6, m7,
m8, m9, m10, m11,
m12, m13, m14, m15}
{}
static SkM44 Rows(const SkV4& r0, const SkV4& r1, const SkV4& r2, const SkV4& r3) {
SkM44 m(kUninitialized_Constructor);
m.setRow(0, r0);
m.setRow(1, r1);
m.setRow(2, r2);
m.setRow(3, r3);
return m;
}
static SkM44 Cols(const SkV4& c0, const SkV4& c1, const SkV4& c2, const SkV4& c3) {
SkM44 m(kUninitialized_Constructor);
m.setCol(0, c0);
m.setCol(1, c1);
m.setCol(2, c2);
m.setCol(3, c3);
return m;
}
static SkM44 RowMajor(const SkScalar r[16]) {
return SkM44(r[ 0], r[ 1], r[ 2], r[ 3],
r[ 4], r[ 5], r[ 6], r[ 7],
r[ 8], r[ 9], r[10], r[11],
r[12], r[13], r[14], r[15]);
}
static SkM44 ColMajor(const SkScalar c[16]) {
return SkM44(c[0], c[4], c[ 8], c[12],
c[1], c[5], c[ 9], c[13],
c[2], c[6], c[10], c[14],
c[3], c[7], c[11], c[15]);
}
static SkM44 Translate(SkScalar x, SkScalar y, SkScalar z = 0) {
return SkM44(1, 0, 0, x,
0, 1, 0, y,
0, 0, 1, z,
0, 0, 0, 1);
}
static SkM44 Scale(SkScalar x, SkScalar y, SkScalar z = 1) {
return SkM44(x, 0, 0, 0,
0, y, 0, 0,
0, 0, z, 0,
0, 0, 0, 1);
}
static SkM44 Rotate(SkV3 axis, SkScalar radians) {
SkM44 m(kUninitialized_Constructor);
m.setRotate(axis, radians);
return m;
}
// Scales and translates 'src' to fill 'dst' exactly.
static SkM44 RectToRect(const SkRect& src, const SkRect& dst);
static SkM44 LookAt(const SkV3& eye, const SkV3& center, const SkV3& up);
static SkM44 Perspective(float near, float far, float angle);
bool operator==(const SkM44& other) const;
bool operator!=(const SkM44& other) const {
return !(other == *this);
}
void getColMajor(SkScalar v[]) const {
memcpy(v, fMat, sizeof(fMat));
}
void getRowMajor(SkScalar v[]) const;
SkScalar rc(int r, int c) const {
SkASSERT(r >= 0 && r <= 3);
SkASSERT(c >= 0 && c <= 3);
return fMat[c*4 + r];
}
void setRC(int r, int c, SkScalar value) {
SkASSERT(r >= 0 && r <= 3);
SkASSERT(c >= 0 && c <= 3);
fMat[c*4 + r] = value;
}
SkV4 row(int i) const {
SkASSERT(i >= 0 && i <= 3);
return {fMat[i + 0], fMat[i + 4], fMat[i + 8], fMat[i + 12]};
}
SkV4 col(int i) const {
SkASSERT(i >= 0 && i <= 3);
return {fMat[i*4 + 0], fMat[i*4 + 1], fMat[i*4 + 2], fMat[i*4 + 3]};
}
void setRow(int i, const SkV4& v) {
SkASSERT(i >= 0 && i <= 3);
fMat[i + 0] = v.x;
fMat[i + 4] = v.y;
fMat[i + 8] = v.z;
fMat[i + 12] = v.w;
}
void setCol(int i, const SkV4& v) {
SkASSERT(i >= 0 && i <= 3);
memcpy(&fMat[i*4], v.ptr(), sizeof(v));
}
SkM44& setIdentity() {
*this = { 1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1 };
return *this;
}
SkM44& setTranslate(SkScalar x, SkScalar y, SkScalar z = 0) {
*this = { 1, 0, 0, x,
0, 1, 0, y,
0, 0, 1, z,
0, 0, 0, 1 };
return *this;
}
SkM44& setScale(SkScalar x, SkScalar y, SkScalar z = 1) {
*this = { x, 0, 0, 0,
0, y, 0, 0,
0, 0, z, 0,
0, 0, 0, 1 };
return *this;
}
/**
* Set this matrix to rotate about the specified unit-length axis vector,
* by an angle specified by its sin() and cos().
*
* This does not attempt to verify that axis.length() == 1 or that the sin,cos values
* are correct.
*/
SkM44& setRotateUnitSinCos(SkV3 axis, SkScalar sinAngle, SkScalar cosAngle);
/**
* Set this matrix to rotate about the specified unit-length axis vector,
* by an angle specified in radians.
*
* This does not attempt to verify that axis.length() == 1.
*/
SkM44& setRotateUnit(SkV3 axis, SkScalar radians) {
return this->setRotateUnitSinCos(axis, SkScalarSin(radians), SkScalarCos(radians));
}
/**
* Set this matrix to rotate about the specified axis vector,
* by an angle specified in radians.
*
* Note: axis is not assumed to be unit-length, so it will be normalized internally.
* If axis is already unit-length, call setRotateAboutUnitRadians() instead.
*/
SkM44& setRotate(SkV3 axis, SkScalar radians);
SkM44& setConcat(const SkM44& a, const SkM44& b);
friend SkM44 operator*(const SkM44& a, const SkM44& b) {
return SkM44(a, b);
}
SkM44& preConcat(const SkM44& m) {
return this->setConcat(*this, m);
}
SkM44& postConcat(const SkM44& m) {
return this->setConcat(m, *this);
}
/**
* A matrix is categorized as 'perspective' if the bottom row is not [0, 0, 0, 1].
* For most uses, a bottom row of [0, 0, 0, X] behaves like a non-perspective matrix, though
* it will be categorized as perspective. Calling normalizePerspective() will change the
* matrix such that, if its bottom row was [0, 0, 0, X], it will be changed to [0, 0, 0, 1]
* by scaling the rest of the matrix by 1/X.
*
* | A B C D | | A/X B/X C/X D/X |
* | E F G H | -> | E/X F/X G/X H/X | for X != 0
* | I J K L | | I/X J/X K/X L/X |
* | 0 0 0 X | | 0 0 0 1 |
*/
void normalizePerspective();
/** Returns true if all elements of the matrix are finite. Returns false if any
element is infinity, or NaN.
@return true if matrix has only finite elements
*/
bool isFinite() const { return SkIsFinite(fMat, 16); }
/** If this is invertible, return that in inverse and return true. If it is
* not invertible, return false and leave the inverse parameter unchanged.
*/
[[nodiscard]] bool invert(SkM44* inverse) const;
[[nodiscard]] SkM44 transpose() const;
void dump() const;
////////////
SkV4 map(float x, float y, float z, float w) const;
SkV4 operator*(const SkV4& v) const {
return this->map(v.x, v.y, v.z, v.w);
}
SkV3 operator*(SkV3 v) const {
auto v4 = this->map(v.x, v.y, v.z, 0);
return {v4.x, v4.y, v4.z};
}
////////////////////// Converting to/from SkMatrix
/* When converting from SkM44 to SkMatrix, the third row and
* column is dropped. When converting from SkMatrix to SkM44
* the third row and column remain as identity:
* [ a b c ] [ a b 0 c ]
* [ d e f ] -> [ d e 0 f ]
* [ g h i ] [ 0 0 1 0 ]
* [ g h 0 i ]
*/
SkMatrix asM33() const {
return SkMatrix::MakeAll(fMat[0], fMat[4], fMat[12],
fMat[1], fMat[5], fMat[13],
fMat[3], fMat[7], fMat[15]);
}
explicit SkM44(const SkMatrix& src)
: SkM44(src[SkMatrix::kMScaleX], src[SkMatrix::kMSkewX], 0, src[SkMatrix::kMTransX],
src[SkMatrix::kMSkewY], src[SkMatrix::kMScaleY], 0, src[SkMatrix::kMTransY],
0, 0, 1, 0,
src[SkMatrix::kMPersp0], src[SkMatrix::kMPersp1], 0, src[SkMatrix::kMPersp2])
{}
SkM44& preTranslate(SkScalar x, SkScalar y, SkScalar z = 0);
SkM44& postTranslate(SkScalar x, SkScalar y, SkScalar z = 0);
SkM44& preScale(SkScalar x, SkScalar y);
SkM44& preScale(SkScalar x, SkScalar y, SkScalar z);
SkM44& preConcat(const SkMatrix&);
private:
/* Stored in column-major.
* Indices
* 0 4 8 12 1 0 0 trans_x
* 1 5 9 13 e.g. 0 1 0 trans_y
* 2 6 10 14 0 0 1 trans_z
* 3 7 11 15 0 0 0 1
*/
SkScalar fMat[16];
friend class SkMatrixPriv;
};
#endif

View File

@ -0,0 +1,45 @@
/*
* Copyright 2008 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkMallocPixelRef_DEFINED
#define SkMallocPixelRef_DEFINED
#include "include/core/SkRefCnt.h"
#include "include/core/SkTypes.h"
#include <cstddef>
class SkData;
class SkPixelRef;
struct SkImageInfo;
/** We explicitly use the same allocator for our pixels that SkMask does,
so that we can freely assign memory allocated by one class to the other.
*/
namespace SkMallocPixelRef {
/**
* Return a new SkMallocPixelRef, automatically allocating storage for the
* pixels. If rowBytes are 0, an optimal value will be chosen automatically.
* If rowBytes is > 0, then it will be respected, or NULL will be returned
* if rowBytes is invalid for the specified info.
*
* All pixel bytes are zeroed.
*
* Returns NULL on failure.
*/
SK_API sk_sp<SkPixelRef> MakeAllocate(const SkImageInfo&, size_t rowBytes);
/**
* Return a new SkMallocPixelRef that will use the provided SkData and
* rowBytes as pixel storage. The SkData will be ref()ed and on
* destruction of the PixelRef, the SkData will be unref()ed.
*
* Returns NULL on failure.
*/
SK_API sk_sp<SkPixelRef> MakeWithData(const SkImageInfo&, size_t rowBytes, sk_sp<SkData> data);
} // namespace SkMallocPixelRef
#endif

View File

@ -0,0 +1,53 @@
/*
* Copyright 2006 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkMaskFilter_DEFINED
#define SkMaskFilter_DEFINED
#include "include/core/SkFlattenable.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/core/SkTypes.h"
#include <cstddef>
enum SkBlurStyle : int;
struct SkDeserialProcs;
struct SkRect;
/** \class SkMaskFilter
SkMaskFilter is the base class for object that perform transformations on
the mask before drawing it. An example subclass is Blur.
*/
class SK_API SkMaskFilter : public SkFlattenable {
public:
/** Create a blur maskfilter.
* @param style The SkBlurStyle to use
* @param sigma Standard deviation of the Gaussian blur to apply. Must be > 0.
* @param respectCTM if true the blur's sigma is modified by the CTM.
* @return The new blur maskfilter
*/
static sk_sp<SkMaskFilter> MakeBlur(SkBlurStyle style, SkScalar sigma,
bool respectCTM = true);
/**
* Returns the approximate bounds that would result from filtering the src rect.
* The actual result may be different, but it should be contained within the
* returned bounds.
*/
SkRect approximateFilteredBounds(const SkRect& src) const;
static sk_sp<SkMaskFilter> Deserialize(const void* data, size_t size,
const SkDeserialProcs* procs = nullptr);
private:
static void RegisterFlattenables();
friend class SkFlattenable;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,429 @@
/*
* Copyright 2021 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkMesh_DEFINED
#define SkMesh_DEFINED
#include "include/core/SkData.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkSpan.h"
#include "include/core/SkString.h"
#include "include/effects/SkRuntimeEffect.h"
#include "include/private/base/SkAPI.h"
#include "include/private/base/SkTArray.h"
#include <cstddef>
#include <cstdint>
#include <memory>
#include <string_view>
#include <tuple>
#include <vector>
class GrDirectContext;
class SkColorSpace;
enum SkAlphaType : int;
namespace SkSL { struct Program; }
/**
* A specification for custom meshes. Specifies the vertex buffer attributes and stride, the
* vertex program that produces a user-defined set of varyings, and a fragment program that ingests
* the interpolated varyings and produces local coordinates for shading and optionally a color.
*
* The varyings must include a float2 named "position". If the passed varyings does not
* contain such a varying then one is implicitly added to the final specification and the SkSL
* Varyings struct described below. It is an error to have a varying named "position" that has a
* type other than float2.
*
* The provided attributes and varyings are used to create Attributes and Varyings structs in SkSL
* that are used by the shaders. Each attribute from the Attribute span becomes a member of the
* SkSL Attributes struct and likewise for the varyings.
*
* The signature of the vertex program must be:
* Varyings main(const Attributes).
*
* The signature of the fragment program must be either:
* float2 main(const Varyings)
* or
* float2 main(const Varyings, out (half4|float4) color)
*
* where the return value is the local coordinates that will be used to access SkShader. If the
* color variant is used, the returned color will be blended with SkPaint's SkShader (or SkPaint
* color in absence of a SkShader) using the SkBlender passed to SkCanvas drawMesh(). To use
* interpolated local space positions as the shader coordinates, equivalent to how SkPaths are
* shaded, return the position field from the Varying struct as the coordinates.
*
* The vertex and fragment programs may both contain uniforms. Uniforms with the same name are
* assumed to be shared between stages. It is an error to specify uniforms in the vertex and
* fragment program with the same name but different types, dimensionality, or layouts.
*/
class SK_API SkMeshSpecification : public SkNVRefCnt<SkMeshSpecification> {
public:
/** These values are enforced when creating a specification. */
static constexpr size_t kMaxStride = 1024;
static constexpr size_t kMaxAttributes = 8;
static constexpr size_t kStrideAlignment = 4;
static constexpr size_t kOffsetAlignment = 4;
static constexpr size_t kMaxVaryings = 6;
struct Attribute {
enum class Type : uint32_t { // CPU representation Shader Type
kFloat, // float float
kFloat2, // two floats float2
kFloat3, // three floats float3
kFloat4, // four floats float4
kUByte4_unorm, // four bytes half4
kLast = kUByte4_unorm
};
Type type;
size_t offset;
SkString name;
};
struct Varying {
enum class Type : uint32_t {
kFloat, // "float"
kFloat2, // "float2"
kFloat3, // "float3"
kFloat4, // "float4"
kHalf, // "half"
kHalf2, // "half2"
kHalf3, // "half3"
kHalf4, // "half4"
kLast = kHalf4
};
Type type;
SkString name;
};
using Uniform = SkRuntimeEffect::Uniform;
using Child = SkRuntimeEffect::Child;
~SkMeshSpecification();
struct Result {
sk_sp<SkMeshSpecification> specification;
SkString error;
};
/**
* If successful the return is a specification and an empty error string. Otherwise, it is a
* null specification a non-empty error string.
*
* @param attributes The vertex attributes that will be consumed by 'vs'. Attributes need
* not be tightly packed but attribute offsets must be aligned to
* kOffsetAlignment and offset + size may not be greater than
* 'vertexStride'. At least one attribute is required.
* @param vertexStride The offset between successive attribute values. This must be aligned to
* kStrideAlignment.
* @param varyings The varyings that will be written by 'vs' and read by 'fs'. This may
* be empty.
* @param vs The vertex shader code that computes a vertex position and the varyings
* from the attributes.
* @param fs The fragment code that computes a local coordinate and optionally a
* color from the varyings. The local coordinate is used to sample
* SkShader.
* @param cs The colorspace of the color produced by 'fs'. Ignored if 'fs's main()
* function does not have a color out param.
* @param at The alpha type of the color produced by 'fs'. Ignored if 'fs's main()
* function does not have a color out param. Cannot be kUnknown.
*/
static Result Make(SkSpan<const Attribute> attributes,
size_t vertexStride,
SkSpan<const Varying> varyings,
const SkString& vs,
const SkString& fs);
static Result Make(SkSpan<const Attribute> attributes,
size_t vertexStride,
SkSpan<const Varying> varyings,
const SkString& vs,
const SkString& fs,
sk_sp<SkColorSpace> cs);
static Result Make(SkSpan<const Attribute> attributes,
size_t vertexStride,
SkSpan<const Varying> varyings,
const SkString& vs,
const SkString& fs,
sk_sp<SkColorSpace> cs,
SkAlphaType at);
SkSpan<const Attribute> attributes() const { return SkSpan(fAttributes); }
/**
* Combined size of all 'uniform' variables. When creating a SkMesh with this specification
* provide an SkData of this size, containing values for all of those variables. Use uniforms()
* to get the offset of each uniform within the SkData.
*/
size_t uniformSize() const;
/**
* Provides info about individual uniforms including the offset into an SkData where each
* uniform value should be placed.
*/
SkSpan<const Uniform> uniforms() const { return SkSpan(fUniforms); }
/** Provides basic info about individual children: names, indices and runtime effect type. */
SkSpan<const Child> children() const { return SkSpan(fChildren); }
/** Returns a pointer to the named child's description, or nullptr if not found. */
const Child* findChild(std::string_view name) const;
/** Returns a pointer to the named uniform variable's description, or nullptr if not found. */
const Uniform* findUniform(std::string_view name) const;
/** Returns a pointer to the named attribute, or nullptr if not found. */
const Attribute* findAttribute(std::string_view name) const;
/** Returns a pointer to the named varying, or nullptr if not found. */
const Varying* findVarying(std::string_view name) const;
size_t stride() const { return fStride; }
SkColorSpace* colorSpace() const { return fColorSpace.get(); }
private:
friend struct SkMeshSpecificationPriv;
enum class ColorType {
kNone,
kHalf4,
kFloat4,
};
static Result MakeFromSourceWithStructs(SkSpan<const Attribute> attributes,
size_t stride,
SkSpan<const Varying> varyings,
const SkString& vs,
const SkString& fs,
sk_sp<SkColorSpace> cs,
SkAlphaType at);
SkMeshSpecification(SkSpan<const Attribute>,
size_t,
SkSpan<const Varying>,
int passthroughLocalCoordsVaryingIndex,
uint32_t deadVaryingMask,
std::vector<Uniform> uniforms,
std::vector<Child> children,
std::unique_ptr<const SkSL::Program>,
std::unique_ptr<const SkSL::Program>,
ColorType,
sk_sp<SkColorSpace>,
SkAlphaType);
SkMeshSpecification(const SkMeshSpecification&) = delete;
SkMeshSpecification(SkMeshSpecification&&) = delete;
SkMeshSpecification& operator=(const SkMeshSpecification&) = delete;
SkMeshSpecification& operator=(SkMeshSpecification&&) = delete;
const std::vector<Attribute> fAttributes;
const std::vector<Varying> fVaryings;
const std::vector<Uniform> fUniforms;
const std::vector<Child> fChildren;
const std::unique_ptr<const SkSL::Program> fVS;
const std::unique_ptr<const SkSL::Program> fFS;
const size_t fStride;
uint32_t fHash;
const int fPassthroughLocalCoordsVaryingIndex;
const uint32_t fDeadVaryingMask;
const ColorType fColorType;
const sk_sp<SkColorSpace> fColorSpace;
const SkAlphaType fAlphaType;
};
/**
* A vertex buffer, a topology, optionally an index buffer, and a compatible SkMeshSpecification.
*
* The data in the vertex buffer is expected to contain the attributes described by the spec
* for vertexCount vertices, beginning at vertexOffset. vertexOffset must be aligned to the
* SkMeshSpecification's vertex stride. The size of the buffer must be at least vertexOffset +
* spec->stride()*vertexCount (even if vertex attributes contains pad at the end of the stride). If
* the specified bounds do not contain all the points output by the spec's vertex program when
* applied to the vertices in the custom mesh, then the result is undefined.
*
* MakeIndexed may be used to create an indexed mesh. indexCount indices are read from the index
* buffer at the specified offset, which must be aligned to 2. The indices are always unsigned
* 16-bit integers. The index count must be at least 3.
*
* If Make() is used, the implicit index sequence is 0, 1, 2, 3, ... and vertexCount must be at
* least 3.
*
* Both Make() and MakeIndexed() take a SkData with the uniform values. See
* SkMeshSpecification::uniformSize() and SkMeshSpecification::uniforms() for sizing and packing
* uniforms into the SkData.
*/
class SK_API SkMesh {
public:
class IndexBuffer : public SkRefCnt {
public:
virtual size_t size() const = 0;
/**
* Modifies the data in the IndexBuffer by copying size bytes from data into the buffer
* at offset. Fails if offset + size > this->size() or if either offset or size is not
* aligned to 4 bytes. The GrDirectContext* must match that used to create the buffer. We
* take it as a parameter to emphasize that the context must be used to update the data and
* thus the context must be valid for the current thread.
*/
bool update(GrDirectContext*, const void* data, size_t offset, size_t size);
private:
virtual bool onUpdate(GrDirectContext*, const void* data, size_t offset, size_t size) = 0;
};
class VertexBuffer : public SkRefCnt {
public:
virtual size_t size() const = 0;
/**
* Modifies the data in the IndexBuffer by copying size bytes from data into the buffer
* at offset. Fails if offset + size > this->size() or if either offset or size is not
* aligned to 4 bytes. The GrDirectContext* must match that used to create the buffer. We
* take it as a parameter to emphasize that the context must be used to update the data and
* thus the context must be valid for the current thread.
*/
bool update(GrDirectContext*, const void* data, size_t offset, size_t size);
private:
virtual bool onUpdate(GrDirectContext*, const void* data, size_t offset, size_t size) = 0;
};
SkMesh();
~SkMesh();
SkMesh(const SkMesh&);
SkMesh(SkMesh&&);
SkMesh& operator=(const SkMesh&);
SkMesh& operator=(SkMesh&&);
enum class Mode { kTriangles, kTriangleStrip };
struct Result;
using ChildPtr = SkRuntimeEffect::ChildPtr;
/**
* Creates a non-indexed SkMesh. The returned SkMesh can be tested for validity using
* SkMesh::isValid(). An invalid mesh simply fails to draws if passed to SkCanvas::drawMesh().
* If the mesh is invalid the returned string give contain the reason for the failure (e.g. the
* vertex buffer was null or uniform data too small).
*/
static Result Make(sk_sp<SkMeshSpecification>,
Mode,
sk_sp<VertexBuffer>,
size_t vertexCount,
size_t vertexOffset,
sk_sp<const SkData> uniforms,
SkSpan<ChildPtr> children,
const SkRect& bounds);
/**
* Creates an indexed SkMesh. The returned SkMesh can be tested for validity using
* SkMesh::isValid(). A invalid mesh simply fails to draw if passed to SkCanvas::drawMesh().
* If the mesh is invalid the returned string give contain the reason for the failure (e.g. the
* index buffer was null or uniform data too small).
*/
static Result MakeIndexed(sk_sp<SkMeshSpecification>,
Mode,
sk_sp<VertexBuffer>,
size_t vertexCount,
size_t vertexOffset,
sk_sp<IndexBuffer>,
size_t indexCount,
size_t indexOffset,
sk_sp<const SkData> uniforms,
SkSpan<ChildPtr> children,
const SkRect& bounds);
sk_sp<SkMeshSpecification> refSpec() const { return fSpec; }
SkMeshSpecification* spec() const { return fSpec.get(); }
Mode mode() const { return fMode; }
sk_sp<VertexBuffer> refVertexBuffer() const { return fVB; }
VertexBuffer* vertexBuffer() const { return fVB.get(); }
size_t vertexOffset() const { return fVOffset; }
size_t vertexCount() const { return fVCount; }
sk_sp<IndexBuffer> refIndexBuffer() const { return fIB; }
IndexBuffer* indexBuffer() const { return fIB.get(); }
size_t indexOffset() const { return fIOffset; }
size_t indexCount() const { return fICount; }
sk_sp<const SkData> refUniforms() const { return fUniforms; }
const SkData* uniforms() const { return fUniforms.get(); }
SkSpan<const ChildPtr> children() const { return SkSpan(fChildren); }
SkRect bounds() const { return fBounds; }
bool isValid() const;
private:
std::tuple<bool, SkString> validate() const;
sk_sp<SkMeshSpecification> fSpec;
sk_sp<VertexBuffer> fVB;
sk_sp<IndexBuffer> fIB;
sk_sp<const SkData> fUniforms;
skia_private::STArray<2, ChildPtr> fChildren;
size_t fVOffset = 0; // Must be a multiple of spec->stride()
size_t fVCount = 0;
size_t fIOffset = 0; // Must be a multiple of sizeof(uint16_t)
size_t fICount = 0;
Mode fMode = Mode::kTriangles;
SkRect fBounds = SkRect::MakeEmpty();
};
struct SkMesh::Result { SkMesh mesh; SkString error; };
namespace SkMeshes {
/**
* Makes a CPU-backed index buffer to be used with SkMeshes.
*
* @param data The data used to populate the buffer, or nullptr to create a zero-
* initialized buffer.
* @param size Both the size of the data in 'data' and the size of the resulting
* buffer, in bytes.
*/
SK_API sk_sp<SkMesh::IndexBuffer> MakeIndexBuffer(const void* data, size_t size);
/**
* Makes a copy of an index buffer. The copy will be CPU-backed.
*/
SK_API sk_sp<SkMesh::IndexBuffer> CopyIndexBuffer(const sk_sp<SkMesh::IndexBuffer>&);
/**
* Makes a CPU-backed vertex buffer to be used with SkMeshes.
*
* @param data The data used to populate the buffer, or nullptr to create a zero-
* initialized buffer.
* @param size Both the size of the data in 'data' and the size of the resulting
* buffer, in bytes.
*/
SK_API sk_sp<SkMesh::VertexBuffer> MakeVertexBuffer(const void*, size_t size);
/**
* Makes a copy of a vertex buffer. The copy will be CPU-backed.
*/
SK_API sk_sp<SkMesh::VertexBuffer> CopyVertexBuffer(const sk_sp<SkMesh::VertexBuffer>&);
} // namespace SkMeshes
#endif

View File

@ -0,0 +1,9 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SK_MILESTONE
#define SK_MILESTONE 127
#endif

View File

@ -0,0 +1,30 @@
/*
* Copyright 2022 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkOpenTypeSVGDecoder_DEFINED
#define SkOpenTypeSVGDecoder_DEFINED
#include "include/core/SkColor.h"
#include "include/core/SkSpan.h"
#include "include/core/SkTypes.h"
#include <memory>
class SkCanvas;
class SkOpenTypeSVGDecoder {
public:
/** Each instance probably owns an SVG DOM.
* The instance may be cached so needs to report how much memory it retains.
*/
virtual size_t approximateSize() = 0;
virtual bool render(SkCanvas&, int upem, SkGlyphID glyphId,
SkColor foregroundColor, SkSpan<SkColor> palette) = 0;
virtual ~SkOpenTypeSVGDecoder() = default;
};
#endif // SkOpenTypeSVGDecoder_DEFINED

View File

@ -0,0 +1,94 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkOverdrawCanvas_DEFINED
#define SkOverdrawCanvas_DEFINED
#include "include/core/SkCanvas.h"
#include "include/core/SkCanvasVirtualEnforcer.h"
#include "include/core/SkColor.h"
#include "include/core/SkPaint.h"
#include "include/core/SkSamplingOptions.h"
#include "include/core/SkScalar.h"
#include "include/private/base/SkAPI.h"
#include "include/utils/SkNWayCanvas.h"
#include <cstddef>
class SkData;
class SkDrawable;
class SkImage;
class SkMatrix;
class SkPath;
class SkPicture;
class SkRRect;
class SkRegion;
class SkTextBlob;
class SkVertices;
enum class SkBlendMode;
namespace sktext { class GlyphRunList; }
struct SkDrawShadowRec;
struct SkPoint;
struct SkRSXform;
struct SkRect;
/**
* Captures all drawing commands. Rather than draw the actual content, this device
* increments the alpha channel of each pixel every time it would have been touched
* by a draw call. This is useful for detecting overdraw.
*/
class SK_API SkOverdrawCanvas : public SkCanvasVirtualEnforcer<SkNWayCanvas> {
public:
/* Does not take ownership of canvas */
SkOverdrawCanvas(SkCanvas*);
void onDrawTextBlob(const SkTextBlob*, SkScalar, SkScalar, const SkPaint&) override;
void onDrawGlyphRunList(
const sktext::GlyphRunList& glyphRunList, const SkPaint& paint) override;
void onDrawPatch(const SkPoint[12], const SkColor[4], const SkPoint[4], SkBlendMode,
const SkPaint&) override;
void onDrawPaint(const SkPaint&) override;
void onDrawBehind(const SkPaint& paint) override;
void onDrawRect(const SkRect&, const SkPaint&) override;
void onDrawRegion(const SkRegion&, const SkPaint&) override;
void onDrawOval(const SkRect&, const SkPaint&) override;
void onDrawArc(const SkRect&, SkScalar, SkScalar, bool, const SkPaint&) override;
void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override;
void onDrawRRect(const SkRRect&, const SkPaint&) override;
void onDrawPoints(PointMode, size_t, const SkPoint[], const SkPaint&) override;
void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override;
void onDrawPath(const SkPath&, const SkPaint&) override;
void onDrawImage2(const SkImage*, SkScalar, SkScalar, const SkSamplingOptions&,
const SkPaint*) override;
void onDrawImageRect2(const SkImage*, const SkRect&, const SkRect&, const SkSamplingOptions&,
const SkPaint*, SrcRectConstraint) override;
void onDrawImageLattice2(const SkImage*, const Lattice&, const SkRect&, SkFilterMode,
const SkPaint*) override;
void onDrawAtlas2(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int,
SkBlendMode, const SkSamplingOptions&, const SkRect*, const SkPaint*) override;
void onDrawDrawable(SkDrawable*, const SkMatrix*) override;
void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override;
void onDrawAnnotation(const SkRect&, const char key[], SkData* value) override;
void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override;
void onDrawEdgeAAQuad(const SkRect&, const SkPoint[4], SkCanvas::QuadAAFlags, const SkColor4f&,
SkBlendMode) override;
void onDrawEdgeAAImageSet2(const ImageSetEntry[], int count, const SkPoint[], const SkMatrix[],
const SkSamplingOptions&,const SkPaint*, SrcRectConstraint) override;
private:
inline SkPaint overdrawPaint(const SkPaint& paint);
SkPaint fPaint;
using INHERITED = SkCanvasVirtualEnforcer<SkNWayCanvas>;
};
#endif

View File

@ -0,0 +1,695 @@
/*
* Copyright 2006 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkPaint_DEFINED
#define SkPaint_DEFINED
#include "include/core/SkColor.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/core/SkTypes.h"
#include "include/private/base/SkCPUTypes.h"
#include "include/private/base/SkFloatingPoint.h"
#include "include/private/base/SkTo.h"
#include "include/private/base/SkTypeTraits.h"
#include <cstdint>
#include <optional>
#include <type_traits>
class SkBlender;
class SkColorFilter;
class SkColorSpace;
class SkImageFilter;
class SkMaskFilter;
class SkPathEffect;
class SkShader;
enum class SkBlendMode;
struct SkRect;
/** \class SkPaint
SkPaint controls options applied when drawing. SkPaint collects all
options outside of the SkCanvas clip and SkCanvas matrix.
Various options apply to strokes and fills, and images.
SkPaint collects effects and filters that describe single-pass and multiple-pass
algorithms that alter the drawing geometry, color, and transparency. For instance,
SkPaint does not directly implement dashing or blur, but contains the objects that do so.
*/
class SK_API SkPaint {
public:
/** Constructs SkPaint with default values.
@return default initialized SkPaint
example: https://fiddle.skia.org/c/@Paint_empty_constructor
*/
SkPaint();
/** Constructs SkPaint with default values and the given color.
Sets alpha and RGB used when stroking and filling. The color is four floating
point values, unpremultiplied. The color values are interpreted as being in
the colorSpace. If colorSpace is nullptr, then color is assumed to be in the
sRGB color space.
@param color unpremultiplied RGBA
@param colorSpace SkColorSpace describing the encoding of color
@return SkPaint with the given color
*/
explicit SkPaint(const SkColor4f& color, SkColorSpace* colorSpace = nullptr);
/** Makes a shallow copy of SkPaint. SkPathEffect, SkShader,
SkMaskFilter, SkColorFilter, and SkImageFilter are shared
between the original paint and the copy. Objects containing SkRefCnt increment
their references by one.
The referenced objects SkPathEffect, SkShader, SkMaskFilter, SkColorFilter,
and SkImageFilter cannot be modified after they are created.
This prevents objects with SkRefCnt from being modified once SkPaint refers to them.
@param paint original to copy
@return shallow copy of paint
example: https://fiddle.skia.org/c/@Paint_copy_const_SkPaint
*/
SkPaint(const SkPaint& paint);
/** Implements a move constructor to avoid increasing the reference counts
of objects referenced by the paint.
After the call, paint is undefined, and can be safely destructed.
@param paint original to move
@return content of paint
example: https://fiddle.skia.org/c/@Paint_move_SkPaint
*/
SkPaint(SkPaint&& paint);
/** Decreases SkPaint SkRefCnt of owned objects: SkPathEffect, SkShader,
SkMaskFilter, SkColorFilter, and SkImageFilter. If the
objects containing SkRefCnt go to zero, they are deleted.
*/
~SkPaint();
/** Makes a shallow copy of SkPaint. SkPathEffect, SkShader,
SkMaskFilter, SkColorFilter, and SkImageFilter are shared
between the original paint and the copy. Objects containing SkRefCnt in the
prior destination are decreased by one, and the referenced objects are deleted if the
resulting count is zero. Objects containing SkRefCnt in the parameter paint
are increased by one. paint is unmodified.
@param paint original to copy
@return content of paint
example: https://fiddle.skia.org/c/@Paint_copy_operator
*/
SkPaint& operator=(const SkPaint& paint);
/** Moves the paint to avoid increasing the reference counts
of objects referenced by the paint parameter. Objects containing SkRefCnt in the
prior destination are decreased by one; those objects are deleted if the resulting count
is zero.
After the call, paint is undefined, and can be safely destructed.
@param paint original to move
@return content of paint
example: https://fiddle.skia.org/c/@Paint_move_operator
*/
SkPaint& operator=(SkPaint&& paint);
/** Compares a and b, and returns true if a and b are equivalent. May return false
if SkPathEffect, SkShader, SkMaskFilter, SkColorFilter,
or SkImageFilter have identical contents but different pointers.
@param a SkPaint to compare
@param b SkPaint to compare
@return true if SkPaint pair are equivalent
*/
SK_API friend bool operator==(const SkPaint& a, const SkPaint& b);
/** Compares a and b, and returns true if a and b are not equivalent. May return true
if SkPathEffect, SkShader, SkMaskFilter, SkColorFilter,
or SkImageFilter have identical contents but different pointers.
@param a SkPaint to compare
@param b SkPaint to compare
@return true if SkPaint pair are not equivalent
*/
friend bool operator!=(const SkPaint& a, const SkPaint& b) {
return !(a == b);
}
/** Sets all SkPaint contents to their initial values. This is equivalent to replacing
SkPaint with the result of SkPaint().
example: https://fiddle.skia.org/c/@Paint_reset
*/
void reset();
/** Returns true if pixels on the active edges of SkPath may be drawn with partial transparency.
@return antialiasing state
*/
bool isAntiAlias() const {
return SkToBool(fBitfields.fAntiAlias);
}
/** Requests, but does not require, that edge pixels draw opaque or with
partial transparency.
@param aa setting for antialiasing
*/
void setAntiAlias(bool aa) { fBitfields.fAntiAlias = static_cast<unsigned>(aa); }
/** Returns true if color error may be distributed to smooth color transition.
@return dithering state
*/
bool isDither() const {
return SkToBool(fBitfields.fDither);
}
/** Requests, but does not require, to distribute color error.
@param dither setting for ditering
*/
void setDither(bool dither) { fBitfields.fDither = static_cast<unsigned>(dither); }
/** \enum SkPaint::Style
Set Style to fill, stroke, or both fill and stroke geometry.
The stroke and fill
share all paint attributes; for instance, they are drawn with the same color.
Use kStrokeAndFill_Style to avoid hitting the same pixels twice with a stroke draw and
a fill draw.
*/
enum Style : uint8_t {
kFill_Style, //!< set to fill geometry
kStroke_Style, //!< set to stroke geometry
kStrokeAndFill_Style, //!< sets to stroke and fill geometry
};
/** May be used to verify that SkPaint::Style is a legal value.
*/
static constexpr int kStyleCount = kStrokeAndFill_Style + 1;
/** Returns whether the geometry is filled, stroked, or filled and stroked.
*/
Style getStyle() const { return (Style)fBitfields.fStyle; }
/** Sets whether the geometry is filled, stroked, or filled and stroked.
Has no effect if style is not a legal SkPaint::Style value.
example: https://fiddle.skia.org/c/@Paint_setStyle
example: https://fiddle.skia.org/c/@Stroke_Width
*/
void setStyle(Style style);
/**
* Set paint's style to kStroke if true, or kFill if false.
*/
void setStroke(bool);
/** Retrieves alpha and RGB, unpremultiplied, packed into 32 bits.
Use helpers SkColorGetA(), SkColorGetR(), SkColorGetG(), and SkColorGetB() to extract
a color component.
@return unpremultiplied ARGB
*/
SkColor getColor() const { return fColor4f.toSkColor(); }
/** Retrieves alpha and RGB, unpremultiplied, as four floating point values. RGB are
extended sRGB values (sRGB gamut, and encoded with the sRGB transfer function).
@return unpremultiplied RGBA
*/
SkColor4f getColor4f() const { return fColor4f; }
/** Sets alpha and RGB used when stroking and filling. The color is a 32-bit value,
unpremultiplied, packing 8-bit components for alpha, red, blue, and green.
@param color unpremultiplied ARGB
example: https://fiddle.skia.org/c/@Paint_setColor
*/
void setColor(SkColor color);
/** Sets alpha and RGB used when stroking and filling. The color is four floating
point values, unpremultiplied. The color values are interpreted as being in
the colorSpace. If colorSpace is nullptr, then color is assumed to be in the
sRGB color space.
@param color unpremultiplied RGBA
@param colorSpace SkColorSpace describing the encoding of color
*/
void setColor(const SkColor4f& color, SkColorSpace* colorSpace = nullptr);
void setColor4f(const SkColor4f& color, SkColorSpace* colorSpace = nullptr) {
this->setColor(color, colorSpace);
}
/** Retrieves alpha from the color used when stroking and filling.
@return alpha ranging from zero, fully transparent, to one, fully opaque
*/
float getAlphaf() const { return fColor4f.fA; }
// Helper that scales the alpha by 255.
uint8_t getAlpha() const {
return static_cast<uint8_t>(sk_float_round2int(this->getAlphaf() * 255));
}
/** Replaces alpha, leaving RGB
unchanged. An out of range value triggers an assert in the debug
build. a is a value from 0.0 to 1.0.
a set to zero makes color fully transparent; a set to 1.0 makes color
fully opaque.
@param a alpha component of color
*/
void setAlphaf(float a);
// Helper that accepts an int between 0 and 255, and divides it by 255.0
void setAlpha(U8CPU a) {
this->setAlphaf(a * (1.0f / 255));
}
/** Sets color used when drawing solid fills. The color components range from 0 to 255.
The color is unpremultiplied; alpha sets the transparency independent of RGB.
@param a amount of alpha, from fully transparent (0) to fully opaque (255)
@param r amount of red, from no red (0) to full red (255)
@param g amount of green, from no green (0) to full green (255)
@param b amount of blue, from no blue (0) to full blue (255)
example: https://fiddle.skia.org/c/@Paint_setARGB
*/
void setARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
/** Returns the thickness of the pen used by SkPaint to
outline the shape.
@return zero for hairline, greater than zero for pen thickness
*/
SkScalar getStrokeWidth() const { return fWidth; }
/** Sets the thickness of the pen used by the paint to outline the shape.
A stroke-width of zero is treated as "hairline" width. Hairlines are always exactly one
pixel wide in device space (their thickness does not change as the canvas is scaled).
Negative stroke-widths are invalid; setting a negative width will have no effect.
@param width zero thickness for hairline; greater than zero for pen thickness
example: https://fiddle.skia.org/c/@Miter_Limit
example: https://fiddle.skia.org/c/@Paint_setStrokeWidth
*/
void setStrokeWidth(SkScalar width);
/** Returns the limit at which a sharp corner is drawn beveled.
@return zero and greater miter limit
*/
SkScalar getStrokeMiter() const { return fMiterLimit; }
/** Sets the limit at which a sharp corner is drawn beveled.
Valid values are zero and greater.
Has no effect if miter is less than zero.
@param miter zero and greater miter limit
example: https://fiddle.skia.org/c/@Paint_setStrokeMiter
*/
void setStrokeMiter(SkScalar miter);
/** \enum SkPaint::Cap
Cap draws at the beginning and end of an open path contour.
*/
enum Cap {
kButt_Cap, //!< no stroke extension
kRound_Cap, //!< adds circle
kSquare_Cap, //!< adds square
kLast_Cap = kSquare_Cap, //!< largest Cap value
kDefault_Cap = kButt_Cap, //!< equivalent to kButt_Cap
};
/** May be used to verify that SkPaint::Cap is a legal value.
*/
static constexpr int kCapCount = kLast_Cap + 1;
/** \enum SkPaint::Join
Join specifies how corners are drawn when a shape is stroked. Join
affects the four corners of a stroked rectangle, and the connected segments in a
stroked path.
Choose miter join to draw sharp corners. Choose round join to draw a circle with a
radius equal to the stroke width on top of the corner. Choose bevel join to minimally
connect the thick strokes.
The fill path constructed to describe the stroked path respects the join setting but may
not contain the actual join. For instance, a fill path constructed with round joins does
not necessarily include circles at each connected segment.
*/
enum Join : uint8_t {
kMiter_Join, //!< extends to miter limit
kRound_Join, //!< adds circle
kBevel_Join, //!< connects outside edges
kLast_Join = kBevel_Join, //!< equivalent to the largest value for Join
kDefault_Join = kMiter_Join, //!< equivalent to kMiter_Join
};
/** May be used to verify that SkPaint::Join is a legal value.
*/
static constexpr int kJoinCount = kLast_Join + 1;
/** Returns the geometry drawn at the beginning and end of strokes.
*/
Cap getStrokeCap() const { return (Cap)fBitfields.fCapType; }
/** Sets the geometry drawn at the beginning and end of strokes.
example: https://fiddle.skia.org/c/@Paint_setStrokeCap_a
example: https://fiddle.skia.org/c/@Paint_setStrokeCap_b
*/
void setStrokeCap(Cap cap);
/** Returns the geometry drawn at the corners of strokes.
*/
Join getStrokeJoin() const { return (Join)fBitfields.fJoinType; }
/** Sets the geometry drawn at the corners of strokes.
example: https://fiddle.skia.org/c/@Paint_setStrokeJoin
*/
void setStrokeJoin(Join join);
/** Returns optional colors used when filling a path, such as a gradient.
Does not alter SkShader SkRefCnt.
@return SkShader if previously set, nullptr otherwise
*/
SkShader* getShader() const { return fShader.get(); }
/** Returns optional colors used when filling a path, such as a gradient.
Increases SkShader SkRefCnt by one.
@return SkShader if previously set, nullptr otherwise
example: https://fiddle.skia.org/c/@Paint_refShader
*/
sk_sp<SkShader> refShader() const;
/** Sets optional colors used when filling a path, such as a gradient.
Sets SkShader to shader, decreasing SkRefCnt of the previous SkShader.
Increments shader SkRefCnt by one.
@param shader how geometry is filled with color; if nullptr, color is used instead
example: https://fiddle.skia.org/c/@Color_Filter_Methods
example: https://fiddle.skia.org/c/@Paint_setShader
*/
void setShader(sk_sp<SkShader> shader);
/** Returns SkColorFilter if set, or nullptr.
Does not alter SkColorFilter SkRefCnt.
@return SkColorFilter if previously set, nullptr otherwise
*/
SkColorFilter* getColorFilter() const { return fColorFilter.get(); }
/** Returns SkColorFilter if set, or nullptr.
Increases SkColorFilter SkRefCnt by one.
@return SkColorFilter if set, or nullptr
example: https://fiddle.skia.org/c/@Paint_refColorFilter
*/
sk_sp<SkColorFilter> refColorFilter() const;
/** Sets SkColorFilter to filter, decreasing SkRefCnt of the previous
SkColorFilter. Pass nullptr to clear SkColorFilter.
Increments filter SkRefCnt by one.
@param colorFilter SkColorFilter to apply to subsequent draw
example: https://fiddle.skia.org/c/@Blend_Mode_Methods
example: https://fiddle.skia.org/c/@Paint_setColorFilter
*/
void setColorFilter(sk_sp<SkColorFilter> colorFilter);
/** If the current blender can be represented as a SkBlendMode enum, this returns that
* enum in the optional's value(). If it cannot, then the returned optional does not
* contain a value.
*/
std::optional<SkBlendMode> asBlendMode() const;
/**
* Queries the blender, and if it can be represented as a SkBlendMode, return that mode,
* else return the defaultMode provided.
*/
SkBlendMode getBlendMode_or(SkBlendMode defaultMode) const;
/** Returns true iff the current blender claims to be equivalent to SkBlendMode::kSrcOver.
*
* Also returns true of the current blender is nullptr.
*/
bool isSrcOver() const;
/** Helper method for calling setBlender().
*
* This sets a blender that implements the specified blendmode enum.
*/
void setBlendMode(SkBlendMode mode);
/** Returns the user-supplied blend function, if one has been set.
* Does not alter SkBlender's SkRefCnt.
*
* A nullptr blender signifies the default SrcOver behavior.
*
* @return the SkBlender assigned to this paint, otherwise nullptr
*/
SkBlender* getBlender() const { return fBlender.get(); }
/** Returns the user-supplied blend function, if one has been set.
* Increments the SkBlender's SkRefCnt by one.
*
* A nullptr blender signifies the default SrcOver behavior.
*
* @return the SkBlender assigned to this paint, otherwise nullptr
*/
sk_sp<SkBlender> refBlender() const;
/** Sets the current blender, increasing its refcnt, and if a blender is already
* present, decreasing that object's refcnt.
*
* A nullptr blender signifies the default SrcOver behavior.
*
* For convenience, you can call setBlendMode() if the blend effect can be expressed
* as one of those values.
*/
void setBlender(sk_sp<SkBlender> blender);
/** Returns SkPathEffect if set, or nullptr.
Does not alter SkPathEffect SkRefCnt.
@return SkPathEffect if previously set, nullptr otherwise
*/
SkPathEffect* getPathEffect() const { return fPathEffect.get(); }
/** Returns SkPathEffect if set, or nullptr.
Increases SkPathEffect SkRefCnt by one.
@return SkPathEffect if previously set, nullptr otherwise
example: https://fiddle.skia.org/c/@Paint_refPathEffect
*/
sk_sp<SkPathEffect> refPathEffect() const;
/** Sets SkPathEffect to pathEffect, decreasing SkRefCnt of the previous
SkPathEffect. Pass nullptr to leave the path geometry unaltered.
Increments pathEffect SkRefCnt by one.
@param pathEffect replace SkPath with a modification when drawn
example: https://fiddle.skia.org/c/@Mask_Filter_Methods
example: https://fiddle.skia.org/c/@Paint_setPathEffect
*/
void setPathEffect(sk_sp<SkPathEffect> pathEffect);
/** Returns SkMaskFilter if set, or nullptr.
Does not alter SkMaskFilter SkRefCnt.
@return SkMaskFilter if previously set, nullptr otherwise
*/
SkMaskFilter* getMaskFilter() const { return fMaskFilter.get(); }
/** Returns SkMaskFilter if set, or nullptr.
Increases SkMaskFilter SkRefCnt by one.
@return SkMaskFilter if previously set, nullptr otherwise
example: https://fiddle.skia.org/c/@Paint_refMaskFilter
*/
sk_sp<SkMaskFilter> refMaskFilter() const;
/** Sets SkMaskFilter to maskFilter, decreasing SkRefCnt of the previous
SkMaskFilter. Pass nullptr to clear SkMaskFilter and leave SkMaskFilter effect on
mask alpha unaltered.
Increments maskFilter SkRefCnt by one.
@param maskFilter modifies clipping mask generated from drawn geometry
example: https://fiddle.skia.org/c/@Paint_setMaskFilter
example: https://fiddle.skia.org/c/@Typeface_Methods
*/
void setMaskFilter(sk_sp<SkMaskFilter> maskFilter);
/** Returns SkImageFilter if set, or nullptr.
Does not alter SkImageFilter SkRefCnt.
@return SkImageFilter if previously set, nullptr otherwise
*/
SkImageFilter* getImageFilter() const { return fImageFilter.get(); }
/** Returns SkImageFilter if set, or nullptr.
Increases SkImageFilter SkRefCnt by one.
@return SkImageFilter if previously set, nullptr otherwise
example: https://fiddle.skia.org/c/@Paint_refImageFilter
*/
sk_sp<SkImageFilter> refImageFilter() const;
/** Sets SkImageFilter to imageFilter, decreasing SkRefCnt of the previous
SkImageFilter. Pass nullptr to clear SkImageFilter, and remove SkImageFilter effect
on drawing.
Increments imageFilter SkRefCnt by one.
@param imageFilter how SkImage is sampled when transformed
example: https://fiddle.skia.org/c/@Paint_setImageFilter
*/
void setImageFilter(sk_sp<SkImageFilter> imageFilter);
/** Returns true if SkPaint prevents all drawing;
otherwise, the SkPaint may or may not allow drawing.
Returns true if, for example, SkBlendMode combined with alpha computes a
new alpha of zero.
@return true if SkPaint prevents all drawing
example: https://fiddle.skia.org/c/@Paint_nothingToDraw
*/
bool nothingToDraw() const;
/** (to be made private)
Returns true if SkPaint does not include elements requiring extensive computation
to compute device bounds of drawn geometry. For instance, SkPaint with SkPathEffect
always returns false.
@return true if SkPaint allows for fast computation of bounds
*/
bool canComputeFastBounds() const;
/** (to be made private)
Only call this if canComputeFastBounds() returned true. This takes a
raw rectangle (the raw bounds of a shape), and adjusts it for stylistic
effects in the paint (e.g. stroking). If needed, it uses the storage
parameter. It returns the adjusted bounds that can then be used
for SkCanvas::quickReject tests.
The returned SkRect will either be orig or storage, thus the caller
should not rely on storage being set to the result, but should always
use the returned value. It is legal for orig and storage to be the same
SkRect.
For example:
if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
SkRect storage;
if (canvas->quickReject(paint.computeFastBounds(path.getBounds(), &storage))) {
return; // do not draw the path
}
}
// draw the path
@param orig geometry modified by SkPaint when drawn
@param storage computed bounds of geometry; may not be nullptr
@return fast computed bounds
*/
const SkRect& computeFastBounds(const SkRect& orig, SkRect* storage) const;
/** (to be made private)
@param orig geometry modified by SkPaint when drawn
@param storage computed bounds of geometry
@return fast computed bounds
*/
const SkRect& computeFastStrokeBounds(const SkRect& orig,
SkRect* storage) const {
return this->doComputeFastBounds(orig, storage, kStroke_Style);
}
/** (to be made private)
Computes the bounds, overriding the SkPaint SkPaint::Style. This can be used to
account for additional width required by stroking orig, without
altering SkPaint::Style set to fill.
@param orig geometry modified by SkPaint when drawn
@param storage computed bounds of geometry
@param style overrides SkPaint::Style
@return fast computed bounds
*/
const SkRect& doComputeFastBounds(const SkRect& orig, SkRect* storage,
Style style) const;
using sk_is_trivially_relocatable = std::true_type;
private:
sk_sp<SkPathEffect> fPathEffect;
sk_sp<SkShader> fShader;
sk_sp<SkMaskFilter> fMaskFilter;
sk_sp<SkColorFilter> fColorFilter;
sk_sp<SkImageFilter> fImageFilter;
sk_sp<SkBlender> fBlender;
SkColor4f fColor4f;
SkScalar fWidth;
SkScalar fMiterLimit;
union {
struct {
unsigned fAntiAlias : 1;
unsigned fDither : 1;
unsigned fCapType : 2;
unsigned fJoinType : 2;
unsigned fStyle : 2;
unsigned fPadding : 24; // 24 == 32 -1-1-2-2-2
} fBitfields;
uint32_t fBitfieldsUInt;
};
static_assert(::sk_is_trivially_relocatable<decltype(fPathEffect)>::value);
static_assert(::sk_is_trivially_relocatable<decltype(fShader)>::value);
static_assert(::sk_is_trivially_relocatable<decltype(fMaskFilter)>::value);
static_assert(::sk_is_trivially_relocatable<decltype(fColorFilter)>::value);
static_assert(::sk_is_trivially_relocatable<decltype(fImageFilter)>::value);
static_assert(::sk_is_trivially_relocatable<decltype(fBlender)>::value);
static_assert(::sk_is_trivially_relocatable<decltype(fColor4f)>::value);
static_assert(::sk_is_trivially_relocatable<decltype(fBitfields)>::value);
friend class SkPaintPriv;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,271 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkPathBuilder_DEFINED
#define SkPathBuilder_DEFINED
#include "include/core/SkPath.h"
#include "include/core/SkPathTypes.h"
#include "include/core/SkPoint.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/core/SkTypes.h"
#include "include/private/SkPathRef.h"
#include "include/private/base/SkTo.h"
#include <initializer_list>
class SkRRect;
class SK_API SkPathBuilder {
public:
SkPathBuilder();
SkPathBuilder(SkPathFillType);
SkPathBuilder(const SkPath&);
SkPathBuilder(const SkPathBuilder&) = default;
~SkPathBuilder();
SkPathBuilder& operator=(const SkPath&);
SkPathBuilder& operator=(const SkPathBuilder&) = default;
SkPathFillType fillType() const { return fFillType; }
SkRect computeBounds() const;
SkPath snapshot() const; // the builder is unchanged after returning this path
SkPath detach(); // the builder is reset to empty after returning this path
SkPathBuilder& setFillType(SkPathFillType ft) { fFillType = ft; return *this; }
SkPathBuilder& setIsVolatile(bool isVolatile) { fIsVolatile = isVolatile; return *this; }
SkPathBuilder& reset();
SkPathBuilder& moveTo(SkPoint pt);
SkPathBuilder& moveTo(SkScalar x, SkScalar y) { return this->moveTo(SkPoint::Make(x, y)); }
SkPathBuilder& lineTo(SkPoint pt);
SkPathBuilder& lineTo(SkScalar x, SkScalar y) { return this->lineTo(SkPoint::Make(x, y)); }
SkPathBuilder& quadTo(SkPoint pt1, SkPoint pt2);
SkPathBuilder& quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
return this->quadTo(SkPoint::Make(x1, y1), SkPoint::Make(x2, y2));
}
SkPathBuilder& quadTo(const SkPoint pts[2]) { return this->quadTo(pts[0], pts[1]); }
SkPathBuilder& conicTo(SkPoint pt1, SkPoint pt2, SkScalar w);
SkPathBuilder& conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar w) {
return this->conicTo(SkPoint::Make(x1, y1), SkPoint::Make(x2, y2), w);
}
SkPathBuilder& conicTo(const SkPoint pts[2], SkScalar w) {
return this->conicTo(pts[0], pts[1], w);
}
SkPathBuilder& cubicTo(SkPoint pt1, SkPoint pt2, SkPoint pt3);
SkPathBuilder& cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar x3, SkScalar y3) {
return this->cubicTo(SkPoint::Make(x1, y1), SkPoint::Make(x2, y2), SkPoint::Make(x3, y3));
}
SkPathBuilder& cubicTo(const SkPoint pts[3]) {
return this->cubicTo(pts[0], pts[1], pts[2]);
}
SkPathBuilder& close();
// Append a series of lineTo(...)
SkPathBuilder& polylineTo(const SkPoint pts[], int count);
SkPathBuilder& polylineTo(const std::initializer_list<SkPoint>& list) {
return this->polylineTo(list.begin(), SkToInt(list.size()));
}
// Relative versions of segments, relative to the previous position.
SkPathBuilder& rLineTo(SkPoint pt);
SkPathBuilder& rLineTo(SkScalar x, SkScalar y) { return this->rLineTo({x, y}); }
SkPathBuilder& rQuadTo(SkPoint pt1, SkPoint pt2);
SkPathBuilder& rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
return this->rQuadTo({x1, y1}, {x2, y2});
}
SkPathBuilder& rConicTo(SkPoint p1, SkPoint p2, SkScalar w);
SkPathBuilder& rConicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar w) {
return this->rConicTo({x1, y1}, {x2, y2}, w);
}
SkPathBuilder& rCubicTo(SkPoint pt1, SkPoint pt2, SkPoint pt3);
SkPathBuilder& rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar x3, SkScalar y3) {
return this->rCubicTo({x1, y1}, {x2, y2}, {x3, y3});
}
// Arcs
/** Appends arc to the builder. Arc added is part of ellipse
bounded by oval, from startAngle through sweepAngle. Both startAngle and
sweepAngle are measured in degrees, where zero degrees is aligned with the
positive x-axis, and positive sweeps extends arc clockwise.
arcTo() adds line connecting the builder's last point to initial arc point if forceMoveTo
is false and the builder is not empty. Otherwise, added contour begins with first point
of arc. Angles greater than -360 and less than 360 are treated modulo 360.
@param oval bounds of ellipse containing arc
@param startAngleDeg starting angle of arc in degrees
@param sweepAngleDeg sweep, in degrees. Positive is clockwise; treated modulo 360
@param forceMoveTo true to start a new contour with arc
@return reference to the builder
*/
SkPathBuilder& arcTo(const SkRect& oval, SkScalar startAngleDeg, SkScalar sweepAngleDeg,
bool forceMoveTo);
/** Appends arc to SkPath, after appending line if needed. Arc is implemented by conic
weighted to describe part of circle. Arc is contained by tangent from
last SkPath point to p1, and tangent from p1 to p2. Arc
is part of circle sized to radius, positioned so it touches both tangent lines.
If last SkPath SkPoint does not start arc, arcTo() appends connecting line to SkPath.
The length of vector from p1 to p2 does not affect arc.
Arc sweep is always less than 180 degrees. If radius is zero, or if
tangents are nearly parallel, arcTo() appends line from last SkPath SkPoint to p1.
arcTo() appends at most one line and one conic.
arcTo() implements the functionality of PostScript arct and HTML Canvas arcTo.
@param p1 SkPoint common to pair of tangents
@param p2 end of second tangent
@param radius distance from arc to circle center
@return reference to SkPath
*/
SkPathBuilder& arcTo(SkPoint p1, SkPoint p2, SkScalar radius);
enum ArcSize {
kSmall_ArcSize, //!< smaller of arc pair
kLarge_ArcSize, //!< larger of arc pair
};
/** Appends arc to SkPath. Arc is implemented by one or more conic weighted to describe
part of oval with radii (r.fX, r.fY) rotated by xAxisRotate degrees. Arc curves
from last SkPath SkPoint to (xy.fX, xy.fY), choosing one of four possible routes:
clockwise or counterclockwise,
and smaller or larger.
Arc sweep is always less than 360 degrees. arcTo() appends line to xy if either
radii are zero, or if last SkPath SkPoint equals (xy.fX, xy.fY). arcTo() scales radii r to
fit last SkPath SkPoint and xy if both are greater than zero but too small to describe
an arc.
arcTo() appends up to four conic curves.
arcTo() implements the functionality of SVG arc, although SVG sweep-flag value is
opposite the integer value of sweep; SVG sweep-flag uses 1 for clockwise, while
kCW_Direction cast to int is zero.
@param r radii on axes before x-axis rotation
@param xAxisRotate x-axis rotation in degrees; positive values are clockwise
@param largeArc chooses smaller or larger arc
@param sweep chooses clockwise or counterclockwise arc
@param xy end of arc
@return reference to SkPath
*/
SkPathBuilder& arcTo(SkPoint r, SkScalar xAxisRotate, ArcSize largeArc, SkPathDirection sweep,
SkPoint xy);
/** Appends arc to the builder, as the start of new contour. Arc added is part of ellipse
bounded by oval, from startAngle through sweepAngle. Both startAngle and
sweepAngle are measured in degrees, where zero degrees is aligned with the
positive x-axis, and positive sweeps extends arc clockwise.
If sweepAngle <= -360, or sweepAngle >= 360; and startAngle modulo 90 is nearly
zero, append oval instead of arc. Otherwise, sweepAngle values are treated
modulo 360, and arc may or may not draw depending on numeric rounding.
@param oval bounds of ellipse containing arc
@param startAngleDeg starting angle of arc in degrees
@param sweepAngleDeg sweep, in degrees. Positive is clockwise; treated modulo 360
@return reference to this builder
*/
SkPathBuilder& addArc(const SkRect& oval, SkScalar startAngleDeg, SkScalar sweepAngleDeg);
// Add a new contour
SkPathBuilder& addRect(const SkRect&, SkPathDirection, unsigned startIndex);
SkPathBuilder& addOval(const SkRect&, SkPathDirection, unsigned startIndex);
SkPathBuilder& addRRect(const SkRRect&, SkPathDirection, unsigned startIndex);
SkPathBuilder& addRect(const SkRect& rect, SkPathDirection dir = SkPathDirection::kCW) {
return this->addRect(rect, dir, 0);
}
SkPathBuilder& addOval(const SkRect& rect, SkPathDirection dir = SkPathDirection::kCW) {
// legacy start index: 1
return this->addOval(rect, dir, 1);
}
SkPathBuilder& addRRect(const SkRRect& rrect, SkPathDirection dir = SkPathDirection::kCW) {
// legacy start indices: 6 (CW) and 7 (CCW)
return this->addRRect(rrect, dir, dir == SkPathDirection::kCW ? 6 : 7);
}
SkPathBuilder& addCircle(SkScalar center_x, SkScalar center_y, SkScalar radius,
SkPathDirection dir = SkPathDirection::kCW);
SkPathBuilder& addPolygon(const SkPoint pts[], int count, bool isClosed);
SkPathBuilder& addPolygon(const std::initializer_list<SkPoint>& list, bool isClosed) {
return this->addPolygon(list.begin(), SkToInt(list.size()), isClosed);
}
SkPathBuilder& addPath(const SkPath&);
// Performance hint, to reserve extra storage for subsequent calls to lineTo, quadTo, etc.
void incReserve(int extraPtCount, int extraVerbCount);
void incReserve(int extraPtCount) {
this->incReserve(extraPtCount, extraPtCount);
}
SkPathBuilder& offset(SkScalar dx, SkScalar dy);
SkPathBuilder& toggleInverseFillType() {
fFillType = (SkPathFillType)((unsigned)fFillType ^ 2);
return *this;
}
private:
SkPathRef::PointsArray fPts;
SkPathRef::VerbsArray fVerbs;
SkPathRef::ConicWeightsArray fConicWeights;
SkPathFillType fFillType;
bool fIsVolatile;
unsigned fSegmentMask;
SkPoint fLastMovePoint;
int fLastMoveIndex; // only needed until SkPath is immutable
bool fNeedsMoveVerb;
enum IsA {
kIsA_JustMoves, // we only have 0 or more moves
kIsA_MoreThanMoves, // we have verbs other than just move
kIsA_Oval, // we are 0 or more moves followed by an oval
kIsA_RRect, // we are 0 or more moves followed by a rrect
};
IsA fIsA = kIsA_JustMoves;
int fIsAStart = -1; // tracks direction iff fIsA is not unknown
bool fIsACCW = false; // tracks direction iff fIsA is not unknown
int countVerbs() const { return fVerbs.size(); }
// called right before we add a (non-move) verb
void ensureMove() {
fIsA = kIsA_MoreThanMoves;
if (fNeedsMoveVerb) {
this->moveTo(fLastMovePoint);
}
}
SkPath make(sk_sp<SkPathRef>) const;
SkPathBuilder& privateReverseAddPath(const SkPath&);
friend class SkPathPriv;
};
#endif

View File

@ -0,0 +1,113 @@
/*
* Copyright 2006 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkPathEffect_DEFINED
#define SkPathEffect_DEFINED
#include "include/core/SkFlattenable.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/private/base/SkAPI.h"
// TODO(kjlubick) update clients and remove this unnecessary #include
#include "include/core/SkPath.h" // IWYU pragma: keep
#include <cstddef>
#include <cstdint>
class SkMatrix;
class SkStrokeRec;
struct SkDeserialProcs;
struct SkRect;
/** \class SkPathEffect
SkPathEffect is the base class for objects in the SkPaint that affect
the geometry of a drawing primitive before it is transformed by the
canvas' matrix and drawn.
Dashing is implemented as a subclass of SkPathEffect.
*/
class SK_API SkPathEffect : public SkFlattenable {
public:
/**
* Returns a patheffect that apples each effect (first and second) to the original path,
* and returns a path with the sum of these.
*
* result = first(path) + second(path)
*
*/
static sk_sp<SkPathEffect> MakeSum(sk_sp<SkPathEffect> first, sk_sp<SkPathEffect> second);
/**
* Returns a patheffect that applies the inner effect to the path, and then applies the
* outer effect to the result of the inner's.
*
* result = outer(inner(path))
*/
static sk_sp<SkPathEffect> MakeCompose(sk_sp<SkPathEffect> outer, sk_sp<SkPathEffect> inner);
static SkFlattenable::Type GetFlattenableType() {
return kSkPathEffect_Type;
}
// move to base?
enum DashType {
kNone_DashType, //!< ignores the info parameter
kDash_DashType, //!< fills in all of the info parameter
};
struct DashInfo {
DashInfo() : fIntervals(nullptr), fCount(0), fPhase(0) {}
DashInfo(SkScalar* intervals, int32_t count, SkScalar phase)
: fIntervals(intervals), fCount(count), fPhase(phase) {}
SkScalar* fIntervals; //!< Length of on/off intervals for dashed lines
// Even values represent ons, and odds offs
int32_t fCount; //!< Number of intervals in the dash. Should be even number
SkScalar fPhase; //!< Offset into the dashed interval pattern
// mod the sum of all intervals
};
DashType asADash(DashInfo* info) const;
/**
* Given a src path (input) and a stroke-rec (input and output), apply
* this effect to the src path, returning the new path in dst, and return
* true. If this effect cannot be applied, return false and ignore dst
* and stroke-rec.
*
* The stroke-rec specifies the initial request for stroking (if any).
* The effect can treat this as input only, or it can choose to change
* the rec as well. For example, the effect can decide to change the
* stroke's width or join, or the effect can change the rec from stroke
* to fill (or fill to stroke) in addition to returning a new (dst) path.
*
* If this method returns true, the caller will apply (as needed) the
* resulting stroke-rec to dst and then draw.
*/
bool filterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect* cullR) const;
/** Version of filterPath that can be called when the CTM is known. */
bool filterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect* cullR,
const SkMatrix& ctm) const;
/** True if this path effect requires a valid CTM */
bool needsCTM() const;
static sk_sp<SkPathEffect> Deserialize(const void* data, size_t size,
const SkDeserialProcs* procs = nullptr);
private:
SkPathEffect() = default;
friend class SkPathEffectBase;
using INHERITED = SkFlattenable;
};
#endif

View File

@ -0,0 +1,95 @@
/*
* Copyright 2006 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkPathMeasure_DEFINED
#define SkPathMeasure_DEFINED
#include "include/core/SkContourMeasure.h"
#include "include/core/SkPoint.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/private/base/SkAPI.h"
#include "include/private/base/SkDebug.h"
class SkMatrix;
class SkPath;
class SK_API SkPathMeasure {
public:
SkPathMeasure();
/** Initialize the pathmeasure with the specified path. The parts of the path that are needed
* are copied, so the client is free to modify/delete the path after this call.
*
* resScale controls the precision of the measure. values > 1 increase the
* precision (and possibly slow down the computation).
*/
SkPathMeasure(const SkPath& path, bool forceClosed, SkScalar resScale = 1);
~SkPathMeasure();
SkPathMeasure(SkPathMeasure&&) = default;
SkPathMeasure& operator=(SkPathMeasure&&) = default;
/** Reset the pathmeasure with the specified path. The parts of the path that are needed
* are copied, so the client is free to modify/delete the path after this call..
*/
void setPath(const SkPath*, bool forceClosed);
/** Return the total length of the current contour, or 0 if no path
is associated (e.g. resetPath(null))
*/
SkScalar getLength();
/** Pins distance to 0 <= distance <= getLength(), and then computes
the corresponding position and tangent.
Returns false if there is no path, or a zero-length path was specified, in which case
position and tangent are unchanged.
*/
[[nodiscard]] bool getPosTan(SkScalar distance, SkPoint* position, SkVector* tangent);
enum MatrixFlags {
kGetPosition_MatrixFlag = 0x01,
kGetTangent_MatrixFlag = 0x02,
kGetPosAndTan_MatrixFlag = kGetPosition_MatrixFlag | kGetTangent_MatrixFlag
};
/** Pins distance to 0 <= distance <= getLength(), and then computes
the corresponding matrix (by calling getPosTan).
Returns false if there is no path, or a zero-length path was specified, in which case
matrix is unchanged.
*/
[[nodiscard]] bool getMatrix(SkScalar distance, SkMatrix* matrix,
MatrixFlags flags = kGetPosAndTan_MatrixFlag);
/** Given a start and stop distance, return in dst the intervening segment(s).
If the segment is zero-length, return false, else return true.
startD and stopD are pinned to legal values (0..getLength()). If startD > stopD
then return false (and leave dst untouched).
Begin the segment with a moveTo if startWithMoveTo is true
*/
bool getSegment(SkScalar startD, SkScalar stopD, SkPath* dst, bool startWithMoveTo);
/** Return true if the current contour is closed()
*/
bool isClosed();
/** Move to the next contour in the path. Return true if one exists, or false if
we're done with the path.
*/
bool nextContour();
#ifdef SK_DEBUG
void dump();
#endif
const SkContourMeasure* currentMeasure() const { return fContour.get(); }
private:
SkContourMeasureIter fIter;
sk_sp<SkContourMeasure> fContour;
};
#endif

View File

@ -0,0 +1,57 @@
/*
* Copyright 2019 Google LLC.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkPathTypes_DEFINED
#define SkPathTypes_DEFINED
enum class SkPathFillType {
/** Specifies that "inside" is computed by a non-zero sum of signed edge crossings */
kWinding,
/** Specifies that "inside" is computed by an odd number of edge crossings */
kEvenOdd,
/** Same as Winding, but draws outside of the path, rather than inside */
kInverseWinding,
/** Same as EvenOdd, but draws outside of the path, rather than inside */
kInverseEvenOdd
};
static inline bool SkPathFillType_IsEvenOdd(SkPathFillType ft) {
return (static_cast<int>(ft) & 1) != 0;
}
static inline bool SkPathFillType_IsInverse(SkPathFillType ft) {
return (static_cast<int>(ft) & 2) != 0;
}
static inline SkPathFillType SkPathFillType_ConvertToNonInverse(SkPathFillType ft) {
return static_cast<SkPathFillType>(static_cast<int>(ft) & 1);
}
enum class SkPathDirection {
/** clockwise direction for adding closed contours */
kCW,
/** counter-clockwise direction for adding closed contours */
kCCW,
};
enum SkPathSegmentMask {
kLine_SkPathSegmentMask = 1 << 0,
kQuad_SkPathSegmentMask = 1 << 1,
kConic_SkPathSegmentMask = 1 << 2,
kCubic_SkPathSegmentMask = 1 << 3,
};
enum class SkPathVerb {
kMove, //!< SkPath::RawIter returns 1 point
kLine, //!< SkPath::RawIter returns 2 points
kQuad, //!< SkPath::RawIter returns 3 points
kConic, //!< SkPath::RawIter returns 3 points + 1 weight
kCubic, //!< SkPath::RawIter returns 4 points
kClose //!< SkPath::RawIter returns 0 points
};
#endif

View File

@ -0,0 +1,42 @@
/*
* Copyright 2022 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkPathUtils_DEFINED
#define SkPathUtils_DEFINED
#include "include/core/SkScalar.h"
#include "include/core/SkTypes.h"
class SkMatrix;
class SkPaint;
class SkPath;
struct SkRect;
namespace skpathutils {
/** Returns the filled equivalent of the stroked path.
@param src SkPath read to create a filled version
@param paint SkPaint, from which attributes such as stroke cap, width, miter, and join,
as well as pathEffect will be used.
@param dst resulting SkPath; may be the same as src, but may not be nullptr
@param cullRect optional limit passed to SkPathEffect
@param resScale if > 1, increase precision, else if (0 < resScale < 1) reduce precision
to favor speed and size
@return true if the dst path was updated, false if it was not (e.g. if the path
represents hairline and cannot be filled).
*/
SK_API bool FillPathWithPaint(const SkPath &src, const SkPaint &paint, SkPath *dst,
const SkRect *cullRect, SkScalar resScale = 1);
SK_API bool FillPathWithPaint(const SkPath &src, const SkPaint &paint, SkPath *dst,
const SkRect *cullRect, const SkMatrix &ctm);
SK_API bool FillPathWithPaint(const SkPath &src, const SkPaint &paint, SkPath *dst);
}
#endif

View File

@ -0,0 +1,291 @@
/*
* Copyright 2007 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkPicture_DEFINED
#define SkPicture_DEFINED
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkShader.h" // IWYU pragma: keep
#include "include/core/SkTypes.h"
#include <atomic>
#include <cstddef>
#include <cstdint>
class SkCanvas;
class SkData;
class SkMatrix;
class SkStream;
class SkWStream;
enum class SkFilterMode;
struct SkDeserialProcs;
struct SkSerialProcs;
// TODO(kjlubick) Remove this after cleaning up clients
#include "include/core/SkTileMode.h" // IWYU pragma: keep
/** \class SkPicture
SkPicture records drawing commands made to SkCanvas. The command stream may be
played in whole or in part at a later time.
SkPicture is an abstract class. SkPicture may be generated by SkPictureRecorder
or SkDrawable, or from SkPicture previously saved to SkData or SkStream.
SkPicture may contain any SkCanvas drawing command, as well as one or more
SkCanvas matrix or SkCanvas clip. SkPicture has a cull SkRect, which is used as
a bounding box hint. To limit SkPicture bounds, use SkCanvas clip when
recording or drawing SkPicture.
*/
class SK_API SkPicture : public SkRefCnt {
public:
~SkPicture() override;
/** Recreates SkPicture that was serialized into a stream. Returns constructed SkPicture
if successful; otherwise, returns nullptr. Fails if data does not permit
constructing valid SkPicture.
procs->fPictureProc permits supplying a custom function to decode SkPicture.
If procs->fPictureProc is nullptr, default decoding is used. procs->fPictureCtx
may be used to provide user context to procs->fPictureProc; procs->fPictureProc
is called with a pointer to data, data byte length, and user context.
@param stream container for serial data
@param procs custom serial data decoders; may be nullptr
@return SkPicture constructed from stream data
*/
static sk_sp<SkPicture> MakeFromStream(SkStream* stream,
const SkDeserialProcs* procs = nullptr);
/** Recreates SkPicture that was serialized into data. Returns constructed SkPicture
if successful; otherwise, returns nullptr. Fails if data does not permit
constructing valid SkPicture.
procs->fPictureProc permits supplying a custom function to decode SkPicture.
If procs->fPictureProc is nullptr, default decoding is used. procs->fPictureCtx
may be used to provide user context to procs->fPictureProc; procs->fPictureProc
is called with a pointer to data, data byte length, and user context.
@param data container for serial data
@param procs custom serial data decoders; may be nullptr
@return SkPicture constructed from data
*/
static sk_sp<SkPicture> MakeFromData(const SkData* data,
const SkDeserialProcs* procs = nullptr);
/**
@param data pointer to serial data
@param size size of data
@param procs custom serial data decoders; may be nullptr
@return SkPicture constructed from data
*/
static sk_sp<SkPicture> MakeFromData(const void* data, size_t size,
const SkDeserialProcs* procs = nullptr);
/** \class SkPicture::AbortCallback
AbortCallback is an abstract class. An implementation of AbortCallback may
passed as a parameter to SkPicture::playback, to stop it before all drawing
commands have been processed.
If AbortCallback::abort returns true, SkPicture::playback is interrupted.
*/
class SK_API AbortCallback {
public:
/** Has no effect.
*/
virtual ~AbortCallback() = default;
/** Stops SkPicture playback when some condition is met. A subclass of
AbortCallback provides an override for abort() that can stop SkPicture::playback.
The part of SkPicture drawn when aborted is undefined. SkPicture instantiations are
free to stop drawing at different points during playback.
If the abort happens inside one or more calls to SkCanvas::save(), stack
of SkCanvas matrix and SkCanvas clip values is restored to its state before
SkPicture::playback was called.
@return true to stop playback
example: https://fiddle.skia.org/c/@Picture_AbortCallback_abort
*/
virtual bool abort() = 0;
protected:
AbortCallback() = default;
AbortCallback(const AbortCallback&) = delete;
AbortCallback& operator=(const AbortCallback&) = delete;
};
/** Replays the drawing commands on the specified canvas. In the case that the
commands are recorded, each command in the SkPicture is sent separately to canvas.
To add a single command to draw SkPicture to recording canvas, call
SkCanvas::drawPicture instead.
@param canvas receiver of drawing commands
@param callback allows interruption of playback
example: https://fiddle.skia.org/c/@Picture_playback
*/
virtual void playback(SkCanvas* canvas, AbortCallback* callback = nullptr) const = 0;
/** Returns cull SkRect for this picture, passed in when SkPicture was created.
Returned SkRect does not specify clipping SkRect for SkPicture; cull is hint
of SkPicture bounds.
SkPicture is free to discard recorded drawing commands that fall outside
cull.
@return bounds passed when SkPicture was created
example: https://fiddle.skia.org/c/@Picture_cullRect
*/
virtual SkRect cullRect() const = 0;
/** Returns a non-zero value unique among SkPicture in Skia process.
@return identifier for SkPicture
*/
uint32_t uniqueID() const { return fUniqueID; }
/** Returns storage containing SkData describing SkPicture, using optional custom
encoders.
procs->fPictureProc permits supplying a custom function to encode SkPicture.
If procs->fPictureProc is nullptr, default encoding is used. procs->fPictureCtx
may be used to provide user context to procs->fPictureProc; procs->fPictureProc
is called with a pointer to SkPicture and user context.
The default behavior for serializing SkImages is to encode a nullptr. Should
clients want to, for example, encode these SkImages as PNGs so they can be
deserialized, they must provide SkSerialProcs with the fImageProc set to do so.
@param procs custom serial data encoders; may be nullptr
@return storage containing serialized SkPicture
example: https://fiddle.skia.org/c/@Picture_serialize
*/
sk_sp<SkData> serialize(const SkSerialProcs* procs = nullptr) const;
/** Writes picture to stream, using optional custom encoders.
procs->fPictureProc permits supplying a custom function to encode SkPicture.
If procs->fPictureProc is nullptr, default encoding is used. procs->fPictureCtx
may be used to provide user context to procs->fPictureProc; procs->fPictureProc
is called with a pointer to SkPicture and user context.
The default behavior for serializing SkImages is to encode a nullptr. Should
clients want to, for example, encode these SkImages as PNGs so they can be
deserialized, they must provide SkSerialProcs with the fImageProc set to do so.
@param stream writable serial data stream
@param procs custom serial data encoders; may be nullptr
example: https://fiddle.skia.org/c/@Picture_serialize_2
*/
void serialize(SkWStream* stream, const SkSerialProcs* procs = nullptr) const;
/** Returns a placeholder SkPicture. Result does not draw, and contains only
cull SkRect, a hint of its bounds. Result is immutable; it cannot be changed
later. Result identifier is unique.
Returned placeholder can be intercepted during playback to insert other
commands into SkCanvas draw stream.
@param cull placeholder dimensions
@return placeholder with unique identifier
example: https://fiddle.skia.org/c/@Picture_MakePlaceholder
*/
static sk_sp<SkPicture> MakePlaceholder(SkRect cull);
/** Returns the approximate number of operations in SkPicture. Returned value
may be greater or less than the number of SkCanvas calls
recorded: some calls may be recorded as more than one operation, other
calls may be optimized away.
@param nested if true, include the op-counts of nested pictures as well, else
just return count the ops in the top-level picture.
@return approximate operation count
example: https://fiddle.skia.org/c/@Picture_approximateOpCount
*/
virtual int approximateOpCount(bool nested = false) const = 0;
/** Returns the approximate byte size of SkPicture. Does not include large objects
referenced by SkPicture.
@return approximate size
example: https://fiddle.skia.org/c/@Picture_approximateBytesUsed
*/
virtual size_t approximateBytesUsed() const = 0;
/** Return a new shader that will draw with this picture.
*
* @param tmx The tiling mode to use when sampling in the x-direction.
* @param tmy The tiling mode to use when sampling in the y-direction.
* @param mode How to filter the tiles
* @param localMatrix Optional matrix used when sampling
* @param tileRect The tile rectangle in picture coordinates: this represents the subset
* (or superset) of the picture used when building a tile. It is not
* affected by localMatrix and does not imply scaling (only translation
* and cropping). If null, the tile rect is considered equal to the picture
* bounds.
* @return Returns a new shader object. Note: this function never returns null.
*/
sk_sp<SkShader> makeShader(SkTileMode tmx, SkTileMode tmy, SkFilterMode mode,
const SkMatrix* localMatrix, const SkRect* tileRect) const;
sk_sp<SkShader> makeShader(SkTileMode tmx, SkTileMode tmy, SkFilterMode mode) const {
return this->makeShader(tmx, tmy, mode, nullptr, nullptr);
}
private:
// Allowed subclasses.
SkPicture();
friend class SkBigPicture;
friend class SkEmptyPicture;
friend class SkPicturePriv;
void serialize(SkWStream*, const SkSerialProcs*, class SkRefCntSet* typefaces,
bool textBlobsOnly=false) const;
static sk_sp<SkPicture> MakeFromStreamPriv(SkStream*, const SkDeserialProcs*,
class SkTypefacePlayback*,
int recursionLimit);
friend class SkPictureData;
/** Return true if the SkStream/Buffer represents a serialized picture, and
fills out SkPictInfo. After this function returns, the data source is not
rewound so it will have to be manually reset before passing to
MakeFromStream or MakeFromBuffer. Note, MakeFromStream and
MakeFromBuffer perform this check internally so these entry points are
intended for stand alone tools.
If false is returned, SkPictInfo is unmodified.
*/
static bool StreamIsSKP(SkStream*, struct SkPictInfo*);
static bool BufferIsSKP(class SkReadBuffer*, struct SkPictInfo*);
friend bool SkPicture_StreamIsSKP(SkStream*, struct SkPictInfo*);
// Returns NULL if this is not an SkBigPicture.
virtual const class SkBigPicture* asSkBigPicture() const { return nullptr; }
static bool IsValidPictInfo(const struct SkPictInfo& info);
static sk_sp<SkPicture> Forwardport(const struct SkPictInfo&,
const class SkPictureData*,
class SkReadBuffer* buffer);
struct SkPictInfo createHeader() const;
class SkPictureData* backport() const;
uint32_t fUniqueID;
mutable std::atomic<bool> fAddedToCache{false};
};
#endif

View File

@ -0,0 +1,115 @@
/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkPictureRecorder_DEFINED
#define SkPictureRecorder_DEFINED
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/private/base/SkAPI.h"
#include <memory>
#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
namespace android {
class Picture;
};
#endif
class SkBBHFactory;
class SkBBoxHierarchy;
class SkCanvas;
class SkDrawable;
class SkPicture;
class SkRecord;
class SkRecorder;
class SK_API SkPictureRecorder {
public:
SkPictureRecorder();
~SkPictureRecorder();
/** Returns the canvas that records the drawing commands.
@param bounds the cull rect used when recording this picture. Any drawing the falls outside
of this rect is undefined, and may be drawn or it may not.
@param bbh optional acceleration structure
@param recordFlags optional flags that control recording.
@return the canvas.
*/
SkCanvas* beginRecording(const SkRect& bounds, sk_sp<SkBBoxHierarchy> bbh);
SkCanvas* beginRecording(const SkRect& bounds, SkBBHFactory* bbhFactory = nullptr);
SkCanvas* beginRecording(SkScalar width, SkScalar height,
SkBBHFactory* bbhFactory = nullptr) {
return this->beginRecording(SkRect::MakeWH(width, height), bbhFactory);
}
/** Returns the recording canvas if one is active, or NULL if recording is
not active. This does not alter the refcnt on the canvas (if present).
*/
SkCanvas* getRecordingCanvas();
/**
* Signal that the caller is done recording. This invalidates the canvas returned by
* beginRecording/getRecordingCanvas. Ownership of the object is passed to the caller, who
* must call unref() when they are done using it.
*
* The returned picture is immutable. If during recording drawables were added to the canvas,
* these will have been "drawn" into a recording canvas, so that this resulting picture will
* reflect their current state, but will not contain a live reference to the drawables
* themselves.
*/
sk_sp<SkPicture> finishRecordingAsPicture();
/**
* Signal that the caller is done recording, and update the cull rect to use for bounding
* box hierarchy (BBH) generation. The behavior is the same as calling
* finishRecordingAsPicture(), except that this method updates the cull rect initially passed
* into beginRecording.
* @param cullRect the new culling rectangle to use as the overall bound for BBH generation
* and subsequent culling operations.
* @return the picture containing the recorded content.
*/
sk_sp<SkPicture> finishRecordingAsPictureWithCull(const SkRect& cullRect);
/**
* Signal that the caller is done recording. This invalidates the canvas returned by
* beginRecording/getRecordingCanvas. Ownership of the object is passed to the caller, who
* must call unref() when they are done using it.
*
* Unlike finishRecordingAsPicture(), which returns an immutable picture, the returned drawable
* may contain live references to other drawables (if they were added to the recording canvas)
* and therefore this drawable will reflect the current state of those nested drawables anytime
* it is drawn or a new picture is snapped from it (by calling drawable->makePictureSnapshot()).
*/
sk_sp<SkDrawable> finishRecordingAsDrawable();
private:
void reset();
/** Replay the current (partially recorded) operation stream into
canvas. This call doesn't close the current recording.
*/
#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
friend class android::Picture;
#endif
friend class SkPictureRecorderReplayTester; // for unit testing
void partialReplay(SkCanvas* canvas) const;
bool fActivelyRecording;
SkRect fCullRect;
sk_sp<SkBBoxHierarchy> fBBH;
std::unique_ptr<SkRecorder> fRecorder;
sk_sp<SkRecord> fRecord;
SkPictureRecorder(SkPictureRecorder&&) = delete;
SkPictureRecorder& operator=(SkPictureRecorder&&) = delete;
};
#endif

View File

@ -0,0 +1,119 @@
/*
* Copyright 2008 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkPixelRef_DEFINED
#define SkPixelRef_DEFINED
#include "include/core/SkRefCnt.h"
#include "include/core/SkSize.h"
#include "include/private/SkIDChangeListener.h"
#include "include/private/base/SkAPI.h"
#include "include/private/base/SkTo.h"
#include <atomic>
#include <cstddef>
#include <cstdint>
class SkDiscardableMemory;
/** \class SkPixelRef
This class is the smart container for pixel memory, and is used with SkBitmap.
This class can be shared/accessed between multiple threads.
*/
class SK_API SkPixelRef : public SkRefCnt {
public:
SkPixelRef(int width, int height, void* addr, size_t rowBytes);
~SkPixelRef() override;
SkISize dimensions() const { return {fWidth, fHeight}; }
int width() const { return fWidth; }
int height() const { return fHeight; }
void* pixels() const { return fPixels; }
size_t rowBytes() const { return fRowBytes; }
/** Returns a non-zero, unique value corresponding to the pixels in this
pixelref. Each time the pixels are changed (and notifyPixelsChanged is
called), a different generation ID will be returned.
*/
uint32_t getGenerationID() const;
/**
* Call this if you have changed the contents of the pixels. This will in-
* turn cause a different generation ID value to be returned from
* getGenerationID().
*/
void notifyPixelsChanged();
/** Returns true if this pixelref is marked as immutable, meaning that the
contents of its pixels will not change for the lifetime of the pixelref.
*/
bool isImmutable() const { return fMutability != kMutable; }
/** Marks this pixelref is immutable, meaning that the contents of its
pixels will not change for the lifetime of the pixelref. This state can
be set on a pixelref, but it cannot be cleared once it is set.
*/
void setImmutable();
// Register a listener that may be called the next time our generation ID changes.
//
// We'll only call the listener if we're confident that we are the only SkPixelRef with this
// generation ID. If our generation ID changes and we decide not to call the listener, we'll
// never call it: you must add a new listener for each generation ID change. We also won't call
// the listener when we're certain no one knows what our generation ID is.
//
// This can be used to invalidate caches keyed by SkPixelRef generation ID.
// Takes ownership of listener. Threadsafe.
void addGenIDChangeListener(sk_sp<SkIDChangeListener> listener);
// Call when this pixelref is part of the key to a resourcecache entry. This allows the cache
// to know automatically those entries can be purged when this pixelref is changed or deleted.
void notifyAddedToCache() {
fAddedToCache.store(true);
}
virtual SkDiscardableMemory* diagnostic_only_getDiscardable() const { return nullptr; }
protected:
void android_only_reset(int width, int height, size_t rowBytes);
private:
int fWidth;
int fHeight;
void* fPixels;
size_t fRowBytes;
// Bottom bit indicates the Gen ID is unique.
bool genIDIsUnique() const { return SkToBool(fTaggedGenID.load() & 1); }
mutable std::atomic<uint32_t> fTaggedGenID;
SkIDChangeListener::List fGenIDChangeListeners;
// Set true by caches when they cache content that's derived from the current pixels.
std::atomic<bool> fAddedToCache;
enum Mutability {
kMutable, // PixelRefs begin mutable.
kTemporarilyImmutable, // Considered immutable, but can revert to mutable.
kImmutable, // Once set to this state, it never leaves.
} fMutability : 8; // easily fits inside a byte
void needsNewGenID();
void callGenIDChangeListeners();
void setTemporarilyImmutable();
void restoreMutability();
friend class SkSurface_Raster; // For temporary immutable methods above.
void setImmutableWithID(uint32_t genID);
friend void SkBitmapCache_setImmutableWithID(SkPixelRef*, uint32_t);
using INHERITED = SkRefCnt;
};
#endif

View File

@ -0,0 +1,731 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkPixmap_DEFINED
#define SkPixmap_DEFINED
#include "include/core/SkColor.h"
#include "include/core/SkColorType.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkSamplingOptions.h"
#include "include/core/SkSize.h"
#include "include/private/base/SkAPI.h"
#include "include/private/base/SkAssert.h"
#include <cstddef>
#include <cstdint>
class SkColorSpace;
enum SkAlphaType : int;
struct SkMask;
/** \class SkPixmap
SkPixmap provides a utility to pair SkImageInfo with pixels and row bytes.
SkPixmap is a low level class which provides convenience functions to access
raster destinations. SkCanvas can not draw SkPixmap, nor does SkPixmap provide
a direct drawing destination.
Use SkBitmap to draw pixels referenced by SkPixmap; use SkSurface to draw into
pixels referenced by SkPixmap.
SkPixmap does not try to manage the lifetime of the pixel memory. Use SkPixelRef
to manage pixel memory; SkPixelRef is safe across threads.
*/
class SK_API SkPixmap {
public:
/** Creates an empty SkPixmap without pixels, with kUnknown_SkColorType, with
kUnknown_SkAlphaType, and with a width and height of zero. Use
reset() to associate pixels, SkColorType, SkAlphaType, width, and height
after SkPixmap has been created.
@return empty SkPixmap
*/
SkPixmap()
: fPixels(nullptr), fRowBytes(0), fInfo(SkImageInfo::MakeUnknown(0, 0))
{}
/** Creates SkPixmap from info width, height, SkAlphaType, and SkColorType.
addr points to pixels, or nullptr. rowBytes should be info.width() times
info.bytesPerPixel(), or larger.
No parameter checking is performed; it is up to the caller to ensure that
addr and rowBytes agree with info.
The memory lifetime of pixels is managed by the caller. When SkPixmap goes
out of scope, addr is unaffected.
SkPixmap may be later modified by reset() to change its size, pixel type, or
storage.
@param info width, height, SkAlphaType, SkColorType of SkImageInfo
@param addr pointer to pixels allocated by caller; may be nullptr
@param rowBytes size of one row of addr; width times pixel size, or larger
@return initialized SkPixmap
*/
SkPixmap(const SkImageInfo& info, const void* addr, size_t rowBytes)
: fPixels(addr), fRowBytes(rowBytes), fInfo(info)
{}
/** Sets width, height, row bytes to zero; pixel address to nullptr; SkColorType to
kUnknown_SkColorType; and SkAlphaType to kUnknown_SkAlphaType.
The prior pixels are unaffected; it is up to the caller to release pixels
memory if desired.
example: https://fiddle.skia.org/c/@Pixmap_reset
*/
void reset();
/** Sets width, height, SkAlphaType, and SkColorType from info.
Sets pixel address from addr, which may be nullptr.
Sets row bytes from rowBytes, which should be info.width() times
info.bytesPerPixel(), or larger.
Does not check addr. Asserts if built with SK_DEBUG defined and if rowBytes is
too small to hold one row of pixels.
The memory lifetime pixels are managed by the caller. When SkPixmap goes
out of scope, addr is unaffected.
@param info width, height, SkAlphaType, SkColorType of SkImageInfo
@param addr pointer to pixels allocated by caller; may be nullptr
@param rowBytes size of one row of addr; width times pixel size, or larger
example: https://fiddle.skia.org/c/@Pixmap_reset_2
*/
void reset(const SkImageInfo& info, const void* addr, size_t rowBytes);
/** Changes SkColorSpace in SkImageInfo; preserves width, height, SkAlphaType, and
SkColorType in SkImage, and leaves pixel address and row bytes unchanged.
SkColorSpace reference count is incremented.
@param colorSpace SkColorSpace moved to SkImageInfo
example: https://fiddle.skia.org/c/@Pixmap_setColorSpace
*/
void setColorSpace(sk_sp<SkColorSpace> colorSpace);
/** Deprecated.
*/
[[nodiscard]] bool reset(const SkMask& mask);
/** Sets subset width, height, pixel address to intersection of SkPixmap with area,
if intersection is not empty; and return true. Otherwise, leave subset unchanged
and return false.
Failing to read the return value generates a compile time warning.
@param subset storage for width, height, pixel address of intersection
@param area bounds to intersect with SkPixmap
@return true if intersection of SkPixmap and area is not empty
*/
[[nodiscard]] bool extractSubset(SkPixmap* subset, const SkIRect& area) const;
/** Returns width, height, SkAlphaType, SkColorType, and SkColorSpace.
@return reference to SkImageInfo
*/
const SkImageInfo& info() const { return fInfo; }
/** Returns row bytes, the interval from one pixel row to the next. Row bytes
is at least as large as: width() * info().bytesPerPixel().
Returns zero if colorType() is kUnknown_SkColorType.
It is up to the SkBitmap creator to ensure that row bytes is a useful value.
@return byte length of pixel row
*/
size_t rowBytes() const { return fRowBytes; }
/** Returns pixel address, the base address corresponding to the pixel origin.
It is up to the SkPixmap creator to ensure that pixel address is a useful value.
@return pixel address
*/
const void* addr() const { return fPixels; }
/** Returns pixel count in each pixel row. Should be equal or less than:
rowBytes() / info().bytesPerPixel().
@return pixel width in SkImageInfo
*/
int width() const { return fInfo.width(); }
/** Returns pixel row count.
@return pixel height in SkImageInfo
*/
int height() const { return fInfo.height(); }
/**
* Return the dimensions of the pixmap (from its ImageInfo)
*/
SkISize dimensions() const { return fInfo.dimensions(); }
SkColorType colorType() const { return fInfo.colorType(); }
SkAlphaType alphaType() const { return fInfo.alphaType(); }
/** Returns SkColorSpace, the range of colors, associated with SkImageInfo. The
reference count of SkColorSpace is unchanged. The returned SkColorSpace is
immutable.
@return SkColorSpace in SkImageInfo, or nullptr
*/
SkColorSpace* colorSpace() const;
/** Returns smart pointer to SkColorSpace, the range of colors, associated with
SkImageInfo. The smart pointer tracks the number of objects sharing this
SkColorSpace reference so the memory is released when the owners destruct.
The returned SkColorSpace is immutable.
@return SkColorSpace in SkImageInfo wrapped in a smart pointer
*/
sk_sp<SkColorSpace> refColorSpace() const;
/** Returns true if SkAlphaType is kOpaque_SkAlphaType.
Does not check if SkColorType allows alpha, or if any pixel value has
transparency.
@return true if SkImageInfo has opaque SkAlphaType
*/
bool isOpaque() const { return fInfo.isOpaque(); }
/** Returns SkIRect { 0, 0, width(), height() }.
@return integral rectangle from origin to width() and height()
*/
SkIRect bounds() const { return SkIRect::MakeWH(this->width(), this->height()); }
/** Returns number of pixels that fit on row. Should be greater than or equal to
width().
@return maximum pixels per row
*/
int rowBytesAsPixels() const { return int(fRowBytes >> this->shiftPerPixel()); }
/** Returns bit shift converting row bytes to row pixels.
Returns zero for kUnknown_SkColorType.
@return one of: 0, 1, 2, 3; left shift to convert pixels to bytes
*/
int shiftPerPixel() const { return fInfo.shiftPerPixel(); }
/** Returns minimum memory required for pixel storage.
Does not include unused memory on last row when rowBytesAsPixels() exceeds width().
Returns SIZE_MAX if result does not fit in size_t.
Returns zero if height() or width() is 0.
Returns height() times rowBytes() if colorType() is kUnknown_SkColorType.
@return size in bytes of image buffer
*/
size_t computeByteSize() const { return fInfo.computeByteSize(fRowBytes); }
/** Returns true if all pixels are opaque. SkColorType determines how pixels
are encoded, and whether pixel describes alpha. Returns true for SkColorType
without alpha in each pixel; for other SkColorType, returns true if all
pixels have alpha values equivalent to 1.0 or greater.
For SkColorType kRGB_565_SkColorType or kGray_8_SkColorType: always
returns true. For SkColorType kAlpha_8_SkColorType, kBGRA_8888_SkColorType,
kRGBA_8888_SkColorType: returns true if all pixel alpha values are 255.
For SkColorType kARGB_4444_SkColorType: returns true if all pixel alpha values are 15.
For kRGBA_F16_SkColorType: returns true if all pixel alpha values are 1.0 or
greater.
Returns false for kUnknown_SkColorType.
@return true if all pixels have opaque values or SkColorType is opaque
example: https://fiddle.skia.org/c/@Pixmap_computeIsOpaque
*/
bool computeIsOpaque() const;
/** Returns pixel at (x, y) as unpremultiplied color.
Returns black with alpha if SkColorType is kAlpha_8_SkColorType.
Input is not validated: out of bounds values of x or y trigger an assert() if
built with SK_DEBUG defined; and returns undefined values or may crash if
SK_RELEASE is defined. Fails if SkColorType is kUnknown_SkColorType or
pixel address is nullptr.
SkColorSpace in SkImageInfo is ignored. Some color precision may be lost in the
conversion to unpremultiplied color; original pixel data may have additional
precision.
@param x column index, zero or greater, and less than width()
@param y row index, zero or greater, and less than height()
@return pixel converted to unpremultiplied color
example: https://fiddle.skia.org/c/@Pixmap_getColor
*/
SkColor getColor(int x, int y) const;
/** Returns pixel at (x, y) as unpremultiplied color as an SkColor4f.
Returns black with alpha if SkColorType is kAlpha_8_SkColorType.
Input is not validated: out of bounds values of x or y trigger an assert() if
built with SK_DEBUG defined; and returns undefined values or may crash if
SK_RELEASE is defined. Fails if SkColorType is kUnknown_SkColorType or
pixel address is nullptr.
SkColorSpace in SkImageInfo is ignored. Some color precision may be lost in the
conversion to unpremultiplied color; original pixel data may have additional
precision, though this is less likely than for getColor(). Rounding errors may
occur if the underlying type has lower precision.
@param x column index, zero or greater, and less than width()
@param y row index, zero or greater, and less than height()
@return pixel converted to unpremultiplied float color
*/
SkColor4f getColor4f(int x, int y) const;
/** Look up the pixel at (x,y) and return its alpha component, normalized to [0..1].
This is roughly equivalent to SkGetColorA(getColor()), but can be more efficent
(and more precise if the pixels store more than 8 bits per component).
@param x column index, zero or greater, and less than width()
@param y row index, zero or greater, and less than height()
@return alpha converted to normalized float
*/
float getAlphaf(int x, int y) const;
/** Returns readable pixel address at (x, y). Returns nullptr if SkPixelRef is nullptr.
Input is not validated: out of bounds values of x or y trigger an assert() if
built with SK_DEBUG defined. Returns nullptr if SkColorType is kUnknown_SkColorType.
Performs a lookup of pixel size; for better performance, call
one of: addr8, addr16, addr32, addr64, or addrF16().
@param x column index, zero or greater, and less than width()
@param y row index, zero or greater, and less than height()
@return readable generic pointer to pixel
*/
const void* addr(int x, int y) const {
return (const char*)fPixels + fInfo.computeOffset(x, y, fRowBytes);
}
/** Returns readable base pixel address. Result is addressable as unsigned 8-bit bytes.
Will trigger an assert() if SkColorType is not kAlpha_8_SkColorType or
kGray_8_SkColorType, and is built with SK_DEBUG defined.
One byte corresponds to one pixel.
@return readable unsigned 8-bit pointer to pixels
*/
const uint8_t* addr8() const {
SkASSERT(1 == fInfo.bytesPerPixel());
return reinterpret_cast<const uint8_t*>(fPixels);
}
/** Returns readable base pixel address. Result is addressable as unsigned 16-bit words.
Will trigger an assert() if SkColorType is not kRGB_565_SkColorType or
kARGB_4444_SkColorType, and is built with SK_DEBUG defined.
One word corresponds to one pixel.
@return readable unsigned 16-bit pointer to pixels
*/
const uint16_t* addr16() const {
SkASSERT(2 == fInfo.bytesPerPixel());
return reinterpret_cast<const uint16_t*>(fPixels);
}
/** Returns readable base pixel address. Result is addressable as unsigned 32-bit words.
Will trigger an assert() if SkColorType is not kRGBA_8888_SkColorType or
kBGRA_8888_SkColorType, and is built with SK_DEBUG defined.
One word corresponds to one pixel.
@return readable unsigned 32-bit pointer to pixels
*/
const uint32_t* addr32() const {
SkASSERT(4 == fInfo.bytesPerPixel());
return reinterpret_cast<const uint32_t*>(fPixels);
}
/** Returns readable base pixel address. Result is addressable as unsigned 64-bit words.
Will trigger an assert() if SkColorType is not kRGBA_F16_SkColorType and is built
with SK_DEBUG defined.
One word corresponds to one pixel.
@return readable unsigned 64-bit pointer to pixels
*/
const uint64_t* addr64() const {
SkASSERT(8 == fInfo.bytesPerPixel());
return reinterpret_cast<const uint64_t*>(fPixels);
}
/** Returns readable base pixel address. Result is addressable as unsigned 16-bit words.
Will trigger an assert() if SkColorType is not kRGBA_F16_SkColorType and is built
with SK_DEBUG defined.
Each word represents one color component encoded as a half float.
Four words correspond to one pixel.
@return readable unsigned 16-bit pointer to first component of pixels
*/
const uint16_t* addrF16() const {
SkASSERT(8 == fInfo.bytesPerPixel());
SkASSERT(kRGBA_F16_SkColorType == fInfo.colorType() ||
kRGBA_F16Norm_SkColorType == fInfo.colorType());
return reinterpret_cast<const uint16_t*>(fPixels);
}
/** Returns readable pixel address at (x, y).
Input is not validated: out of bounds values of x or y trigger an assert() if
built with SK_DEBUG defined.
Will trigger an assert() if SkColorType is not kAlpha_8_SkColorType or
kGray_8_SkColorType, and is built with SK_DEBUG defined.
@param x column index, zero or greater, and less than width()
@param y row index, zero or greater, and less than height()
@return readable unsigned 8-bit pointer to pixel at (x, y)
*/
const uint8_t* addr8(int x, int y) const {
SkASSERT((unsigned)x < (unsigned)fInfo.width());
SkASSERT((unsigned)y < (unsigned)fInfo.height());
return (const uint8_t*)((const char*)this->addr8() + (size_t)y * fRowBytes + (x << 0));
}
/** Returns readable pixel address at (x, y).
Input is not validated: out of bounds values of x or y trigger an assert() if
built with SK_DEBUG defined.
Will trigger an assert() if SkColorType is not kRGB_565_SkColorType or
kARGB_4444_SkColorType, and is built with SK_DEBUG defined.
@param x column index, zero or greater, and less than width()
@param y row index, zero or greater, and less than height()
@return readable unsigned 16-bit pointer to pixel at (x, y)
*/
const uint16_t* addr16(int x, int y) const {
SkASSERT((unsigned)x < (unsigned)fInfo.width());
SkASSERT((unsigned)y < (unsigned)fInfo.height());
return (const uint16_t*)((const char*)this->addr16() + (size_t)y * fRowBytes + (x << 1));
}
/** Returns readable pixel address at (x, y).
Input is not validated: out of bounds values of x or y trigger an assert() if
built with SK_DEBUG defined.
Will trigger an assert() if SkColorType is not kRGBA_8888_SkColorType or
kBGRA_8888_SkColorType, and is built with SK_DEBUG defined.
@param x column index, zero or greater, and less than width()
@param y row index, zero or greater, and less than height()
@return readable unsigned 32-bit pointer to pixel at (x, y)
*/
const uint32_t* addr32(int x, int y) const {
SkASSERT((unsigned)x < (unsigned)fInfo.width());
SkASSERT((unsigned)y < (unsigned)fInfo.height());
return (const uint32_t*)((const char*)this->addr32() + (size_t)y * fRowBytes + (x << 2));
}
/** Returns readable pixel address at (x, y).
Input is not validated: out of bounds values of x or y trigger an assert() if
built with SK_DEBUG defined.
Will trigger an assert() if SkColorType is not kRGBA_F16_SkColorType and is built
with SK_DEBUG defined.
@param x column index, zero or greater, and less than width()
@param y row index, zero or greater, and less than height()
@return readable unsigned 64-bit pointer to pixel at (x, y)
*/
const uint64_t* addr64(int x, int y) const {
SkASSERT((unsigned)x < (unsigned)fInfo.width());
SkASSERT((unsigned)y < (unsigned)fInfo.height());
return (const uint64_t*)((const char*)this->addr64() + (size_t)y * fRowBytes + (x << 3));
}
/** Returns readable pixel address at (x, y).
Input is not validated: out of bounds values of x or y trigger an assert() if
built with SK_DEBUG defined.
Will trigger an assert() if SkColorType is not kRGBA_F16_SkColorType and is built
with SK_DEBUG defined.
Each unsigned 16-bit word represents one color component encoded as a half float.
Four words correspond to one pixel.
@param x column index, zero or greater, and less than width()
@param y row index, zero or greater, and less than height()
@return readable unsigned 16-bit pointer to pixel component at (x, y)
*/
const uint16_t* addrF16(int x, int y) const {
SkASSERT(kRGBA_F16_SkColorType == fInfo.colorType() ||
kRGBA_F16Norm_SkColorType == fInfo.colorType());
return reinterpret_cast<const uint16_t*>(this->addr64(x, y));
}
/** Returns writable base pixel address.
@return writable generic base pointer to pixels
*/
void* writable_addr() const { return const_cast<void*>(fPixels); }
/** Returns writable pixel address at (x, y).
Input is not validated: out of bounds values of x or y trigger an assert() if
built with SK_DEBUG defined. Returns zero if SkColorType is kUnknown_SkColorType.
@param x column index, zero or greater, and less than width()
@param y row index, zero or greater, and less than height()
@return writable generic pointer to pixel
*/
void* writable_addr(int x, int y) const {
return const_cast<void*>(this->addr(x, y));
}
/** Returns writable pixel address at (x, y). Result is addressable as unsigned
8-bit bytes. Will trigger an assert() if SkColorType is not kAlpha_8_SkColorType
or kGray_8_SkColorType, and is built with SK_DEBUG defined.
One byte corresponds to one pixel.
@param x column index, zero or greater, and less than width()
@param y row index, zero or greater, and less than height()
@return writable unsigned 8-bit pointer to pixels
*/
uint8_t* writable_addr8(int x, int y) const {
return const_cast<uint8_t*>(this->addr8(x, y));
}
/** Returns writable_addr pixel address at (x, y). Result is addressable as unsigned
16-bit words. Will trigger an assert() if SkColorType is not kRGB_565_SkColorType
or kARGB_4444_SkColorType, and is built with SK_DEBUG defined.
One word corresponds to one pixel.
@param x column index, zero or greater, and less than width()
@param y row index, zero or greater, and less than height()
@return writable unsigned 16-bit pointer to pixel
*/
uint16_t* writable_addr16(int x, int y) const {
return const_cast<uint16_t*>(this->addr16(x, y));
}
/** Returns writable pixel address at (x, y). Result is addressable as unsigned
32-bit words. Will trigger an assert() if SkColorType is not
kRGBA_8888_SkColorType or kBGRA_8888_SkColorType, and is built with SK_DEBUG
defined.
One word corresponds to one pixel.
@param x column index, zero or greater, and less than width()
@param y row index, zero or greater, and less than height()
@return writable unsigned 32-bit pointer to pixel
*/
uint32_t* writable_addr32(int x, int y) const {
return const_cast<uint32_t*>(this->addr32(x, y));
}
/** Returns writable pixel address at (x, y). Result is addressable as unsigned
64-bit words. Will trigger an assert() if SkColorType is not
kRGBA_F16_SkColorType and is built with SK_DEBUG defined.
One word corresponds to one pixel.
@param x column index, zero or greater, and less than width()
@param y row index, zero or greater, and less than height()
@return writable unsigned 64-bit pointer to pixel
*/
uint64_t* writable_addr64(int x, int y) const {
return const_cast<uint64_t*>(this->addr64(x, y));
}
/** Returns writable pixel address at (x, y). Result is addressable as unsigned
16-bit words. Will trigger an assert() if SkColorType is not
kRGBA_F16_SkColorType and is built with SK_DEBUG defined.
Each word represents one color component encoded as a half float.
Four words correspond to one pixel.
@param x column index, zero or greater, and less than width()
@param y row index, zero or greater, and less than height()
@return writable unsigned 16-bit pointer to first component of pixel
*/
uint16_t* writable_addrF16(int x, int y) const {
return reinterpret_cast<uint16_t*>(writable_addr64(x, y));
}
/** Copies a SkRect of pixels to dstPixels. Copy starts at (0, 0), and does not
exceed SkPixmap (width(), height()).
dstInfo specifies width, height, SkColorType, SkAlphaType, and
SkColorSpace of destination. dstRowBytes specifics the gap from one destination
row to the next. Returns true if pixels are copied. Returns false if
dstInfo address equals nullptr, or dstRowBytes is less than dstInfo.minRowBytes().
Pixels are copied only if pixel conversion is possible. If SkPixmap colorType() is
kGray_8_SkColorType, or kAlpha_8_SkColorType; dstInfo.colorType() must match.
If SkPixmap colorType() is kGray_8_SkColorType, dstInfo.colorSpace() must match.
If SkPixmap alphaType() is kOpaque_SkAlphaType, dstInfo.alphaType() must
match. If SkPixmap colorSpace() is nullptr, dstInfo.colorSpace() must match. Returns
false if pixel conversion is not possible.
Returns false if SkPixmap width() or height() is zero or negative.
@param dstInfo destination width, height, SkColorType, SkAlphaType, SkColorSpace
@param dstPixels destination pixel storage
@param dstRowBytes destination row length
@return true if pixels are copied to dstPixels
*/
bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes) const {
return this->readPixels(dstInfo, dstPixels, dstRowBytes, 0, 0);
}
/** Copies a SkRect of pixels to dstPixels. Copy starts at (srcX, srcY), and does not
exceed SkPixmap (width(), height()).
dstInfo specifies width, height, SkColorType, SkAlphaType, and
SkColorSpace of destination. dstRowBytes specifics the gap from one destination
row to the next. Returns true if pixels are copied. Returns false if
dstInfo address equals nullptr, or dstRowBytes is less than dstInfo.minRowBytes().
Pixels are copied only if pixel conversion is possible. If SkPixmap colorType() is
kGray_8_SkColorType, or kAlpha_8_SkColorType; dstInfo.colorType() must match.
If SkPixmap colorType() is kGray_8_SkColorType, dstInfo.colorSpace() must match.
If SkPixmap alphaType() is kOpaque_SkAlphaType, dstInfo.alphaType() must
match. If SkPixmap colorSpace() is nullptr, dstInfo.colorSpace() must match. Returns
false if pixel conversion is not possible.
srcX and srcY may be negative to copy only top or left of source. Returns
false if SkPixmap width() or height() is zero or negative. Returns false if:
abs(srcX) >= Pixmap width(), or if abs(srcY) >= Pixmap height().
@param dstInfo destination width, height, SkColorType, SkAlphaType, SkColorSpace
@param dstPixels destination pixel storage
@param dstRowBytes destination row length
@param srcX column index whose absolute value is less than width()
@param srcY row index whose absolute value is less than height()
@return true if pixels are copied to dstPixels
*/
bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, int srcX,
int srcY) const;
/** Copies a SkRect of pixels to dst. Copy starts at (srcX, srcY), and does not
exceed SkPixmap (width(), height()). dst specifies width, height, SkColorType,
SkAlphaType, and SkColorSpace of destination. Returns true if pixels are copied.
Returns false if dst address equals nullptr, or dst.rowBytes() is less than
dst SkImageInfo::minRowBytes.
Pixels are copied only if pixel conversion is possible. If SkPixmap colorType() is
kGray_8_SkColorType, or kAlpha_8_SkColorType; dst.info().colorType must match.
If SkPixmap colorType() is kGray_8_SkColorType, dst.info().colorSpace must match.
If SkPixmap alphaType() is kOpaque_SkAlphaType, dst.info().alphaType must
match. If SkPixmap colorSpace() is nullptr, dst.info().colorSpace must match. Returns
false if pixel conversion is not possible.
srcX and srcY may be negative to copy only top or left of source. Returns
false SkPixmap width() or height() is zero or negative. Returns false if:
abs(srcX) >= Pixmap width(), or if abs(srcY) >= Pixmap height().
@param dst SkImageInfo and pixel address to write to
@param srcX column index whose absolute value is less than width()
@param srcY row index whose absolute value is less than height()
@return true if pixels are copied to dst
*/
bool readPixels(const SkPixmap& dst, int srcX, int srcY) const {
return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), srcX, srcY);
}
/** Copies pixels inside bounds() to dst. dst specifies width, height, SkColorType,
SkAlphaType, and SkColorSpace of destination. Returns true if pixels are copied.
Returns false if dst address equals nullptr, or dst.rowBytes() is less than
dst SkImageInfo::minRowBytes.
Pixels are copied only if pixel conversion is possible. If SkPixmap colorType() is
kGray_8_SkColorType, or kAlpha_8_SkColorType; dst SkColorType must match.
If SkPixmap colorType() is kGray_8_SkColorType, dst SkColorSpace must match.
If SkPixmap alphaType() is kOpaque_SkAlphaType, dst SkAlphaType must
match. If SkPixmap colorSpace() is nullptr, dst SkColorSpace must match. Returns
false if pixel conversion is not possible.
Returns false if SkPixmap width() or height() is zero or negative.
@param dst SkImageInfo and pixel address to write to
@return true if pixels are copied to dst
*/
bool readPixels(const SkPixmap& dst) const {
return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), 0, 0);
}
/** Copies SkBitmap to dst, scaling pixels to fit dst.width() and dst.height(), and
converting pixels to match dst.colorType() and dst.alphaType(). Returns true if
pixels are copied. Returns false if dst address is nullptr, or dst.rowBytes() is
less than dst SkImageInfo::minRowBytes.
Pixels are copied only if pixel conversion is possible. If SkPixmap colorType() is
kGray_8_SkColorType, or kAlpha_8_SkColorType; dst SkColorType must match.
If SkPixmap colorType() is kGray_8_SkColorType, dst SkColorSpace must match.
If SkPixmap alphaType() is kOpaque_SkAlphaType, dst SkAlphaType must
match. If SkPixmap colorSpace() is nullptr, dst SkColorSpace must match. Returns
false if pixel conversion is not possible.
Returns false if SkBitmap width() or height() is zero or negative.
@param dst SkImageInfo and pixel address to write to
@return true if pixels are scaled to fit dst
example: https://fiddle.skia.org/c/@Pixmap_scalePixels
*/
bool scalePixels(const SkPixmap& dst, const SkSamplingOptions&) const;
/** Writes color to pixels bounded by subset; returns true on success.
Returns false if colorType() is kUnknown_SkColorType, or if subset does
not intersect bounds().
@param color sRGB unpremultiplied color to write
@param subset bounding integer SkRect of written pixels
@return true if pixels are changed
example: https://fiddle.skia.org/c/@Pixmap_erase
*/
bool erase(SkColor color, const SkIRect& subset) const;
/** Writes color to pixels inside bounds(); returns true on success.
Returns false if colorType() is kUnknown_SkColorType, or if bounds()
is empty.
@param color sRGB unpremultiplied color to write
@return true if pixels are changed
*/
bool erase(SkColor color) const { return this->erase(color, this->bounds()); }
/** Writes color to pixels bounded by subset; returns true on success.
if subset is nullptr, writes colors pixels inside bounds(). Returns false if
colorType() is kUnknown_SkColorType, if subset is not nullptr and does
not intersect bounds(), or if subset is nullptr and bounds() is empty.
@param color unpremultiplied color to write
@param subset bounding integer SkRect of pixels to write; may be nullptr
@return true if pixels are changed
*/
bool erase(const SkColor4f& color, const SkIRect* subset = nullptr) const;
private:
const void* fPixels;
size_t fRowBytes;
SkImageInfo fInfo;
};
#endif

View File

@ -0,0 +1,10 @@
/*
* Copyright 2023 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
*/
// SkPoint is part of the public API, but is also required by code in base. The following include
// forwarding allows SkPoint to participate in the API and for use by code in base.
#include "include/private/base/SkPoint_impl.h" // IWYU pragma: export

View File

@ -0,0 +1,149 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkPoint3_DEFINED
#define SkPoint3_DEFINED
#include "include/core/SkScalar.h"
#include "include/private/base/SkAPI.h"
#include "include/private/base/SkFloatingPoint.h"
struct SK_API SkPoint3 {
SkScalar fX, fY, fZ;
static SkPoint3 Make(SkScalar x, SkScalar y, SkScalar z) {
SkPoint3 pt;
pt.set(x, y, z);
return pt;
}
SkScalar x() const { return fX; }
SkScalar y() const { return fY; }
SkScalar z() const { return fZ; }
void set(SkScalar x, SkScalar y, SkScalar z) { fX = x; fY = y; fZ = z; }
friend bool operator==(const SkPoint3& a, const SkPoint3& b) {
return a.fX == b.fX && a.fY == b.fY && a.fZ == b.fZ;
}
friend bool operator!=(const SkPoint3& a, const SkPoint3& b) {
return !(a == b);
}
/** Returns the Euclidian distance from (0,0,0) to (x,y,z)
*/
static SkScalar Length(SkScalar x, SkScalar y, SkScalar z);
/** Return the Euclidian distance from (0,0,0) to the point
*/
SkScalar length() const { return SkPoint3::Length(fX, fY, fZ); }
/** Set the point (vector) to be unit-length in the same direction as it
already points. If the point has a degenerate length (i.e., nearly 0)
then set it to (0,0,0) and return false; otherwise return true.
*/
bool normalize();
/** Return a new point whose X, Y and Z coordinates are scaled.
*/
SkPoint3 makeScale(SkScalar scale) const {
SkPoint3 p;
p.set(scale * fX, scale * fY, scale * fZ);
return p;
}
/** Scale the point's coordinates by scale.
*/
void scale(SkScalar value) {
fX *= value;
fY *= value;
fZ *= value;
}
/** Return a new point whose X, Y and Z coordinates are the negative of the
original point's
*/
SkPoint3 operator-() const {
SkPoint3 neg;
neg.fX = -fX;
neg.fY = -fY;
neg.fZ = -fZ;
return neg;
}
/** Returns a new point whose coordinates are the difference between
a and b (i.e., a - b)
*/
friend SkPoint3 operator-(const SkPoint3& a, const SkPoint3& b) {
return { a.fX - b.fX, a.fY - b.fY, a.fZ - b.fZ };
}
/** Returns a new point whose coordinates are the sum of a and b (a + b)
*/
friend SkPoint3 operator+(const SkPoint3& a, const SkPoint3& b) {
return { a.fX + b.fX, a.fY + b.fY, a.fZ + b.fZ };
}
/** Add v's coordinates to the point's
*/
void operator+=(const SkPoint3& v) {
fX += v.fX;
fY += v.fY;
fZ += v.fZ;
}
/** Subtract v's coordinates from the point's
*/
void operator-=(const SkPoint3& v) {
fX -= v.fX;
fY -= v.fY;
fZ -= v.fZ;
}
friend SkPoint3 operator*(SkScalar t, SkPoint3 p) {
return { t * p.fX, t * p.fY, t * p.fZ };
}
/** Returns true if fX, fY, and fZ are measurable values.
@return true for values other than infinities and NaN
*/
bool isFinite() const {
return SkIsFinite(fX, fY, fZ);
}
/** Returns the dot product of a and b, treating them as 3D vectors
*/
static SkScalar DotProduct(const SkPoint3& a, const SkPoint3& b) {
return a.fX * b.fX + a.fY * b.fY + a.fZ * b.fZ;
}
SkScalar dot(const SkPoint3& vec) const {
return DotProduct(*this, vec);
}
/** Returns the cross product of a and b, treating them as 3D vectors
*/
static SkPoint3 CrossProduct(const SkPoint3& a, const SkPoint3& b) {
SkPoint3 result;
result.fX = a.fY*b.fZ - a.fZ*b.fY;
result.fY = a.fZ*b.fX - a.fX*b.fZ;
result.fZ = a.fX*b.fY - a.fY*b.fX;
return result;
}
SkPoint3 cross(const SkPoint3& vec) const {
return CrossProduct(*this, vec);
}
};
typedef SkPoint3 SkVector3;
typedef SkPoint3 SkColor3f;
#endif

View File

@ -0,0 +1,516 @@
/*
* Copyright 2012 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkRRect_DEFINED
#define SkRRect_DEFINED
#include "include/core/SkPoint.h"
#include "include/core/SkRect.h"
#include "include/core/SkScalar.h"
#include "include/core/SkTypes.h"
#include <cstdint>
#include <cstring>
class SkMatrix;
class SkString;
/** \class SkRRect
SkRRect describes a rounded rectangle with a bounds and a pair of radii for each corner.
The bounds and radii can be set so that SkRRect describes: a rectangle with sharp corners;
a circle; an oval; or a rectangle with one or more rounded corners.
SkRRect allows implementing CSS properties that describe rounded corners.
SkRRect may have up to eight different radii, one for each axis on each of its four
corners.
SkRRect may modify the provided parameters when initializing bounds and radii.
If either axis radii is zero or less: radii are stored as zero; corner is square.
If corner curves overlap, radii are proportionally reduced to fit within bounds.
*/
class SK_API SkRRect {
public:
/** Initializes bounds at (0, 0), the origin, with zero width and height.
Initializes corner radii to (0, 0), and sets type of kEmpty_Type.
@return empty SkRRect
*/
SkRRect() = default;
/** Initializes to copy of rrect bounds and corner radii.
@param rrect bounds and corner to copy
@return copy of rrect
*/
SkRRect(const SkRRect& rrect) = default;
/** Copies rrect bounds and corner radii.
@param rrect bounds and corner to copy
@return copy of rrect
*/
SkRRect& operator=(const SkRRect& rrect) = default;
/** \enum SkRRect::Type
Type describes possible specializations of SkRRect. Each Type is
exclusive; a SkRRect may only have one type.
Type members become progressively less restrictive; larger values of
Type have more degrees of freedom than smaller values.
*/
enum Type {
kEmpty_Type, //!< zero width or height
kRect_Type, //!< non-zero width and height, and zeroed radii
kOval_Type, //!< non-zero width and height filled with radii
kSimple_Type, //!< non-zero width and height with equal radii
kNinePatch_Type, //!< non-zero width and height with axis-aligned radii
kComplex_Type, //!< non-zero width and height with arbitrary radii
kLastType = kComplex_Type, //!< largest Type value
};
Type getType() const {
SkASSERT(this->isValid());
return static_cast<Type>(fType);
}
Type type() const { return this->getType(); }
inline bool isEmpty() const { return kEmpty_Type == this->getType(); }
inline bool isRect() const { return kRect_Type == this->getType(); }
inline bool isOval() const { return kOval_Type == this->getType(); }
inline bool isSimple() const { return kSimple_Type == this->getType(); }
inline bool isNinePatch() const { return kNinePatch_Type == this->getType(); }
inline bool isComplex() const { return kComplex_Type == this->getType(); }
/** Returns span on the x-axis. This does not check if result fits in 32-bit float;
result may be infinity.
@return rect().fRight minus rect().fLeft
*/
SkScalar width() const { return fRect.width(); }
/** Returns span on the y-axis. This does not check if result fits in 32-bit float;
result may be infinity.
@return rect().fBottom minus rect().fTop
*/
SkScalar height() const { return fRect.height(); }
/** Returns top-left corner radii. If type() returns kEmpty_Type, kRect_Type,
kOval_Type, or kSimple_Type, returns a value representative of all corner radii.
If type() returns kNinePatch_Type or kComplex_Type, at least one of the
remaining three corners has a different value.
@return corner radii for simple types
*/
SkVector getSimpleRadii() const {
return fRadii[0];
}
/** Sets bounds to zero width and height at (0, 0), the origin. Sets
corner radii to zero and sets type to kEmpty_Type.
*/
void setEmpty() { *this = SkRRect(); }
/** Sets bounds to sorted rect, and sets corner radii to zero.
If set bounds has width and height, and sets type to kRect_Type;
otherwise, sets type to kEmpty_Type.
@param rect bounds to set
*/
void setRect(const SkRect& rect) {
if (!this->initializeRect(rect)) {
return;
}
memset(fRadii, 0, sizeof(fRadii));
fType = kRect_Type;
SkASSERT(this->isValid());
}
/** Initializes bounds at (0, 0), the origin, with zero width and height.
Initializes corner radii to (0, 0), and sets type of kEmpty_Type.
@return empty SkRRect
*/
static SkRRect MakeEmpty() { return SkRRect(); }
/** Initializes to copy of r bounds and zeroes corner radii.
@param r bounds to copy
@return copy of r
*/
static SkRRect MakeRect(const SkRect& r) {
SkRRect rr;
rr.setRect(r);
return rr;
}
/** Sets bounds to oval, x-axis radii to half oval.width(), and all y-axis radii
to half oval.height(). If oval bounds is empty, sets to kEmpty_Type.
Otherwise, sets to kOval_Type.
@param oval bounds of oval
@return oval
*/
static SkRRect MakeOval(const SkRect& oval) {
SkRRect rr;
rr.setOval(oval);
return rr;
}
/** Sets to rounded rectangle with the same radii for all four corners.
If rect is empty, sets to kEmpty_Type.
Otherwise, if xRad and yRad are zero, sets to kRect_Type.
Otherwise, if xRad is at least half rect.width() and yRad is at least half
rect.height(), sets to kOval_Type.
Otherwise, sets to kSimple_Type.
@param rect bounds of rounded rectangle
@param xRad x-axis radius of corners
@param yRad y-axis radius of corners
@return rounded rectangle
*/
static SkRRect MakeRectXY(const SkRect& rect, SkScalar xRad, SkScalar yRad) {
SkRRect rr;
rr.setRectXY(rect, xRad, yRad);
return rr;
}
/** Sets bounds to oval, x-axis radii to half oval.width(), and all y-axis radii
to half oval.height(). If oval bounds is empty, sets to kEmpty_Type.
Otherwise, sets to kOval_Type.
@param oval bounds of oval
*/
void setOval(const SkRect& oval);
/** Sets to rounded rectangle with the same radii for all four corners.
If rect is empty, sets to kEmpty_Type.
Otherwise, if xRad or yRad is zero, sets to kRect_Type.
Otherwise, if xRad is at least half rect.width() and yRad is at least half
rect.height(), sets to kOval_Type.
Otherwise, sets to kSimple_Type.
@param rect bounds of rounded rectangle
@param xRad x-axis radius of corners
@param yRad y-axis radius of corners
example: https://fiddle.skia.org/c/@RRect_setRectXY
*/
void setRectXY(const SkRect& rect, SkScalar xRad, SkScalar yRad);
/** Sets bounds to rect. Sets radii to (leftRad, topRad), (rightRad, topRad),
(rightRad, bottomRad), (leftRad, bottomRad).
If rect is empty, sets to kEmpty_Type.
Otherwise, if leftRad and rightRad are zero, sets to kRect_Type.
Otherwise, if topRad and bottomRad are zero, sets to kRect_Type.
Otherwise, if leftRad and rightRad are equal and at least half rect.width(), and
topRad and bottomRad are equal at least half rect.height(), sets to kOval_Type.
Otherwise, if leftRad and rightRad are equal, and topRad and bottomRad are equal,
sets to kSimple_Type. Otherwise, sets to kNinePatch_Type.
Nine patch refers to the nine parts defined by the radii: one center rectangle,
four edge patches, and four corner patches.
@param rect bounds of rounded rectangle
@param leftRad left-top and left-bottom x-axis radius
@param topRad left-top and right-top y-axis radius
@param rightRad right-top and right-bottom x-axis radius
@param bottomRad left-bottom and right-bottom y-axis radius
*/
void setNinePatch(const SkRect& rect, SkScalar leftRad, SkScalar topRad,
SkScalar rightRad, SkScalar bottomRad);
/** Sets bounds to rect. Sets radii array for individual control of all for corners.
If rect is empty, sets to kEmpty_Type.
Otherwise, if one of each corner radii are zero, sets to kRect_Type.
Otherwise, if all x-axis radii are equal and at least half rect.width(), and
all y-axis radii are equal at least half rect.height(), sets to kOval_Type.
Otherwise, if all x-axis radii are equal, and all y-axis radii are equal,
sets to kSimple_Type. Otherwise, sets to kNinePatch_Type.
@param rect bounds of rounded rectangle
@param radii corner x-axis and y-axis radii
example: https://fiddle.skia.org/c/@RRect_setRectRadii
*/
void setRectRadii(const SkRect& rect, const SkVector radii[4]);
/** \enum SkRRect::Corner
The radii are stored: top-left, top-right, bottom-right, bottom-left.
*/
enum Corner {
kUpperLeft_Corner, //!< index of top-left corner radii
kUpperRight_Corner, //!< index of top-right corner radii
kLowerRight_Corner, //!< index of bottom-right corner radii
kLowerLeft_Corner, //!< index of bottom-left corner radii
};
/** Returns bounds. Bounds may have zero width or zero height. Bounds right is
greater than or equal to left; bounds bottom is greater than or equal to top.
Result is identical to getBounds().
@return bounding box
*/
const SkRect& rect() const { return fRect; }
/** Returns scalar pair for radius of curve on x-axis and y-axis for one corner.
Both radii may be zero. If not zero, both are positive and finite.
@return x-axis and y-axis radii for one corner
*/
SkVector radii(Corner corner) const { return fRadii[corner]; }
/** Returns bounds. Bounds may have zero width or zero height. Bounds right is
greater than or equal to left; bounds bottom is greater than or equal to top.
Result is identical to rect().
@return bounding box
*/
const SkRect& getBounds() const { return fRect; }
/** Returns true if bounds and radii in a are equal to bounds and radii in b.
a and b are not equal if either contain NaN. a and b are equal if members
contain zeroes with different signs.
@param a SkRect bounds and radii to compare
@param b SkRect bounds and radii to compare
@return true if members are equal
*/
friend bool operator==(const SkRRect& a, const SkRRect& b) {
return a.fRect == b.fRect && SkScalarsEqual(&a.fRadii[0].fX, &b.fRadii[0].fX, 8);
}
/** Returns true if bounds and radii in a are not equal to bounds and radii in b.
a and b are not equal if either contain NaN. a and b are equal if members
contain zeroes with different signs.
@param a SkRect bounds and radii to compare
@param b SkRect bounds and radii to compare
@return true if members are not equal
*/
friend bool operator!=(const SkRRect& a, const SkRRect& b) {
return a.fRect != b.fRect || !SkScalarsEqual(&a.fRadii[0].fX, &b.fRadii[0].fX, 8);
}
/** Copies SkRRect to dst, then insets dst bounds by dx and dy, and adjusts dst
radii by dx and dy. dx and dy may be positive, negative, or zero. dst may be
SkRRect.
If either corner radius is zero, the corner has no curvature and is unchanged.
Otherwise, if adjusted radius becomes negative, pins radius to zero.
If dx exceeds half dst bounds width, dst bounds left and right are set to
bounds x-axis center. If dy exceeds half dst bounds height, dst bounds top and
bottom are set to bounds y-axis center.
If dx or dy cause the bounds to become infinite, dst bounds is zeroed.
@param dx added to rect().fLeft, and subtracted from rect().fRight
@param dy added to rect().fTop, and subtracted from rect().fBottom
@param dst insets bounds and radii
example: https://fiddle.skia.org/c/@RRect_inset
*/
void inset(SkScalar dx, SkScalar dy, SkRRect* dst) const;
/** Insets bounds by dx and dy, and adjusts radii by dx and dy. dx and dy may be
positive, negative, or zero.
If either corner radius is zero, the corner has no curvature and is unchanged.
Otherwise, if adjusted radius becomes negative, pins radius to zero.
If dx exceeds half bounds width, bounds left and right are set to
bounds x-axis center. If dy exceeds half bounds height, bounds top and
bottom are set to bounds y-axis center.
If dx or dy cause the bounds to become infinite, bounds is zeroed.
@param dx added to rect().fLeft, and subtracted from rect().fRight
@param dy added to rect().fTop, and subtracted from rect().fBottom
*/
void inset(SkScalar dx, SkScalar dy) {
this->inset(dx, dy, this);
}
/** Outsets dst bounds by dx and dy, and adjusts radii by dx and dy. dx and dy may be
positive, negative, or zero.
If either corner radius is zero, the corner has no curvature and is unchanged.
Otherwise, if adjusted radius becomes negative, pins radius to zero.
If dx exceeds half dst bounds width, dst bounds left and right are set to
bounds x-axis center. If dy exceeds half dst bounds height, dst bounds top and
bottom are set to bounds y-axis center.
If dx or dy cause the bounds to become infinite, dst bounds is zeroed.
@param dx subtracted from rect().fLeft, and added to rect().fRight
@param dy subtracted from rect().fTop, and added to rect().fBottom
@param dst outset bounds and radii
*/
void outset(SkScalar dx, SkScalar dy, SkRRect* dst) const {
this->inset(-dx, -dy, dst);
}
/** Outsets bounds by dx and dy, and adjusts radii by dx and dy. dx and dy may be
positive, negative, or zero.
If either corner radius is zero, the corner has no curvature and is unchanged.
Otherwise, if adjusted radius becomes negative, pins radius to zero.
If dx exceeds half bounds width, bounds left and right are set to
bounds x-axis center. If dy exceeds half bounds height, bounds top and
bottom are set to bounds y-axis center.
If dx or dy cause the bounds to become infinite, bounds is zeroed.
@param dx subtracted from rect().fLeft, and added to rect().fRight
@param dy subtracted from rect().fTop, and added to rect().fBottom
*/
void outset(SkScalar dx, SkScalar dy) {
this->inset(-dx, -dy, this);
}
/** Translates SkRRect by (dx, dy).
@param dx offset added to rect().fLeft and rect().fRight
@param dy offset added to rect().fTop and rect().fBottom
*/
void offset(SkScalar dx, SkScalar dy) {
fRect.offset(dx, dy);
}
/** Returns SkRRect translated by (dx, dy).
@param dx offset added to rect().fLeft and rect().fRight
@param dy offset added to rect().fTop and rect().fBottom
@return SkRRect bounds offset by (dx, dy), with unchanged corner radii
*/
[[nodiscard]] SkRRect makeOffset(SkScalar dx, SkScalar dy) const {
return SkRRect(fRect.makeOffset(dx, dy), fRadii, fType);
}
/** Returns true if rect is inside the bounds and corner radii, and if
SkRRect and rect are not empty.
@param rect area tested for containment
@return true if SkRRect contains rect
example: https://fiddle.skia.org/c/@RRect_contains
*/
bool contains(const SkRect& rect) const;
/** Returns true if bounds and radii values are finite and describe a SkRRect
SkRRect::Type that matches getType(). All SkRRect methods construct valid types,
even if the input values are not valid. Invalid SkRRect data can only
be generated by corrupting memory.
@return true if bounds and radii match type()
example: https://fiddle.skia.org/c/@RRect_isValid
*/
bool isValid() const;
static constexpr size_t kSizeInMemory = 12 * sizeof(SkScalar);
/** Writes SkRRect to buffer. Writes kSizeInMemory bytes, and returns
kSizeInMemory, the number of bytes written.
@param buffer storage for SkRRect
@return bytes written, kSizeInMemory
example: https://fiddle.skia.org/c/@RRect_writeToMemory
*/
size_t writeToMemory(void* buffer) const;
/** Reads SkRRect from buffer, reading kSizeInMemory bytes.
Returns kSizeInMemory, bytes read if length is at least kSizeInMemory.
Otherwise, returns zero.
@param buffer memory to read from
@param length size of buffer
@return bytes read, or 0 if length is less than kSizeInMemory
example: https://fiddle.skia.org/c/@RRect_readFromMemory
*/
size_t readFromMemory(const void* buffer, size_t length);
/** Transforms by SkRRect by matrix, storing result in dst.
Returns true if SkRRect transformed can be represented by another SkRRect.
Returns false if matrix contains transformations that are not axis aligned.
Asserts in debug builds if SkRRect equals dst.
@param matrix SkMatrix specifying the transform
@param dst SkRRect to store the result
@return true if transformation succeeded.
example: https://fiddle.skia.org/c/@RRect_transform
*/
bool transform(const SkMatrix& matrix, SkRRect* dst) const;
/** Writes text representation of SkRRect to standard output.
Set asHex true to generate exact binary representations
of floating point numbers.
@param asHex true if SkScalar values are written as hexadecimal
example: https://fiddle.skia.org/c/@RRect_dump
*/
void dump(bool asHex) const;
SkString dumpToString(bool asHex) const;
/** Writes text representation of SkRRect to standard output. The representation
may be directly compiled as C++ code. Floating point values are written
with limited precision; it may not be possible to reconstruct original
SkRRect from output.
*/
void dump() const { this->dump(false); }
/** Writes text representation of SkRRect to standard output. The representation
may be directly compiled as C++ code. Floating point values are written
in hexadecimal to preserve their exact bit pattern. The output reconstructs the
original SkRRect.
*/
void dumpHex() const { this->dump(true); }
private:
static bool AreRectAndRadiiValid(const SkRect&, const SkVector[4]);
SkRRect(const SkRect& rect, const SkVector radii[4], int32_t type)
: fRect(rect)
, fRadii{radii[0], radii[1], radii[2], radii[3]}
, fType(type) {}
/**
* Initializes fRect. If the passed in rect is not finite or empty the rrect will be fully
* initialized and false is returned. Otherwise, just fRect is initialized and true is returned.
*/
bool initializeRect(const SkRect&);
void computeType();
bool checkCornerContainment(SkScalar x, SkScalar y) const;
// Returns true if the radii had to be scaled to fit rect
bool scaleRadii();
SkRect fRect = SkRect::MakeEmpty();
// Radii order is UL, UR, LR, LL. Use Corner enum to index into fRadii[]
SkVector fRadii[4] = {{0, 0}, {0, 0}, {0,0}, {0,0}};
// use an explicitly sized type so we're sure the class is dense (no uninitialized bytes)
int32_t fType = kEmpty_Type;
// TODO: add padding so we can use memcpy for flattening and not copy uninitialized data
// to access fRadii directly
friend class SkPath;
friend class SkRRectPriv;
};
#endif

View File

@ -0,0 +1,71 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkRSXform_DEFINED
#define SkRSXform_DEFINED
#include "include/core/SkPoint.h"
#include "include/core/SkScalar.h"
#include "include/core/SkSize.h"
#include "include/private/base/SkAPI.h"
/**
* A compressed form of a rotation+scale matrix.
*
* [ fSCos -fSSin fTx ]
* [ fSSin fSCos fTy ]
* [ 0 0 1 ]
*/
struct SK_API SkRSXform {
static SkRSXform Make(SkScalar scos, SkScalar ssin, SkScalar tx, SkScalar ty) {
SkRSXform xform = { scos, ssin, tx, ty };
return xform;
}
/*
* Initialize a new xform based on the scale, rotation (in radians), final tx,ty location
* and anchor-point ax,ay within the src quad.
*
* Note: the anchor point is not normalized (e.g. 0...1) but is in pixels of the src image.
*/
static SkRSXform MakeFromRadians(SkScalar scale, SkScalar radians, SkScalar tx, SkScalar ty,
SkScalar ax, SkScalar ay) {
const SkScalar s = SkScalarSin(radians) * scale;
const SkScalar c = SkScalarCos(radians) * scale;
return Make(c, s, tx + -c * ax + s * ay, ty + -s * ax - c * ay);
}
SkScalar fSCos;
SkScalar fSSin;
SkScalar fTx;
SkScalar fTy;
bool rectStaysRect() const {
return 0 == fSCos || 0 == fSSin;
}
void setIdentity() {
fSCos = 1;
fSSin = fTx = fTy = 0;
}
void set(SkScalar scos, SkScalar ssin, SkScalar tx, SkScalar ty) {
fSCos = scos;
fSSin = ssin;
fTx = tx;
fTy = ty;
}
void toQuad(SkScalar width, SkScalar height, SkPoint quad[4]) const;
void toQuad(const SkSize& size, SkPoint quad[4]) const {
this->toQuad(size.width(), size.height(), quad);
}
void toTriStrip(SkScalar width, SkScalar height, SkPoint strip[4]) const;
};
#endif

View File

@ -0,0 +1,94 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkRasterHandleAllocator_DEFINED
#define SkRasterHandleAllocator_DEFINED
#include "include/core/SkImageInfo.h"
class SkBitmap;
class SkCanvas;
class SkMatrix;
class SkSurfaceProps;
/**
* If a client wants to control the allocation of raster layers in a canvas, it should subclass
* SkRasterHandleAllocator. This allocator performs two tasks:
* 1. controls how the memory for the pixels is allocated
* 2. associates a "handle" to a private object that can track the matrix/clip of the SkCanvas
*
* This example allocates a canvas, and defers to the allocator to create the base layer.
*
* std::unique_ptr<SkCanvas> canvas = SkRasterHandleAllocator::MakeCanvas(
* SkImageInfo::Make(...),
* std::make_unique<MySubclassRasterHandleAllocator>(...),
* nullptr);
*
* If you have already allocated the base layer (and its handle, release-proc etc.) then you
* can pass those in using the last parameter to MakeCanvas().
*
* Regardless of how the base layer is allocated, each time canvas->saveLayer() is called,
* your allocator's allocHandle() will be called.
*/
class SK_API SkRasterHandleAllocator {
public:
virtual ~SkRasterHandleAllocator() = default;
// The value that is returned to clients of the canvas that has this allocator installed.
typedef void* Handle;
struct Rec {
// When the allocation goes out of scope, this proc is called to free everything associated
// with it: the pixels, the "handle", etc. This is passed the pixel address and fReleaseCtx.
void (*fReleaseProc)(void* pixels, void* ctx);
void* fReleaseCtx; // context passed to fReleaseProc
void* fPixels; // pixels for this allocation
size_t fRowBytes; // rowbytes for these pixels
Handle fHandle; // public handle returned by SkCanvas::accessTopRasterHandle()
};
/**
* Given a requested info, allocate the corresponding pixels/rowbytes, and whatever handle
* is desired to give clients access to those pixels. The rec also contains a proc and context
* which will be called when this allocation goes out of scope.
*
* e.g.
* when canvas->saveLayer() is called, the allocator will be called to allocate the pixels
* for the layer. When canvas->restore() is called, the fReleaseProc will be called.
*/
virtual bool allocHandle(const SkImageInfo&, Rec*) = 0;
/**
* Clients access the handle for a given layer by calling SkCanvas::accessTopRasterHandle().
* To allow the handle to reflect the current matrix/clip in the canvs, updateHandle() is
* is called. The subclass is responsible to update the handle as it sees fit.
*/
virtual void updateHandle(Handle, const SkMatrix&, const SkIRect&) = 0;
/**
* This creates a canvas which will use the allocator to manage pixel allocations, including
* all calls to saveLayer().
*
* If rec is non-null, then it will be used as the base-layer of pixels/handle.
* If rec is null, then the allocator will be called for the base-layer as well.
*/
static std::unique_ptr<SkCanvas> MakeCanvas(std::unique_ptr<SkRasterHandleAllocator>,
const SkImageInfo&, const Rec* rec = nullptr,
const SkSurfaceProps* props = nullptr);
protected:
SkRasterHandleAllocator() = default;
SkRasterHandleAllocator(const SkRasterHandleAllocator&) = delete;
SkRasterHandleAllocator& operator=(const SkRasterHandleAllocator&) = delete;
private:
friend class SkBitmapDevice;
Handle allocBitmap(const SkImageInfo&, SkBitmap*);
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,389 @@
/*
* Copyright 2006 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkRefCnt_DEFINED
#define SkRefCnt_DEFINED
#include "include/core/SkTypes.h"
#include "include/private/base/SkDebug.h"
#include <atomic>
#include <cstddef>
#include <cstdint>
#include <iosfwd>
#include <type_traits>
#include <utility>
/** \class SkRefCntBase
SkRefCntBase is the base class for objects that may be shared by multiple
objects. When an existing owner wants to share a reference, it calls ref().
When an owner wants to release its reference, it calls unref(). When the
shared object's reference count goes to zero as the result of an unref()
call, its (virtual) destructor is called. It is an error for the
destructor to be called explicitly (or via the object going out of scope on
the stack or calling delete) if getRefCnt() > 1.
*/
class SK_API SkRefCntBase {
public:
/** Default construct, initializing the reference count to 1.
*/
SkRefCntBase() : fRefCnt(1) {}
/** Destruct, asserting that the reference count is 1.
*/
virtual ~SkRefCntBase() {
#ifdef SK_DEBUG
SkASSERTF(this->getRefCnt() == 1, "fRefCnt was %d", this->getRefCnt());
// illegal value, to catch us if we reuse after delete
fRefCnt.store(0, std::memory_order_relaxed);
#endif
}
/** May return true if the caller is the only owner.
* Ensures that all previous owner's actions are complete.
*/
bool unique() const {
if (1 == fRefCnt.load(std::memory_order_acquire)) {
// The acquire barrier is only really needed if we return true. It
// prevents code conditioned on the result of unique() from running
// until previous owners are all totally done calling unref().
return true;
}
return false;
}
/** Increment the reference count. Must be balanced by a call to unref().
*/
void ref() const {
SkASSERT(this->getRefCnt() > 0);
// No barrier required.
(void)fRefCnt.fetch_add(+1, std::memory_order_relaxed);
}
/** Decrement the reference count. If the reference count is 1 before the
decrement, then delete the object. Note that if this is the case, then
the object needs to have been allocated via new, and not on the stack.
*/
void unref() const {
SkASSERT(this->getRefCnt() > 0);
// A release here acts in place of all releases we "should" have been doing in ref().
if (1 == fRefCnt.fetch_add(-1, std::memory_order_acq_rel)) {
// Like unique(), the acquire is only needed on success, to make sure
// code in internal_dispose() doesn't happen before the decrement.
this->internal_dispose();
}
}
private:
#ifdef SK_DEBUG
/** Return the reference count. Use only for debugging. */
int32_t getRefCnt() const {
return fRefCnt.load(std::memory_order_relaxed);
}
#endif
/**
* Called when the ref count goes to 0.
*/
virtual void internal_dispose() const {
#ifdef SK_DEBUG
SkASSERT(0 == this->getRefCnt());
fRefCnt.store(1, std::memory_order_relaxed);
#endif
delete this;
}
// The following friends are those which override internal_dispose()
// and conditionally call SkRefCnt::internal_dispose().
friend class SkWeakRefCnt;
mutable std::atomic<int32_t> fRefCnt;
SkRefCntBase(SkRefCntBase&&) = delete;
SkRefCntBase(const SkRefCntBase&) = delete;
SkRefCntBase& operator=(SkRefCntBase&&) = delete;
SkRefCntBase& operator=(const SkRefCntBase&) = delete;
};
#ifdef SK_REF_CNT_MIXIN_INCLUDE
// It is the responsibility of the following include to define the type SkRefCnt.
// This SkRefCnt should normally derive from SkRefCntBase.
#include SK_REF_CNT_MIXIN_INCLUDE
#else
class SK_API SkRefCnt : public SkRefCntBase {
// "#include SK_REF_CNT_MIXIN_INCLUDE" doesn't work with this build system.
#if defined(SK_BUILD_FOR_GOOGLE3)
public:
void deref() const { this->unref(); }
#endif
};
#endif
///////////////////////////////////////////////////////////////////////////////
/** Call obj->ref() and return obj. The obj must not be nullptr.
*/
template <typename T> static inline T* SkRef(T* obj) {
SkASSERT(obj);
obj->ref();
return obj;
}
/** Check if the argument is non-null, and if so, call obj->ref() and return obj.
*/
template <typename T> static inline T* SkSafeRef(T* obj) {
if (obj) {
obj->ref();
}
return obj;
}
/** Check if the argument is non-null, and if so, call obj->unref()
*/
template <typename T> static inline void SkSafeUnref(T* obj) {
if (obj) {
obj->unref();
}
}
///////////////////////////////////////////////////////////////////////////////
// This is a variant of SkRefCnt that's Not Virtual, so weighs 4 bytes instead of 8 or 16.
// There's only benefit to using this if the deriving class does not otherwise need a vtable.
template <typename Derived>
class SkNVRefCnt {
public:
SkNVRefCnt() : fRefCnt(1) {}
~SkNVRefCnt() {
#ifdef SK_DEBUG
int rc = fRefCnt.load(std::memory_order_relaxed);
SkASSERTF(rc == 1, "NVRefCnt was %d", rc);
#endif
}
// Implementation is pretty much the same as SkRefCntBase. All required barriers are the same:
// - unique() needs acquire when it returns true, and no barrier if it returns false;
// - ref() doesn't need any barrier;
// - unref() needs a release barrier, and an acquire if it's going to call delete.
bool unique() const { return 1 == fRefCnt.load(std::memory_order_acquire); }
void ref() const { (void)fRefCnt.fetch_add(+1, std::memory_order_relaxed); }
void unref() const {
if (1 == fRefCnt.fetch_add(-1, std::memory_order_acq_rel)) {
// restore the 1 for our destructor's assert
SkDEBUGCODE(fRefCnt.store(1, std::memory_order_relaxed));
delete (const Derived*)this;
}
}
void deref() const { this->unref(); }
// This must be used with caution. It is only valid to call this when 'threadIsolatedTestCnt'
// refs are known to be isolated to the current thread. That is, it is known that there are at
// least 'threadIsolatedTestCnt' refs for which no other thread may make a balancing unref()
// call. Assuming the contract is followed, if this returns false then no other thread has
// ownership of this. If it returns true then another thread *may* have ownership.
bool refCntGreaterThan(int32_t threadIsolatedTestCnt) const {
int cnt = fRefCnt.load(std::memory_order_acquire);
// If this fails then the above contract has been violated.
SkASSERT(cnt >= threadIsolatedTestCnt);
return cnt > threadIsolatedTestCnt;
}
private:
mutable std::atomic<int32_t> fRefCnt;
SkNVRefCnt(SkNVRefCnt&&) = delete;
SkNVRefCnt(const SkNVRefCnt&) = delete;
SkNVRefCnt& operator=(SkNVRefCnt&&) = delete;
SkNVRefCnt& operator=(const SkNVRefCnt&) = delete;
};
///////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Shared pointer class to wrap classes that support a ref()/unref() interface.
*
* This can be used for classes inheriting from SkRefCnt, but it also works for other
* classes that match the interface, but have different internal choices: e.g. the hosted class
* may have its ref/unref be thread-safe, but that is not assumed/imposed by sk_sp.
*
* Declared with the trivial_abi attribute where supported so that sk_sp and types containing it
* may be considered as trivially relocatable by the compiler so that destroying-move operations
* i.e. move constructor followed by destructor can be optimized to memcpy.
*/
template <typename T> class SK_TRIVIAL_ABI sk_sp {
public:
using element_type = T;
constexpr sk_sp() : fPtr(nullptr) {}
constexpr sk_sp(std::nullptr_t) : fPtr(nullptr) {}
/**
* Shares the underlying object by calling ref(), so that both the argument and the newly
* created sk_sp both have a reference to it.
*/
sk_sp(const sk_sp<T>& that) : fPtr(SkSafeRef(that.get())) {}
template <typename U,
typename = typename std::enable_if<std::is_convertible<U*, T*>::value>::type>
sk_sp(const sk_sp<U>& that) : fPtr(SkSafeRef(that.get())) {}
/**
* Move the underlying object from the argument to the newly created sk_sp. Afterwards only
* the new sk_sp will have a reference to the object, and the argument will point to null.
* No call to ref() or unref() will be made.
*/
sk_sp(sk_sp<T>&& that) : fPtr(that.release()) {}
template <typename U,
typename = typename std::enable_if<std::is_convertible<U*, T*>::value>::type>
sk_sp(sk_sp<U>&& that) : fPtr(that.release()) {}
/**
* Adopt the bare pointer into the newly created sk_sp.
* No call to ref() or unref() will be made.
*/
explicit sk_sp(T* obj) : fPtr(obj) {}
/**
* Calls unref() on the underlying object pointer.
*/
~sk_sp() {
SkSafeUnref(fPtr);
SkDEBUGCODE(fPtr = nullptr);
}
sk_sp<T>& operator=(std::nullptr_t) { this->reset(); return *this; }
/**
* Shares the underlying object referenced by the argument by calling ref() on it. If this
* sk_sp previously had a reference to an object (i.e. not null) it will call unref() on that
* object.
*/
sk_sp<T>& operator=(const sk_sp<T>& that) {
if (this != &that) {
this->reset(SkSafeRef(that.get()));
}
return *this;
}
template <typename U,
typename = typename std::enable_if<std::is_convertible<U*, T*>::value>::type>
sk_sp<T>& operator=(const sk_sp<U>& that) {
this->reset(SkSafeRef(that.get()));
return *this;
}
/**
* Move the underlying object from the argument to the sk_sp. If the sk_sp previously held
* a reference to another object, unref() will be called on that object. No call to ref()
* will be made.
*/
sk_sp<T>& operator=(sk_sp<T>&& that) {
this->reset(that.release());
return *this;
}
template <typename U,
typename = typename std::enable_if<std::is_convertible<U*, T*>::value>::type>
sk_sp<T>& operator=(sk_sp<U>&& that) {
this->reset(that.release());
return *this;
}
T& operator*() const {
SkASSERT(this->get() != nullptr);
return *this->get();
}
explicit operator bool() const { return this->get() != nullptr; }
T* get() const { return fPtr; }
T* operator->() const { return fPtr; }
/**
* Adopt the new bare pointer, and call unref() on any previously held object (if not null).
* No call to ref() will be made.
*/
void reset(T* ptr = nullptr) {
// Calling fPtr->unref() may call this->~() or this->reset(T*).
// http://wg21.cmeerw.net/lwg/issue998
// http://wg21.cmeerw.net/lwg/issue2262
T* oldPtr = fPtr;
fPtr = ptr;
SkSafeUnref(oldPtr);
}
/**
* Return the bare pointer, and set the internal object pointer to nullptr.
* The caller must assume ownership of the object, and manage its reference count directly.
* No call to unref() will be made.
*/
[[nodiscard]] T* release() {
T* ptr = fPtr;
fPtr = nullptr;
return ptr;
}
void swap(sk_sp<T>& that) /*noexcept*/ {
using std::swap;
swap(fPtr, that.fPtr);
}
using sk_is_trivially_relocatable = std::true_type;
private:
T* fPtr;
};
template <typename T> inline void swap(sk_sp<T>& a, sk_sp<T>& b) /*noexcept*/ {
a.swap(b);
}
template <typename T, typename U> inline bool operator==(const sk_sp<T>& a, const sk_sp<U>& b) {
return a.get() == b.get();
}
template <typename T> inline bool operator==(const sk_sp<T>& a, std::nullptr_t) /*noexcept*/ {
return !a;
}
template <typename T> inline bool operator==(std::nullptr_t, const sk_sp<T>& b) /*noexcept*/ {
return !b;
}
template <typename T, typename U> inline bool operator!=(const sk_sp<T>& a, const sk_sp<U>& b) {
return a.get() != b.get();
}
template <typename T> inline bool operator!=(const sk_sp<T>& a, std::nullptr_t) /*noexcept*/ {
return static_cast<bool>(a);
}
template <typename T> inline bool operator!=(std::nullptr_t, const sk_sp<T>& b) /*noexcept*/ {
return static_cast<bool>(b);
}
template <typename C, typename CT, typename T>
auto operator<<(std::basic_ostream<C, CT>& os, const sk_sp<T>& sp) -> decltype(os << sp.get()) {
return os << sp.get();
}
template <typename T, typename... Args>
sk_sp<T> sk_make_sp(Args&&... args) {
return sk_sp<T>(new T(std::forward<Args>(args)...));
}
/*
* Returns a sk_sp wrapping the provided ptr AND calls ref on it (if not null).
*
* This is different than the semantics of the constructor for sk_sp, which just wraps the ptr,
* effectively "adopting" it.
*/
template <typename T> sk_sp<T> sk_ref_sp(T* obj) {
return sk_sp<T>(SkSafeRef(obj));
}
template <typename T> sk_sp<T> sk_ref_sp(const T* obj) {
return sk_sp<T>(const_cast<T*>(SkSafeRef(obj)));
}
#endif

View File

@ -0,0 +1,684 @@
/*
* Copyright 2005 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkRegion_DEFINED
#define SkRegion_DEFINED
#include "include/core/SkRect.h"
#include "include/private/base/SkAPI.h"
#include "include/private/base/SkAssert.h"
#include "include/private/base/SkDebug.h"
#include "include/private/base/SkTypeTraits.h"
#include <cstddef>
#include <cstdint>
#include <type_traits>
class SkPath;
/** \class SkRegion
SkRegion describes the set of pixels used to clip SkCanvas. SkRegion is compact,
efficiently storing a single integer rectangle, or a run length encoded array
of rectangles. SkRegion may reduce the current SkCanvas clip, or may be drawn as
one or more integer rectangles. SkRegion iterator returns the scan lines or
rectangles contained by it, optionally intersecting a bounding rectangle.
*/
class SK_API SkRegion {
typedef int32_t RunType;
public:
/** Constructs an empty SkRegion. SkRegion is set to empty bounds
at (0, 0) with zero width and height.
@return empty SkRegion
example: https://fiddle.skia.org/c/@Region_empty_constructor
*/
SkRegion();
/** Constructs a copy of an existing region.
Copy constructor makes two regions identical by value. Internally, region and
the returned result share pointer values. The underlying SkRect array is
copied when modified.
Creating a SkRegion copy is very efficient and never allocates memory.
SkRegion are always copied by value from the interface; the underlying shared
pointers are not exposed.
@param region SkRegion to copy by value
@return copy of SkRegion
example: https://fiddle.skia.org/c/@Region_copy_const_SkRegion
*/
SkRegion(const SkRegion& region);
/** Constructs a rectangular SkRegion matching the bounds of rect.
@param rect bounds of constructed SkRegion
@return rectangular SkRegion
example: https://fiddle.skia.org/c/@Region_copy_const_SkIRect
*/
explicit SkRegion(const SkIRect& rect);
/** Releases ownership of any shared data and deletes data if SkRegion is sole owner.
example: https://fiddle.skia.org/c/@Region_destructor
*/
~SkRegion();
/** Constructs a copy of an existing region.
Makes two regions identical by value. Internally, region and
the returned result share pointer values. The underlying SkRect array is
copied when modified.
Creating a SkRegion copy is very efficient and never allocates memory.
SkRegion are always copied by value from the interface; the underlying shared
pointers are not exposed.
@param region SkRegion to copy by value
@return SkRegion to copy by value
example: https://fiddle.skia.org/c/@Region_copy_operator
*/
SkRegion& operator=(const SkRegion& region);
/** Compares SkRegion and other; returns true if they enclose exactly
the same area.
@param other SkRegion to compare
@return true if SkRegion pair are equivalent
example: https://fiddle.skia.org/c/@Region_equal1_operator
*/
bool operator==(const SkRegion& other) const;
/** Compares SkRegion and other; returns true if they do not enclose the same area.
@param other SkRegion to compare
@return true if SkRegion pair are not equivalent
*/
bool operator!=(const SkRegion& other) const {
return !(*this == other);
}
/** Sets SkRegion to src, and returns true if src bounds is not empty.
This makes SkRegion and src identical by value. Internally,
SkRegion and src share pointer values. The underlying SkRect array is
copied when modified.
Creating a SkRegion copy is very efficient and never allocates memory.
SkRegion are always copied by value from the interface; the underlying shared
pointers are not exposed.
@param src SkRegion to copy
@return copy of src
*/
bool set(const SkRegion& src) {
*this = src;
return !this->isEmpty();
}
/** Exchanges SkIRect array of SkRegion and other. swap() internally exchanges pointers,
so it is lightweight and does not allocate memory.
swap() usage has largely been replaced by operator=(const SkRegion& region).
SkPath do not copy their content on assignment until they are written to,
making assignment as efficient as swap().
@param other operator=(const SkRegion& region) set
example: https://fiddle.skia.org/c/@Region_swap
*/
void swap(SkRegion& other);
/** Returns true if SkRegion is empty.
Empty SkRegion has bounds width or height less than or equal to zero.
SkRegion() constructs empty SkRegion; setEmpty()
and setRect() with dimensionless data make SkRegion empty.
@return true if bounds has no width or height
*/
bool isEmpty() const { return fRunHead == emptyRunHeadPtr(); }
/** Returns true if SkRegion is one SkIRect with positive dimensions.
@return true if SkRegion contains one SkIRect
*/
bool isRect() const { return fRunHead == kRectRunHeadPtr; }
/** Returns true if SkRegion is described by more than one rectangle.
@return true if SkRegion contains more than one SkIRect
*/
bool isComplex() const { return !this->isEmpty() && !this->isRect(); }
/** Returns minimum and maximum axes values of SkIRect array.
Returns (0, 0, 0, 0) if SkRegion is empty.
@return combined bounds of all SkIRect elements
*/
const SkIRect& getBounds() const { return fBounds; }
/** Returns a value that increases with the number of
elements in SkRegion. Returns zero if SkRegion is empty.
Returns one if SkRegion equals SkIRect; otherwise, returns
value greater than one indicating that SkRegion is complex.
Call to compare SkRegion for relative complexity.
@return relative complexity
example: https://fiddle.skia.org/c/@Region_computeRegionComplexity
*/
int computeRegionComplexity() const;
/** Appends outline of SkRegion to path.
Returns true if SkRegion is not empty; otherwise, returns false, and leaves path
unmodified.
@param path SkPath to append to
@return true if path changed
example: https://fiddle.skia.org/c/@Region_getBoundaryPath
*/
bool getBoundaryPath(SkPath* path) const;
/** Constructs an empty SkRegion. SkRegion is set to empty bounds
at (0, 0) with zero width and height. Always returns false.
@return false
example: https://fiddle.skia.org/c/@Region_setEmpty
*/
bool setEmpty();
/** Constructs a rectangular SkRegion matching the bounds of rect.
If rect is empty, constructs empty and returns false.
@param rect bounds of constructed SkRegion
@return true if rect is not empty
example: https://fiddle.skia.org/c/@Region_setRect
*/
bool setRect(const SkIRect& rect);
/** Constructs SkRegion as the union of SkIRect in rects array. If count is
zero, constructs empty SkRegion. Returns false if constructed SkRegion is empty.
May be faster than repeated calls to op().
@param rects array of SkIRect
@param count array size
@return true if constructed SkRegion is not empty
example: https://fiddle.skia.org/c/@Region_setRects
*/
bool setRects(const SkIRect rects[], int count);
/** Constructs a copy of an existing region.
Makes two regions identical by value. Internally, region and
the returned result share pointer values. The underlying SkRect array is
copied when modified.
Creating a SkRegion copy is very efficient and never allocates memory.
SkRegion are always copied by value from the interface; the underlying shared
pointers are not exposed.
@param region SkRegion to copy by value
@return SkRegion to copy by value
example: https://fiddle.skia.org/c/@Region_setRegion
*/
bool setRegion(const SkRegion& region);
/** Constructs SkRegion to match outline of path within clip.
Returns false if constructed SkRegion is empty.
Constructed SkRegion draws the same pixels as path through clip when
anti-aliasing is disabled.
@param path SkPath providing outline
@param clip SkRegion containing path
@return true if constructed SkRegion is not empty
example: https://fiddle.skia.org/c/@Region_setPath
*/
bool setPath(const SkPath& path, const SkRegion& clip);
/** Returns true if SkRegion intersects rect.
Returns false if either rect or SkRegion is empty, or do not intersect.
@param rect SkIRect to intersect
@return true if rect and SkRegion have area in common
example: https://fiddle.skia.org/c/@Region_intersects
*/
bool intersects(const SkIRect& rect) const;
/** Returns true if SkRegion intersects other.
Returns false if either other or SkRegion is empty, or do not intersect.
@param other SkRegion to intersect
@return true if other and SkRegion have area in common
example: https://fiddle.skia.org/c/@Region_intersects_2
*/
bool intersects(const SkRegion& other) const;
/** Returns true if SkIPoint (x, y) is inside SkRegion.
Returns false if SkRegion is empty.
@param x test SkIPoint x-coordinate
@param y test SkIPoint y-coordinate
@return true if (x, y) is inside SkRegion
example: https://fiddle.skia.org/c/@Region_contains
*/
bool contains(int32_t x, int32_t y) const;
/** Returns true if other is completely inside SkRegion.
Returns false if SkRegion or other is empty.
@param other SkIRect to contain
@return true if other is inside SkRegion
example: https://fiddle.skia.org/c/@Region_contains_2
*/
bool contains(const SkIRect& other) const;
/** Returns true if other is completely inside SkRegion.
Returns false if SkRegion or other is empty.
@param other SkRegion to contain
@return true if other is inside SkRegion
example: https://fiddle.skia.org/c/@Region_contains_3
*/
bool contains(const SkRegion& other) const;
/** Returns true if SkRegion is a single rectangle and contains r.
May return false even though SkRegion contains r.
@param r SkIRect to contain
@return true quickly if r points are equal or inside
*/
bool quickContains(const SkIRect& r) const {
SkASSERT(this->isEmpty() == fBounds.isEmpty()); // valid region
return r.fLeft < r.fRight && r.fTop < r.fBottom &&
fRunHead == kRectRunHeadPtr && // this->isRect()
/* fBounds.contains(left, top, right, bottom); */
fBounds.fLeft <= r.fLeft && fBounds.fTop <= r.fTop &&
fBounds.fRight >= r.fRight && fBounds.fBottom >= r.fBottom;
}
/** Returns true if SkRegion does not intersect rect.
Returns true if rect is empty or SkRegion is empty.
May return false even though SkRegion does not intersect rect.
@param rect SkIRect to intersect
@return true if rect does not intersect
*/
bool quickReject(const SkIRect& rect) const {
return this->isEmpty() || rect.isEmpty() ||
!SkIRect::Intersects(fBounds, rect);
}
/** Returns true if SkRegion does not intersect rgn.
Returns true if rgn is empty or SkRegion is empty.
May return false even though SkRegion does not intersect rgn.
@param rgn SkRegion to intersect
@return true if rgn does not intersect
*/
bool quickReject(const SkRegion& rgn) const {
return this->isEmpty() || rgn.isEmpty() ||
!SkIRect::Intersects(fBounds, rgn.fBounds);
}
/** Offsets SkRegion by ivector (dx, dy). Has no effect if SkRegion is empty.
@param dx x-axis offset
@param dy y-axis offset
*/
void translate(int dx, int dy) { this->translate(dx, dy, this); }
/** Offsets SkRegion by ivector (dx, dy), writing result to dst. SkRegion may be passed
as dst parameter, translating SkRegion in place. Has no effect if dst is nullptr.
If SkRegion is empty, sets dst to empty.
@param dx x-axis offset
@param dy y-axis offset
@param dst translated result
example: https://fiddle.skia.org/c/@Region_translate_2
*/
void translate(int dx, int dy, SkRegion* dst) const;
/** \enum SkRegion::Op
The logical operations that can be performed when combining two SkRegion.
*/
enum Op {
kDifference_Op, //!< target minus operand
kIntersect_Op, //!< target intersected with operand
kUnion_Op, //!< target unioned with operand
kXOR_Op, //!< target exclusive or with operand
kReverseDifference_Op, //!< operand minus target
kReplace_Op, //!< replace target with operand
kLastOp = kReplace_Op, //!< last operator
};
static const int kOpCnt = kLastOp + 1;
/** Replaces SkRegion with the result of SkRegion op rect.
Returns true if replaced SkRegion is not empty.
@param rect SkIRect operand
@return false if result is empty
*/
bool op(const SkIRect& rect, Op op) {
if (this->isRect() && kIntersect_Op == op) {
if (!fBounds.intersect(rect)) {
return this->setEmpty();
}
return true;
}
return this->op(*this, rect, op);
}
/** Replaces SkRegion with the result of SkRegion op rgn.
Returns true if replaced SkRegion is not empty.
@param rgn SkRegion operand
@return false if result is empty
*/
bool op(const SkRegion& rgn, Op op) { return this->op(*this, rgn, op); }
/** Replaces SkRegion with the result of rect op rgn.
Returns true if replaced SkRegion is not empty.
@param rect SkIRect operand
@param rgn SkRegion operand
@return false if result is empty
example: https://fiddle.skia.org/c/@Region_op_4
*/
bool op(const SkIRect& rect, const SkRegion& rgn, Op op);
/** Replaces SkRegion with the result of rgn op rect.
Returns true if replaced SkRegion is not empty.
@param rgn SkRegion operand
@param rect SkIRect operand
@return false if result is empty
example: https://fiddle.skia.org/c/@Region_op_5
*/
bool op(const SkRegion& rgn, const SkIRect& rect, Op op);
/** Replaces SkRegion with the result of rgna op rgnb.
Returns true if replaced SkRegion is not empty.
@param rgna SkRegion operand
@param rgnb SkRegion operand
@return false if result is empty
example: https://fiddle.skia.org/c/@Region_op_6
*/
bool op(const SkRegion& rgna, const SkRegion& rgnb, Op op);
#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
/** Private. Android framework only.
@return string representation of SkRegion
*/
char* toString();
#endif
/** \class SkRegion::Iterator
Returns sequence of rectangles, sorted along y-axis, then x-axis, that make
up SkRegion.
*/
class SK_API Iterator {
public:
/** Initializes SkRegion::Iterator with an empty SkRegion. done() on SkRegion::Iterator
returns true.
Call reset() to initialized SkRegion::Iterator at a later time.
@return empty SkRegion iterator
*/
Iterator() : fRgn(nullptr), fDone(true) {}
/** Sets SkRegion::Iterator to return elements of SkIRect array in region.
@param region SkRegion to iterate
@return SkRegion iterator
example: https://fiddle.skia.org/c/@Region_Iterator_copy_const_SkRegion
*/
Iterator(const SkRegion& region);
/** SkPoint SkRegion::Iterator to start of SkRegion.
Returns true if SkRegion was set; otherwise, returns false.
@return true if SkRegion was set
example: https://fiddle.skia.org/c/@Region_Iterator_rewind
*/
bool rewind();
/** Resets iterator, using the new SkRegion.
@param region SkRegion to iterate
example: https://fiddle.skia.org/c/@Region_Iterator_reset
*/
void reset(const SkRegion& region);
/** Returns true if SkRegion::Iterator is pointing to final SkIRect in SkRegion.
@return true if data parsing is complete
*/
bool done() const { return fDone; }
/** Advances SkRegion::Iterator to next SkIRect in SkRegion if it is not done.
example: https://fiddle.skia.org/c/@Region_Iterator_next
*/
void next();
/** Returns SkIRect element in SkRegion. Does not return predictable results if SkRegion
is empty.
@return part of SkRegion as SkIRect
*/
const SkIRect& rect() const { return fRect; }
/** Returns SkRegion if set; otherwise, returns nullptr.
@return iterated SkRegion
*/
const SkRegion* rgn() const { return fRgn; }
private:
const SkRegion* fRgn;
const SkRegion::RunType* fRuns;
SkIRect fRect = {0, 0, 0, 0};
bool fDone;
};
/** \class SkRegion::Cliperator
Returns the sequence of rectangles, sorted along y-axis, then x-axis, that make
up SkRegion intersected with the specified clip rectangle.
*/
class SK_API Cliperator {
public:
/** Sets SkRegion::Cliperator to return elements of SkIRect array in SkRegion within clip.
@param region SkRegion to iterate
@param clip bounds of iteration
@return SkRegion iterator
example: https://fiddle.skia.org/c/@Region_Cliperator_const_SkRegion_const_SkIRect
*/
Cliperator(const SkRegion& region, const SkIRect& clip);
/** Returns true if SkRegion::Cliperator is pointing to final SkIRect in SkRegion.
@return true if data parsing is complete
*/
bool done() { return fDone; }
/** Advances iterator to next SkIRect in SkRegion contained by clip.
example: https://fiddle.skia.org/c/@Region_Cliperator_next
*/
void next();
/** Returns SkIRect element in SkRegion, intersected with clip passed to
SkRegion::Cliperator constructor. Does not return predictable results if SkRegion
is empty.
@return part of SkRegion inside clip as SkIRect
*/
const SkIRect& rect() const { return fRect; }
private:
Iterator fIter;
SkIRect fClip;
SkIRect fRect = {0, 0, 0, 0};
bool fDone;
};
/** \class SkRegion::Spanerator
Returns the line segment ends within SkRegion that intersect a horizontal line.
*/
class Spanerator {
public:
/** Sets SkRegion::Spanerator to return line segments in SkRegion on scan line.
@param region SkRegion to iterate
@param y horizontal line to intersect
@param left bounds of iteration
@param right bounds of iteration
@return SkRegion iterator
example: https://fiddle.skia.org/c/@Region_Spanerator_const_SkRegion_int_int_int
*/
Spanerator(const SkRegion& region, int y, int left, int right);
/** Advances iterator to next span intersecting SkRegion within line segment provided
in constructor. Returns true if interval was found.
@param left pointer to span start; may be nullptr
@param right pointer to span end; may be nullptr
@return true if interval was found
example: https://fiddle.skia.org/c/@Region_Spanerator_next
*/
bool next(int* left, int* right);
private:
const SkRegion::RunType* fRuns;
int fLeft, fRight;
bool fDone;
};
/** Writes SkRegion to buffer, and returns number of bytes written.
If buffer is nullptr, returns number number of bytes that would be written.
@param buffer storage for binary data
@return size of SkRegion
example: https://fiddle.skia.org/c/@Region_writeToMemory
*/
size_t writeToMemory(void* buffer) const;
/** Constructs SkRegion from buffer of size length. Returns bytes read.
Returned value will be multiple of four or zero if length was too small.
@param buffer storage for binary data
@param length size of buffer
@return bytes read
example: https://fiddle.skia.org/c/@Region_readFromMemory
*/
size_t readFromMemory(const void* buffer, size_t length);
using sk_is_trivially_relocatable = std::true_type;
private:
static constexpr int kOpCount = kReplace_Op + 1;
// T
// [B N L R S]
// S
static constexpr int kRectRegionRuns = 7;
struct RunHead;
static RunHead* emptyRunHeadPtr() { return (SkRegion::RunHead*) -1; }
static constexpr RunHead* kRectRunHeadPtr = nullptr;
// allocate space for count runs
void allocateRuns(int count);
void allocateRuns(int count, int ySpanCount, int intervalCount);
void allocateRuns(const RunHead& src);
SkDEBUGCODE(void dump() const;)
SkIRect fBounds;
RunHead* fRunHead;
static_assert(::sk_is_trivially_relocatable<decltype(fBounds)>::value);
static_assert(::sk_is_trivially_relocatable<decltype(fRunHead)>::value);
void freeRuns();
/**
* Return the runs from this region, consing up fake runs if the region
* is empty or a rect. In those 2 cases, we use tmpStorage to hold the
* run data.
*/
const RunType* getRuns(RunType tmpStorage[], int* intervals) const;
// This is called with runs[] that do not yet have their interval-count
// field set on each scanline. That is computed as part of this call
// (inside ComputeRunBounds).
bool setRuns(RunType runs[], int count);
int count_runtype_values(int* itop, int* ibot) const;
bool isValid() const;
static void BuildRectRuns(const SkIRect& bounds,
RunType runs[kRectRegionRuns]);
// If the runs define a simple rect, return true and set bounds to that
// rect. If not, return false and ignore bounds.
static bool RunsAreARect(const SkRegion::RunType runs[], int count,
SkIRect* bounds);
/**
* If the last arg is null, just return if the result is non-empty,
* else store the result in the last arg.
*/
static bool Oper(const SkRegion&, const SkRegion&, SkRegion::Op, SkRegion*);
friend struct RunHead;
friend class Iterator;
friend class Spanerator;
friend class SkRegionPriv;
friend class SkRgnBuilder;
friend class SkFlatRegion;
};
#endif

View File

@ -0,0 +1,107 @@
/*
* Copyright 2020 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkImageSampling_DEFINED
#define SkImageSampling_DEFINED
#include "include/core/SkTypes.h"
#include <algorithm>
#include <new>
enum class SkFilterMode {
kNearest, // single sample point (nearest neighbor)
kLinear, // interporate between 2x2 sample points (bilinear interpolation)
kLast = kLinear,
};
static constexpr int kSkFilterModeCount = static_cast<int>(SkFilterMode::kLast) + 1;
enum class SkMipmapMode {
kNone, // ignore mipmap levels, sample from the "base"
kNearest, // sample from the nearest level
kLinear, // interpolate between the two nearest levels
kLast = kLinear,
};
static constexpr int kSkMipmapModeCount = static_cast<int>(SkMipmapMode::kLast) + 1;
/*
* Specify B and C (each between 0...1) to create a shader that applies the corresponding
* cubic reconstruction filter to the image.
*
* Example values:
* B = 1/3, C = 1/3 "Mitchell" filter
* B = 0, C = 1/2 "Catmull-Rom" filter
*
* See "Reconstruction Filters in Computer Graphics"
* Don P. Mitchell
* Arun N. Netravali
* 1988
* https://www.cs.utexas.edu/~fussell/courses/cs384g-fall2013/lectures/mitchell/Mitchell.pdf
*
* Desmos worksheet https://www.desmos.com/calculator/aghdpicrvr
* Nice overview https://entropymine.com/imageworsener/bicubic/
*/
struct SkCubicResampler {
float B, C;
// Historic default for kHigh_SkFilterQuality
static constexpr SkCubicResampler Mitchell() { return {1/3.0f, 1/3.0f}; }
static constexpr SkCubicResampler CatmullRom() { return {0.0f, 1/2.0f}; }
};
struct SK_API SkSamplingOptions {
const int maxAniso = 0;
const bool useCubic = false;
const SkCubicResampler cubic = {0, 0};
const SkFilterMode filter = SkFilterMode::kNearest;
const SkMipmapMode mipmap = SkMipmapMode::kNone;
constexpr SkSamplingOptions() = default;
SkSamplingOptions(const SkSamplingOptions&) = default;
SkSamplingOptions& operator=(const SkSamplingOptions& that) {
this->~SkSamplingOptions(); // A pedantic no-op.
new (this) SkSamplingOptions(that);
return *this;
}
constexpr SkSamplingOptions(SkFilterMode fm, SkMipmapMode mm)
: filter(fm)
, mipmap(mm) {}
// These are intentionally implicit because the single parameter clearly conveys what the
// implicitly created SkSamplingOptions will be.
constexpr SkSamplingOptions(SkFilterMode fm)
: filter(fm)
, mipmap(SkMipmapMode::kNone) {}
constexpr SkSamplingOptions(const SkCubicResampler& c)
: useCubic(true)
, cubic(c) {}
static constexpr SkSamplingOptions Aniso(int maxAniso) {
return SkSamplingOptions{std::max(maxAniso, 1)};
}
bool operator==(const SkSamplingOptions& other) const {
return maxAniso == other.maxAniso
&& useCubic == other.useCubic
&& cubic.B == other.cubic.B
&& cubic.C == other.cubic.C
&& filter == other.filter
&& mipmap == other.mipmap;
}
bool operator!=(const SkSamplingOptions& other) const { return !(*this == other); }
bool isAniso() const { return maxAniso != 0; }
private:
constexpr SkSamplingOptions(int maxAniso) : maxAniso(maxAniso) {}
};
#endif

View File

@ -0,0 +1,161 @@
/*
* Copyright 2006 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkScalar_DEFINED
#define SkScalar_DEFINED
#include "include/private/base/SkAssert.h"
#include "include/private/base/SkFloatingPoint.h"
#include <cmath>
typedef float SkScalar;
#define SK_Scalar1 1.0f
#define SK_ScalarHalf 0.5f
#define SK_ScalarSqrt2 SK_FloatSqrt2
#define SK_ScalarPI SK_FloatPI
#define SK_ScalarTanPIOver8 0.414213562f
#define SK_ScalarRoot2Over2 0.707106781f
#define SK_ScalarMax 3.402823466e+38f
#define SK_ScalarMin (-SK_ScalarMax)
#define SK_ScalarInfinity SK_FloatInfinity
#define SK_ScalarNegativeInfinity SK_FloatNegativeInfinity
#define SK_ScalarNaN SK_FloatNaN
#define SkScalarFloorToScalar(x) std::floor(x)
#define SkScalarCeilToScalar(x) std::ceil(x)
#define SkScalarRoundToScalar(x) sk_float_round(x)
#define SkScalarTruncToScalar(x) std::trunc(x)
#define SkScalarFloorToInt(x) sk_float_floor2int(x)
#define SkScalarCeilToInt(x) sk_float_ceil2int(x)
#define SkScalarRoundToInt(x) sk_float_round2int(x)
#define SkScalarAbs(x) std::fabs(x)
#define SkScalarCopySign(x, y) std::copysign(x, y)
#define SkScalarMod(x, y) std::fmod(x,y)
#define SkScalarSqrt(x) std::sqrt(x)
#define SkScalarPow(b, e) std::pow(b, e)
#define SkScalarSin(radians) ((float)std::sin(radians))
#define SkScalarCos(radians) ((float)std::cos(radians))
#define SkScalarTan(radians) ((float)std::tan(radians))
#define SkScalarASin(val) ((float)std::asin(val))
#define SkScalarACos(val) ((float)std::acos(val))
#define SkScalarATan2(y, x) ((float)std::atan2(y,x))
#define SkScalarExp(x) ((float)std::exp(x))
#define SkScalarLog(x) ((float)std::log(x))
#define SkScalarLog2(x) ((float)std::log2(x))
//////////////////////////////////////////////////////////////////////////////////////////////////
#define SkIntToScalar(x) static_cast<SkScalar>(x)
#define SkIntToFloat(x) static_cast<float>(x)
#define SkScalarTruncToInt(x) sk_float_saturate2int(x)
#define SkScalarToFloat(x) static_cast<float>(x)
#define SkFloatToScalar(x) static_cast<SkScalar>(x)
#define SkScalarToDouble(x) static_cast<double>(x)
#define SkDoubleToScalar(x) sk_double_to_float(x)
/** Returns the fractional part of the scalar. */
static inline SkScalar SkScalarFraction(SkScalar x) {
return x - SkScalarTruncToScalar(x);
}
static inline SkScalar SkScalarSquare(SkScalar x) { return x * x; }
#define SkScalarInvert(x) (SK_Scalar1 / (x))
#define SkScalarAve(a, b) (((a) + (b)) * SK_ScalarHalf)
#define SkScalarHalf(a) ((a) * SK_ScalarHalf)
#define SkDegreesToRadians(degrees) ((degrees) * (SK_ScalarPI / 180))
#define SkRadiansToDegrees(radians) ((radians) * (180 / SK_ScalarPI))
static inline bool SkScalarIsInt(SkScalar x) {
return x == SkScalarFloorToScalar(x);
}
/**
* Returns -1 || 0 || 1 depending on the sign of value:
* -1 if x < 0
* 0 if x == 0
* 1 if x > 0
*/
static inline int SkScalarSignAsInt(SkScalar x) {
return x < 0 ? -1 : (x > 0);
}
// Scalar result version of above
static inline SkScalar SkScalarSignAsScalar(SkScalar x) {
return x < 0 ? -SK_Scalar1 : ((x > 0) ? SK_Scalar1 : 0);
}
#define SK_ScalarNearlyZero (SK_Scalar1 / (1 << 12))
static inline bool SkScalarNearlyZero(SkScalar x,
SkScalar tolerance = SK_ScalarNearlyZero) {
SkASSERT(tolerance >= 0);
return SkScalarAbs(x) <= tolerance;
}
static inline bool SkScalarNearlyEqual(SkScalar x, SkScalar y,
SkScalar tolerance = SK_ScalarNearlyZero) {
SkASSERT(tolerance >= 0);
return SkScalarAbs(x-y) <= tolerance;
}
#define SK_ScalarSinCosNearlyZero (SK_Scalar1 / (1 << 16))
static inline float SkScalarSinSnapToZero(SkScalar radians) {
float v = SkScalarSin(radians);
return SkScalarNearlyZero(v, SK_ScalarSinCosNearlyZero) ? 0.0f : v;
}
static inline float SkScalarCosSnapToZero(SkScalar radians) {
float v = SkScalarCos(radians);
return SkScalarNearlyZero(v, SK_ScalarSinCosNearlyZero) ? 0.0f : v;
}
/** Linearly interpolate between A and B, based on t.
If t is 0, return A
If t is 1, return B
else interpolate.
t must be [0..SK_Scalar1]
*/
static inline SkScalar SkScalarInterp(SkScalar A, SkScalar B, SkScalar t) {
SkASSERT(t >= 0 && t <= SK_Scalar1);
return A + (B - A) * t;
}
/** Interpolate along the function described by (keys[length], values[length])
for the passed searchKey. SearchKeys outside the range keys[0]-keys[Length]
clamp to the min or max value. This function assumes the number of pairs
(length) will be small and a linear search is used.
Repeated keys are allowed for discontinuous functions (so long as keys is
monotonically increasing). If key is the value of a repeated scalar in
keys the first one will be used.
*/
SkScalar SkScalarInterpFunc(SkScalar searchKey, const SkScalar keys[],
const SkScalar values[], int length);
/*
* Helper to compare an array of scalars.
*/
static inline bool SkScalarsEqual(const SkScalar a[], const SkScalar b[], int n) {
SkASSERT(n >= 0);
for (int i = 0; i < n; ++i) {
if (a[i] != b[i]) {
return false;
}
}
return true;
}
#endif

View File

@ -0,0 +1,117 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkSerialProcs_DEFINED
#define SkSerialProcs_DEFINED
#include "include/core/SkRefCnt.h"
#include "include/private/base/SkAPI.h"
#include <cstddef>
#include <optional>
class SkData;
class SkImage;
class SkPicture;
class SkTypeface;
class SkReadBuffer;
enum SkAlphaType : int;
namespace sktext::gpu {
class Slug;
}
/**
* A serial-proc is asked to serialize the specified object (e.g. picture or image).
* If a data object is returned, it will be used (even if it is zero-length).
* If null is returned, then Skia will take its default action.
*
* The default action for pictures is to use Skia's internal format.
* The default action for images is to encode either in its native format or PNG.
* The default action for typefaces is to use Skia's internal format.
*/
using SkSerialPictureProc = sk_sp<SkData> (*)(SkPicture*, void* ctx);
using SkSerialImageProc = sk_sp<SkData> (*)(SkImage*, void* ctx);
using SkSerialTypefaceProc = sk_sp<SkData> (*)(SkTypeface*, void* ctx);
/**
* Called with the encoded form of a picture (previously written with a custom
* SkSerialPictureProc proc). Return a picture object, or nullptr indicating failure.
*/
using SkDeserialPictureProc = sk_sp<SkPicture> (*)(const void* data, size_t length, void* ctx);
/**
* Called with the encoded form of an image. The proc can return an image object, or if it
* returns nullptr, then Skia will take its default action to try to create an image from the data.
*
* This will also be used to decode the internal mipmap layers that are saved on some images.
*
* An explicit SkAlphaType may have been encoded in the bytestream; if not, then the passed in
* optional will be not present.
*
* Clients should set at least SkDeserialImageProc; SkDeserialImageFromDataProc may be called
* if the internal implementation has a SkData copy already. Implementations of SkDeserialImageProc
* must make a copy of any data they needed after the proc finishes, since the data will go away
* after serialization ends.
*/
#if !defined(SK_LEGACY_DESERIAL_IMAGE_PROC)
using SkDeserialImageProc = sk_sp<SkImage> (*)(const void* data, size_t length, void* ctx);
#else
using SkDeserialImageProc = sk_sp<SkImage> (*)(const void* data,
size_t length,
std::optional<SkAlphaType>,
void* ctx);
#endif
using SkDeserialImageFromDataProc = sk_sp<SkImage> (*)(sk_sp<SkData>,
std::optional<SkAlphaType>,
void* ctx);
/**
* Slugs are currently only deserializable with a GPU backend. Clients will not be able to
* provide a custom mechanism here, but can enable Slug deserialization by calling
* sktext::gpu::AddDeserialProcs to add Skia's implementation.
*/
using SkSlugProc = sk_sp<sktext::gpu::Slug> (*)(SkReadBuffer&, void* ctx);
/**
* Called with the encoded form of a typeface (previously written with a custom
* SkSerialTypefaceProc proc). Return a typeface object, or nullptr indicating failure.
*/
using SkDeserialTypefaceProc = sk_sp<SkTypeface> (*)(const void* data, size_t length, void* ctx);
struct SK_API SkSerialProcs {
SkSerialPictureProc fPictureProc = nullptr;
void* fPictureCtx = nullptr;
SkSerialImageProc fImageProc = nullptr;
void* fImageCtx = nullptr;
SkSerialTypefaceProc fTypefaceProc = nullptr;
void* fTypefaceCtx = nullptr;
};
struct SK_API SkDeserialProcs {
SkDeserialPictureProc fPictureProc = nullptr;
void* fPictureCtx = nullptr;
SkDeserialImageProc fImageProc = nullptr;
SkDeserialImageFromDataProc fImageDataProc = nullptr;
void* fImageCtx = nullptr;
SkSlugProc fSlugProc = nullptr;
void* fSlugCtx = nullptr;
SkDeserialTypefaceProc fTypefaceProc = nullptr;
void* fTypefaceCtx = nullptr;
// This looks like a flag, but it could be considered a proc as well (one that takes no
// parameters and returns a bool). Given that there are only two valid implementations of that
// proc, we just insert the bool directly.
bool fAllowSkSL = true;
};
#endif

View File

@ -0,0 +1,112 @@
/*
* Copyright 2006 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkShader_DEFINED
#define SkShader_DEFINED
#include "include/core/SkColor.h"
#include "include/core/SkFlattenable.h"
#include "include/core/SkRefCnt.h"
#include "include/private/base/SkAPI.h"
class SkBlender;
class SkColorFilter;
class SkColorSpace;
class SkImage;
class SkMatrix;
enum class SkBlendMode;
enum class SkTileMode;
struct SkRect;
struct SkSamplingOptions;
/** \class SkShader
*
* Shaders specify the source color(s) for what is being drawn. If a paint
* has no shader, then the paint's color is used. If the paint has a
* shader, then the shader's color(s) are use instead, but they are
* modulated by the paint's alpha. This makes it easy to create a shader
* once (e.g. bitmap tiling or gradient) and then change its transparency
* w/o having to modify the original shader... only the paint's alpha needs
* to be modified.
*/
class SK_API SkShader : public SkFlattenable {
public:
/**
* Returns true if the shader is guaranteed to produce only opaque
* colors, subject to the SkPaint using the shader to apply an opaque
* alpha value. Subclasses should override this to allow some
* optimizations.
*/
virtual bool isOpaque() const { return false; }
/**
* Iff this shader is backed by a single SkImage, return its ptr (the caller must ref this
* if they want to keep it longer than the lifetime of the shader). If not, return nullptr.
*/
SkImage* isAImage(SkMatrix* localMatrix, SkTileMode xy[2]) const;
bool isAImage() const {
return this->isAImage(nullptr, (SkTileMode*)nullptr) != nullptr;
}
//////////////////////////////////////////////////////////////////////////
// Methods to create combinations or variants of shaders
/**
* Return a shader that will apply the specified localMatrix to this shader.
* The specified matrix will be applied before any matrix associated with this shader.
*/
sk_sp<SkShader> makeWithLocalMatrix(const SkMatrix&) const;
/**
* Create a new shader that produces the same colors as invoking this shader and then applying
* the colorfilter.
*/
sk_sp<SkShader> makeWithColorFilter(sk_sp<SkColorFilter>) const;
/**
* Return a shader that will compute this shader in a specific color space.
* By default, all shaders operate in the destination (surface) color space.
* The results of a shader are still always converted to the destination - this
* API has no impact on simple shaders or images. Primarily, it impacts shaders
* that perform mathematical operations, like Blend shaders, or runtime shaders.
*/
sk_sp<SkShader> makeWithWorkingColorSpace(sk_sp<SkColorSpace>) const;
private:
SkShader() = default;
friend class SkShaderBase;
using INHERITED = SkFlattenable;
};
namespace SkShaders {
SK_API sk_sp<SkShader> Empty();
SK_API sk_sp<SkShader> Color(SkColor);
SK_API sk_sp<SkShader> Color(const SkColor4f&, sk_sp<SkColorSpace>);
SK_API sk_sp<SkShader> Blend(SkBlendMode mode, sk_sp<SkShader> dst, sk_sp<SkShader> src);
SK_API sk_sp<SkShader> Blend(sk_sp<SkBlender>, sk_sp<SkShader> dst, sk_sp<SkShader> src);
SK_API sk_sp<SkShader> CoordClamp(sk_sp<SkShader>, const SkRect& subset);
/*
* Create an SkShader that will sample the 'image'. This is equivalent to SkImage::makeShader.
*/
SK_API sk_sp<SkShader> Image(sk_sp<SkImage> image,
SkTileMode tmx, SkTileMode tmy,
const SkSamplingOptions& options,
const SkMatrix* localMatrix = nullptr);
/*
* Create an SkShader that will sample 'image' with minimal processing. This is equivalent to
* SkImage::makeRawShader.
*/
SK_API sk_sp<SkShader> RawImage(sk_sp<SkImage> image,
SkTileMode tmx, SkTileMode tmy,
const SkSamplingOptions& options,
const SkMatrix* localMatrix = nullptr);
}
#endif

View File

@ -0,0 +1,93 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkSize_DEFINED
#define SkSize_DEFINED
#include "include/core/SkScalar.h"
#include "include/private/base/SkTo.h"
#include <cstdint>
struct SkISize {
int32_t fWidth;
int32_t fHeight;
static constexpr SkISize Make(int32_t w, int32_t h) { return {w, h}; }
static constexpr SkISize MakeEmpty() { return {0, 0}; }
void set(int32_t w, int32_t h) { *this = SkISize{w, h}; }
/** Returns true iff fWidth == 0 && fHeight == 0
*/
bool isZero() const { return 0 == fWidth && 0 == fHeight; }
/** Returns true if either width or height are <= 0 */
bool isEmpty() const { return fWidth <= 0 || fHeight <= 0; }
/** Set the width and height to 0 */
void setEmpty() { fWidth = fHeight = 0; }
constexpr int32_t width() const { return fWidth; }
constexpr int32_t height() const { return fHeight; }
constexpr int64_t area() const { return SkToS64(fWidth) * SkToS64(fHeight); }
bool equals(int32_t w, int32_t h) const { return fWidth == w && fHeight == h; }
};
static inline bool operator==(const SkISize& a, const SkISize& b) {
return a.fWidth == b.fWidth && a.fHeight == b.fHeight;
}
static inline bool operator!=(const SkISize& a, const SkISize& b) { return !(a == b); }
///////////////////////////////////////////////////////////////////////////////
struct SkSize {
SkScalar fWidth;
SkScalar fHeight;
static constexpr SkSize Make(SkScalar w, SkScalar h) { return {w, h}; }
static constexpr SkSize Make(const SkISize& src) {
return {SkIntToScalar(src.width()), SkIntToScalar(src.height())};
}
static constexpr SkSize MakeEmpty() { return {0, 0}; }
void set(SkScalar w, SkScalar h) { *this = SkSize{w, h}; }
/** Returns true iff fWidth == 0 && fHeight == 0
*/
bool isZero() const { return 0 == fWidth && 0 == fHeight; }
/** Returns true if either width or height are <= 0 */
bool isEmpty() const { return fWidth <= 0 || fHeight <= 0; }
/** Set the width and height to 0 */
void setEmpty() { *this = SkSize{0, 0}; }
SkScalar width() const { return fWidth; }
SkScalar height() const { return fHeight; }
bool equals(SkScalar w, SkScalar h) const { return fWidth == w && fHeight == h; }
SkISize toRound() const { return {SkScalarRoundToInt(fWidth), SkScalarRoundToInt(fHeight)}; }
SkISize toCeil() const { return {SkScalarCeilToInt(fWidth), SkScalarCeilToInt(fHeight)}; }
SkISize toFloor() const { return {SkScalarFloorToInt(fWidth), SkScalarFloorToInt(fHeight)}; }
};
static inline bool operator==(const SkSize& a, const SkSize& b) {
return a.fWidth == b.fWidth && a.fHeight == b.fHeight;
}
static inline bool operator!=(const SkSize& a, const SkSize& b) { return !(a == b); }
#endif

View File

@ -0,0 +1,13 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
// We want SkSpan to be a public API, but it is also fundamental to many of our internal types.
// Thus, we have a public file that clients can include. This file defers to the private copy
// so we do not have a dependency cycle from our "base" files to our "core" files.
#include "include/private/base/SkSpan_impl.h" // IWYU pragma: export

View File

@ -0,0 +1,512 @@
/*
* Copyright 2006 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkStream_DEFINED
#define SkStream_DEFINED
#include "include/core/SkData.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/core/SkTypes.h"
#include "include/private/base/SkCPUTypes.h"
#include "include/private/base/SkTo.h"
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <memory>
#include <utility>
class SkStreamAsset;
/**
* SkStream -- abstraction for a source of bytes. Subclasses can be backed by
* memory, or a file, or something else.
*/
class SK_API SkStream {
public:
virtual ~SkStream() {}
SkStream() {}
/**
* Attempts to open the specified file as a stream, returns nullptr on failure.
*/
static std::unique_ptr<SkStreamAsset> MakeFromFile(const char path[]);
/** Reads or skips size number of bytes.
* If buffer == NULL, skip size bytes, return how many were skipped.
* If buffer != NULL, copy size bytes into buffer, return how many were copied.
* @param buffer when NULL skip size bytes, otherwise copy size bytes into buffer
* @param size the number of bytes to skip or copy
* @return the number of bytes actually read.
*/
virtual size_t read(void* buffer, size_t size) = 0;
/** Skip size number of bytes.
* @return the actual number bytes that could be skipped.
*/
size_t skip(size_t size) {
return this->read(nullptr, size);
}
/**
* Attempt to peek at size bytes.
* If this stream supports peeking, copy min(size, peekable bytes) into
* buffer, and return the number of bytes copied.
* If the stream does not support peeking, or cannot peek any bytes,
* return 0 and leave buffer unchanged.
* The stream is guaranteed to be in the same visible state after this
* call, regardless of success or failure.
* @param buffer Must not be NULL, and must be at least size bytes. Destination
* to copy bytes.
* @param size Number of bytes to copy.
* @return The number of bytes peeked/copied.
*/
virtual size_t peek(void* /*buffer*/, size_t /*size*/) const { return 0; }
/** Returns true when all the bytes in the stream have been read.
* As SkStream represents synchronous I/O, isAtEnd returns false when the
* final stream length isn't known yet, even when all the bytes available
* so far have been read.
* This may return true early (when there are no more bytes to be read)
* or late (after the first unsuccessful read).
*/
virtual bool isAtEnd() const = 0;
[[nodiscard]] bool readS8(int8_t*);
[[nodiscard]] bool readS16(int16_t*);
[[nodiscard]] bool readS32(int32_t*);
[[nodiscard]] bool readU8(uint8_t* i) { return this->readS8((int8_t*)i); }
[[nodiscard]] bool readU16(uint16_t* i) { return this->readS16((int16_t*)i); }
[[nodiscard]] bool readU32(uint32_t* i) { return this->readS32((int32_t*)i); }
[[nodiscard]] bool readBool(bool* b) {
uint8_t i;
if (!this->readU8(&i)) { return false; }
*b = (i != 0);
return true;
}
[[nodiscard]] bool readScalar(SkScalar*);
[[nodiscard]] bool readPackedUInt(size_t*);
//SkStreamRewindable
/** Rewinds to the beginning of the stream. Returns true if the stream is known
* to be at the beginning after this call returns.
*/
virtual bool rewind() { return false; }
/** Duplicates this stream. If this cannot be done, returns NULL.
* The returned stream will be positioned at the beginning of its data.
*/
std::unique_ptr<SkStream> duplicate() const {
return std::unique_ptr<SkStream>(this->onDuplicate());
}
/** Duplicates this stream. If this cannot be done, returns NULL.
* The returned stream will be positioned the same as this stream.
*/
std::unique_ptr<SkStream> fork() const {
return std::unique_ptr<SkStream>(this->onFork());
}
//SkStreamSeekable
/** Returns true if this stream can report its current position. */
virtual bool hasPosition() const { return false; }
/** Returns the current position in the stream. If this cannot be done, returns 0. */
virtual size_t getPosition() const { return 0; }
/** Seeks to an absolute position in the stream. If this cannot be done, returns false.
* If an attempt is made to seek past the end of the stream, the position will be set
* to the end of the stream.
*/
virtual bool seek(size_t /*position*/) { return false; }
/** Seeks to an relative offset in the stream. If this cannot be done, returns false.
* If an attempt is made to move to a position outside the stream, the position will be set
* to the closest point within the stream (beginning or end).
*/
virtual bool move(long /*offset*/) { return false; }
//SkStreamAsset
/** Returns true if this stream can report its total length. */
virtual bool hasLength() const { return false; }
/** Returns the total length of the stream. If this cannot be done, returns 0. */
virtual size_t getLength() const { return 0; }
//SkStreamMemory
/** Returns the starting address for the data. If this cannot be done, returns NULL. */
virtual const void* getMemoryBase() { return nullptr; }
virtual sk_sp<SkData> getData() const { return nullptr; }
private:
virtual SkStream* onDuplicate() const { return nullptr; }
virtual SkStream* onFork() const { return nullptr; }
SkStream(SkStream&&) = delete;
SkStream(const SkStream&) = delete;
SkStream& operator=(SkStream&&) = delete;
SkStream& operator=(const SkStream&) = delete;
};
/** SkStreamRewindable is a SkStream for which rewind and duplicate are required. */
class SK_API SkStreamRewindable : public SkStream {
public:
bool rewind() override = 0;
std::unique_ptr<SkStreamRewindable> duplicate() const {
return std::unique_ptr<SkStreamRewindable>(this->onDuplicate());
}
private:
SkStreamRewindable* onDuplicate() const override = 0;
};
/** SkStreamSeekable is a SkStreamRewindable for which position, seek, move, and fork are required. */
class SK_API SkStreamSeekable : public SkStreamRewindable {
public:
std::unique_ptr<SkStreamSeekable> duplicate() const {
return std::unique_ptr<SkStreamSeekable>(this->onDuplicate());
}
bool hasPosition() const override { return true; }
size_t getPosition() const override = 0;
bool seek(size_t position) override = 0;
bool move(long offset) override = 0;
std::unique_ptr<SkStreamSeekable> fork() const {
return std::unique_ptr<SkStreamSeekable>(this->onFork());
}
private:
SkStreamSeekable* onDuplicate() const override = 0;
SkStreamSeekable* onFork() const override = 0;
};
/** SkStreamAsset is a SkStreamSeekable for which getLength is required. */
class SK_API SkStreamAsset : public SkStreamSeekable {
public:
bool hasLength() const override { return true; }
size_t getLength() const override = 0;
std::unique_ptr<SkStreamAsset> duplicate() const {
return std::unique_ptr<SkStreamAsset>(this->onDuplicate());
}
std::unique_ptr<SkStreamAsset> fork() const {
return std::unique_ptr<SkStreamAsset>(this->onFork());
}
private:
SkStreamAsset* onDuplicate() const override = 0;
SkStreamAsset* onFork() const override = 0;
};
/** SkStreamMemory is a SkStreamAsset for which getMemoryBase is required. */
class SK_API SkStreamMemory : public SkStreamAsset {
public:
const void* getMemoryBase() override = 0;
std::unique_ptr<SkStreamMemory> duplicate() const {
return std::unique_ptr<SkStreamMemory>(this->onDuplicate());
}
std::unique_ptr<SkStreamMemory> fork() const {
return std::unique_ptr<SkStreamMemory>(this->onFork());
}
private:
SkStreamMemory* onDuplicate() const override = 0;
SkStreamMemory* onFork() const override = 0;
};
class SK_API SkWStream {
public:
virtual ~SkWStream();
SkWStream() {}
/** Called to write bytes to a SkWStream. Returns true on success
@param buffer the address of at least size bytes to be written to the stream
@param size The number of bytes in buffer to write to the stream
@return true on success
*/
virtual bool write(const void* buffer, size_t size) = 0;
virtual void flush();
virtual size_t bytesWritten() const = 0;
// helpers
bool write8(U8CPU value) {
uint8_t v = SkToU8(value);
return this->write(&v, 1);
}
bool write16(U16CPU value) {
uint16_t v = SkToU16(value);
return this->write(&v, 2);
}
bool write32(uint32_t v) {
return this->write(&v, 4);
}
bool writeText(const char text[]) {
SkASSERT(text);
return this->write(text, std::strlen(text));
}
bool newline() { return this->write("\n", std::strlen("\n")); }
bool writeDecAsText(int32_t);
bool writeBigDecAsText(int64_t, int minDigits = 0);
bool writeHexAsText(uint32_t, int minDigits = 0);
bool writeScalarAsText(SkScalar);
bool writeBool(bool v) { return this->write8(v); }
bool writeScalar(SkScalar);
bool writePackedUInt(size_t);
bool writeStream(SkStream* input, size_t length);
/**
* This returns the number of bytes in the stream required to store
* 'value'.
*/
static int SizeOfPackedUInt(size_t value);
private:
SkWStream(const SkWStream&) = delete;
SkWStream& operator=(const SkWStream&) = delete;
};
class SK_API SkNullWStream : public SkWStream {
public:
SkNullWStream() : fBytesWritten(0) {}
bool write(const void* , size_t n) override { fBytesWritten += n; return true; }
void flush() override {}
size_t bytesWritten() const override { return fBytesWritten; }
private:
size_t fBytesWritten;
};
////////////////////////////////////////////////////////////////////////////////////////
/** A stream that wraps a C FILE* file stream. */
class SK_API SkFILEStream : public SkStreamAsset {
public:
/** Initialize the stream by calling sk_fopen on the specified path.
* This internal stream will be closed in the destructor.
*/
explicit SkFILEStream(const char path[] = nullptr);
/** Initialize the stream with an existing C FILE stream.
* The current position of the C FILE stream will be considered the
* beginning of the SkFILEStream and the current seek end of the FILE will be the end.
* The C FILE stream will be closed in the destructor.
*/
explicit SkFILEStream(FILE* file);
/** Initialize the stream with an existing C FILE stream.
* The current position of the C FILE stream will be considered the
* beginning of the SkFILEStream and size bytes later will be the end.
* The C FILE stream will be closed in the destructor.
*/
explicit SkFILEStream(FILE* file, size_t size);
~SkFILEStream() override;
static std::unique_ptr<SkFILEStream> Make(const char path[]) {
std::unique_ptr<SkFILEStream> stream(new SkFILEStream(path));
return stream->isValid() ? std::move(stream) : nullptr;
}
/** Returns true if the current path could be opened. */
bool isValid() const { return fFILE != nullptr; }
/** Close this SkFILEStream. */
void close();
size_t read(void* buffer, size_t size) override;
bool isAtEnd() const override;
bool rewind() override;
std::unique_ptr<SkStreamAsset> duplicate() const {
return std::unique_ptr<SkStreamAsset>(this->onDuplicate());
}
size_t getPosition() const override;
bool seek(size_t position) override;
bool move(long offset) override;
std::unique_ptr<SkStreamAsset> fork() const {
return std::unique_ptr<SkStreamAsset>(this->onFork());
}
size_t getLength() const override;
private:
explicit SkFILEStream(FILE*, size_t size, size_t start);
explicit SkFILEStream(std::shared_ptr<FILE>, size_t end, size_t start);
explicit SkFILEStream(std::shared_ptr<FILE>, size_t end, size_t start, size_t current);
SkStreamAsset* onDuplicate() const override;
SkStreamAsset* onFork() const override;
std::shared_ptr<FILE> fFILE;
// My own council will I keep on sizes and offsets.
// These are seek positions in the underling FILE, not offsets into the stream.
size_t fEnd;
size_t fStart;
size_t fCurrent;
using INHERITED = SkStreamAsset;
};
class SK_API SkMemoryStream : public SkStreamMemory {
public:
SkMemoryStream();
/** We allocate (and free) the memory. Write to it via getMemoryBase() */
SkMemoryStream(size_t length);
/** If copyData is true, the stream makes a private copy of the data. */
SkMemoryStream(const void* data, size_t length, bool copyData = false);
/** Creates the stream to read from the specified data */
SkMemoryStream(sk_sp<SkData> data);
/** Returns a stream with a copy of the input data. */
static std::unique_ptr<SkMemoryStream> MakeCopy(const void* data, size_t length);
/** Returns a stream with a bare pointer reference to the input data. */
static std::unique_ptr<SkMemoryStream> MakeDirect(const void* data, size_t length);
/** Returns a stream with a shared reference to the input data. */
static std::unique_ptr<SkMemoryStream> Make(sk_sp<SkData> data);
/** Resets the stream to the specified data and length,
just like the constructor.
if copyData is true, the stream makes a private copy of the data
*/
virtual void setMemory(const void* data, size_t length,
bool copyData = false);
/** Replace any memory buffer with the specified buffer. The caller
must have allocated data with sk_malloc or sk_realloc, since it
will be freed with sk_free.
*/
void setMemoryOwned(const void* data, size_t length);
sk_sp<SkData> getData() const override { return fData; }
void setData(sk_sp<SkData> data);
const void* getAtPos();
size_t read(void* buffer, size_t size) override;
bool isAtEnd() const override;
size_t peek(void* buffer, size_t size) const override;
bool rewind() override;
std::unique_ptr<SkMemoryStream> duplicate() const {
return std::unique_ptr<SkMemoryStream>(this->onDuplicate());
}
size_t getPosition() const override;
bool seek(size_t position) override;
bool move(long offset) override;
std::unique_ptr<SkMemoryStream> fork() const {
return std::unique_ptr<SkMemoryStream>(this->onFork());
}
size_t getLength() const override;
const void* getMemoryBase() override;
private:
SkMemoryStream* onDuplicate() const override;
SkMemoryStream* onFork() const override;
sk_sp<SkData> fData;
size_t fOffset;
using INHERITED = SkStreamMemory;
};
/////////////////////////////////////////////////////////////////////////////////////////////
class SK_API SkFILEWStream : public SkWStream {
public:
SkFILEWStream(const char path[]);
~SkFILEWStream() override;
/** Returns true if the current path could be opened.
*/
bool isValid() const { return fFILE != nullptr; }
bool write(const void* buffer, size_t size) override;
void flush() override;
void fsync();
size_t bytesWritten() const override;
private:
FILE* fFILE;
using INHERITED = SkWStream;
};
class SK_API SkDynamicMemoryWStream : public SkWStream {
public:
SkDynamicMemoryWStream() = default;
SkDynamicMemoryWStream(SkDynamicMemoryWStream&&);
SkDynamicMemoryWStream& operator=(SkDynamicMemoryWStream&&);
~SkDynamicMemoryWStream() override;
bool write(const void* buffer, size_t size) override;
size_t bytesWritten() const override;
bool read(void* buffer, size_t offset, size_t size);
/** More efficient version of read(dst, 0, bytesWritten()). */
void copyTo(void* dst) const;
bool writeToStream(SkWStream* dst) const;
/** Equivalent to copyTo() followed by reset(), but may save memory use. */
void copyToAndReset(void* dst);
/** Equivalent to writeToStream() followed by reset(), but may save memory use. */
bool writeToAndReset(SkWStream* dst);
/** Equivalent to writeToStream() followed by reset(), but may save memory use.
When the dst is also a SkDynamicMemoryWStream, the implementation is constant time. */
bool writeToAndReset(SkDynamicMemoryWStream* dst);
/** Prepend this stream to dst, resetting this. */
void prependToAndReset(SkDynamicMemoryWStream* dst);
/** Return the contents as SkData, and then reset the stream. */
sk_sp<SkData> detachAsData();
/** Reset, returning a reader stream with the current content. */
std::unique_ptr<SkStreamAsset> detachAsStream();
/** Reset the stream to its original, empty, state. */
void reset();
void padToAlign4();
private:
struct Block;
Block* fHead = nullptr;
Block* fTail = nullptr;
size_t fBytesWrittenBeforeTail = 0;
#ifdef SK_DEBUG
void validate() const;
#else
void validate() const {}
#endif
// For access to the Block type.
friend class SkBlockMemoryStream;
friend class SkBlockMemoryRefCnt;
using INHERITED = SkWStream;
};
#endif

Some files were not shown because too many files have changed in this diff Show More