diff --git a/Tests/LottieMetalTest/BUILD b/Tests/LottieMetalTest/BUILD index bc5d916de6..4226bfd67d 100644 --- a/Tests/LottieMetalTest/BUILD +++ b/Tests/LottieMetalTest/BUILD @@ -201,6 +201,7 @@ ios_application( resources = [ "//Tests/Common:LaunchScreen", ":TestDataBundle", + "//Tests/LottieMetalTest/skia", ], frameworks = [ ], diff --git a/Tests/LottieMetalTest/SoftwareLottieRenderer/BUILD b/Tests/LottieMetalTest/SoftwareLottieRenderer/BUILD index df62415519..041c8eda84 100644 --- a/Tests/LottieMetalTest/SoftwareLottieRenderer/BUILD +++ b/Tests/LottieMetalTest/SoftwareLottieRenderer/BUILD @@ -25,6 +25,8 @@ objc_library( deps = [ "//submodules/LottieCpp", "//Tests/LottieMetalTest/thorvg", + "//Tests/LottieMetalTest/skia", + "//Tests/LottieMetalTest/skia:libskia" ], sdk_frameworks = [ "Foundation", diff --git a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SkiaCanvasImpl.cpp b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SkiaCanvasImpl.cpp new file mode 100644 index 0000000000..cb7bc72879 --- /dev/null +++ b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SkiaCanvasImpl.cpp @@ -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 SkiaCanvasImpl::makeLayer(int width, int height) { + return std::make_shared(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 colors; + for (const auto &color : gradient.colors()) { + colors.push_back(skColor(Color(color.r, color.g, color.b, color.a * _alpha))); + } + + std::vector 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 colors; + for (const auto &color : gradient.colors()) { + colors.push_back(skColor(Color(color.r, color.g, color.b, color.a * _alpha))); + } + + std::vector 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 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 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 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 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 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 SkiaCanvasImpl::surface() const { + return _surface; +} + +} diff --git a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SkiaCanvasImpl.h b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SkiaCanvasImpl.h new file mode 100644 index 0000000000..6d7a2f35ef --- /dev/null +++ b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SkiaCanvasImpl.h @@ -0,0 +1,57 @@ +#ifndef SkiaCanvasImpl_h +#define SkiaCanvasImpl_h + +#include + +#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 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 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 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 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 const &other, lottie::CGRect const &rect) override; + + void flush(); + sk_sp surface() const; + +private: + void *_pixelData = nullptr; + bool _ownsPixelData = false; + int _width = 0; + int _height = 0; + sk_sp _surface; + SkCanvas *_canvas = nullptr; + SkBlendMode _blendMode = SkBlendMode::kSrcOver; + double _alpha = 1.0; +}; + +} + +#endif diff --git a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SoftwareLottieRenderer.mm b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SoftwareLottieRenderer.mm index 85cf5b7a85..8476ccd457 100644 --- a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SoftwareLottieRenderer.mm +++ b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SoftwareLottieRenderer.mm @@ -5,11 +5,14 @@ #import "CoreGraphicsCanvasImpl.h" #import "ThorVGCanvasImpl.h" +#import "SkiaCanvasImpl.h" #include #include #include +#import + 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(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 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((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(); diff --git a/Tests/LottieMetalTest/Sources/ViewController.swift b/Tests/LottieMetalTest/Sources/ViewController.swift index 34393712aa..0bd665e3a9 100644 --- a/Tests/LottieMetalTest/Sources/ViewController.swift +++ b/Tests/LottieMetalTest/Sources/ViewController.swift @@ -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)! diff --git a/Tests/LottieMetalTest/skia/BUILD b/Tests/LottieMetalTest/skia/BUILD new file mode 100644 index 0000000000..2444ddde2c --- /dev/null +++ b/Tests/LottieMetalTest/skia/BUILD @@ -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", + ], +) diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/OWNERS b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/OWNERS new file mode 100644 index 0000000000..0d7fbad28a --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/OWNERS @@ -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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkAndroidCodec.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkAndroidCodec.h new file mode 100644 index 0000000000..2b8a79751c --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkAndroidCodec.h @@ -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 +#include + +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 MakeFromCodec(std::unique_ptr); + + /** + * 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 MakeFromStream(std::unique_ptr, + 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 MakeFromData(sk_sp, 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 computeOutputColorSpace(SkColorType outputColorType, + sk_sp 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* 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 fCodec; +}; +#endif // SkAndroidCodec_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkAvifDecoder.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkAvifDecoder.h new file mode 100644 index 0000000000..840a600a31 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkAvifDecoder.h @@ -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 + +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 Decode(std::unique_ptr, + SkCodec::Result*, + SkCodecs::DecodeContext = nullptr); +SK_API std::unique_ptr Decode(sk_sp, + SkCodec::Result*, + SkCodecs::DecodeContext = nullptr); + +inline constexpr SkCodecs::Decoder Decoder() { + return { "avif", IsAvif, Decode }; +} + +} // namespace SkAvifDecoder + +#endif // SkAvifDecoder_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkBmpDecoder.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkBmpDecoder.h new file mode 100644 index 0000000000..104decf3cf --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkBmpDecoder.h @@ -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 + +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 Decode(std::unique_ptr, + SkCodec::Result*, + SkCodecs::DecodeContext = nullptr); +SK_API std::unique_ptr Decode(sk_sp, + SkCodec::Result*, + SkCodecs::DecodeContext = nullptr); + +inline constexpr SkCodecs::Decoder Decoder() { + return { "bmp", IsBmp, Decode }; +} + +} // namespace SkBmpDecoder + +#endif // SkBmpDecoder_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkCodec.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkCodec.h new file mode 100644 index 0000000000..782ea69f32 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkCodec.h @@ -0,0 +1,1085 @@ +/* + * 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 SkCodec_DEFINED +#define SkCodec_DEFINED + +#include "include/codec/SkEncodedOrigin.h" +#include "include/core/SkImageInfo.h" +#include "include/core/SkPixmap.h" +#include "include/core/SkRect.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkSize.h" +#include "include/core/SkSpan.h" +#include "include/core/SkTypes.h" +#include "include/core/SkYUVAPixmaps.h" +#include "include/private/SkEncodedInfo.h" +#include "include/private/base/SkNoncopyable.h" +#include "modules/skcms/skcms.h" + +#include +#include +#include +#include +#include +#include +#include + +class SkData; +class SkFrameHolder; +class SkImage; +class SkPngChunkReader; +class SkSampler; +class SkStream; +struct SkGainmapInfo; +enum SkAlphaType : int; +enum class SkEncodedImageFormat; + +namespace SkCodecAnimation { +enum class Blend; +enum class DisposalMethod; +} + +namespace DM { +class CodecSrc; +} // namespace DM + +namespace SkCodecs { +struct Decoder; +} + +/** + * Abstraction layer directly on top of an image codec. + */ +class SK_API SkCodec : SkNoncopyable { +public: + /** + * Minimum number of bytes that must be buffered in SkStream input. + * + * An SkStream passed to NewFromStream must be able to use this many + * bytes to determine the image type. Then the same SkStream must be + * passed to the correct decoder to read from the beginning. + * + * This can be accomplished by implementing peek() to support peeking + * this many bytes, or by implementing rewind() to be able to rewind() + * after reading this many bytes. + */ + static constexpr size_t MinBufferedBytesNeeded() { return 32; } + + /** + * Error codes for various SkCodec methods. + */ + enum Result { + /** + * General return value for success. + */ + kSuccess, + /** + * The input is incomplete. A partial image was generated. + */ + kIncompleteInput, + /** + * Like kIncompleteInput, except the input had an error. + * + * If returned from an incremental decode, decoding cannot continue, + * even with more data. + */ + kErrorInInput, + /** + * The generator cannot convert to match the request, ignoring + * dimensions. + */ + kInvalidConversion, + /** + * The generator cannot scale to requested size. + */ + kInvalidScale, + /** + * Parameters (besides info) are invalid. e.g. NULL pixels, rowBytes + * too small, etc. + */ + kInvalidParameters, + /** + * The input did not contain a valid image. + */ + kInvalidInput, + /** + * Fulfilling this request requires rewinding the input, which is not + * supported for this input. + */ + kCouldNotRewind, + /** + * An internal error, such as OOM. + */ + kInternalError, + /** + * This method is not implemented by this codec. + * FIXME: Perhaps this should be kUnsupported? + */ + kUnimplemented, + }; + + /** + * Readable string representing the error code. + */ + static const char* ResultToString(Result); + + /** + * For container formats that contain both still images and image sequences, + * instruct the decoder how the output should be selected. (Refer to comments + * for each value for more details.) + */ + enum class SelectionPolicy { + /** + * If the container format contains both still images and image sequences, + * SkCodec should choose one of the still images. This is the default. + * Note that kPreferStillImage may prevent use of the animation features + * if the input is not rewindable. + */ + kPreferStillImage, + /** + * If the container format contains both still images and image sequences, + * SkCodec should choose one of the image sequences for animation. + */ + kPreferAnimation, + }; + + /** + * If this stream represents an encoded image that we know how to decode, + * return an SkCodec that can decode it. Otherwise return NULL. + * + * As stated above, this call must be able to peek or read + * MinBufferedBytesNeeded to determine the correct format, and then start + * reading from the beginning. First it will attempt to peek, and it + * assumes that if less than MinBufferedBytesNeeded bytes (but more than + * zero) are returned, this is because the stream is shorter than this, + * so falling back to reading would not provide more data. If peek() + * returns zero bytes, this call will instead attempt to read(). This + * will require that the stream can be rewind()ed. + * + * If Result is not NULL, it will be set to either kSuccess if an SkCodec + * is returned or a reason for the failure if NULL is returned. + * + * If SkPngChunkReader is not NULL, take a ref and pass it to libpng if + * the image is a png. + * + * If the SkPngChunkReader is not NULL then: + * If the image is not a PNG, the SkPngChunkReader will be ignored. + * If the image is a PNG, the SkPngChunkReader will be reffed. + * If the PNG has unknown chunks, the SkPngChunkReader will be used + * to handle these chunks. SkPngChunkReader will be called to read + * any unknown chunk at any point during the creation of the codec + * or the decode. Note that if SkPngChunkReader fails to read a + * chunk, this could result in a failure to create the codec or a + * failure to decode the image. + * If the PNG does not contain unknown chunks, the SkPngChunkReader + * will not be used or modified. + * + * 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 MakeFromStream( + std::unique_ptr, + SkSpan decoders, + Result* = nullptr, + SkPngChunkReader* = nullptr, + SelectionPolicy selectionPolicy = SelectionPolicy::kPreferStillImage); + // deprecated + static std::unique_ptr MakeFromStream( + std::unique_ptr, + Result* = nullptr, + SkPngChunkReader* = nullptr, + SelectionPolicy selectionPolicy = SelectionPolicy::kPreferStillImage); + + /** + * If this data represents an encoded image that we know how to decode, + * return an SkCodec that can decode it. Otherwise return NULL. + * + * If the SkPngChunkReader is not NULL then: + * If the image is not a PNG, the SkPngChunkReader will be ignored. + * If the image is a PNG, the SkPngChunkReader will be reffed. + * If the PNG has unknown chunks, the SkPngChunkReader will be used + * to handle these chunks. SkPngChunkReader will be called to read + * any unknown chunk at any point during the creation of the codec + * or the decode. Note that if SkPngChunkReader fails to read a + * chunk, this could result in a failure to create the codec or a + * failure to decode the image. + * If the PNG does not contain unknown chunks, the SkPngChunkReader + * will not be used or modified. + */ + static std::unique_ptr MakeFromData(sk_sp, + SkSpan decoders, + SkPngChunkReader* = nullptr); + // deprecated + static std::unique_ptr MakeFromData(sk_sp, SkPngChunkReader* = nullptr); + + virtual ~SkCodec(); + + /** + * Return a reasonable SkImageInfo to decode into. + * + * If the image has an ICC profile that does not map to an SkColorSpace, + * the returned SkImageInfo will use SRGB. + */ + SkImageInfo getInfo() const { return fEncodedInfo.makeImageInfo(); } + + SkISize dimensions() const { return {fEncodedInfo.width(), fEncodedInfo.height()}; } + SkIRect bounds() const { + return SkIRect::MakeWH(fEncodedInfo.width(), fEncodedInfo.height()); + } + + /** + * Return the ICC profile of the encoded data. + */ + const skcms_ICCProfile* getICCProfile() const { + return this->getEncodedInfo().profile(); + } + + /** + * Returns the image orientation stored in the EXIF data. + * If there is no EXIF data, or if we cannot read the EXIF data, returns kTopLeft. + */ + SkEncodedOrigin getOrigin() const { return fOrigin; } + + /** + * Return a size that approximately supports the desired scale factor. + * The codec may not be able to scale efficiently to the exact scale + * factor requested, so return a size that approximates that scale. + * The returned value is the codec's suggestion for the closest valid + * scale that it can natively support + */ + SkISize getScaledDimensions(float desiredScale) const { + // Negative and zero scales are errors. + SkASSERT(desiredScale > 0.0f); + if (desiredScale <= 0.0f) { + return SkISize::Make(0, 0); + } + + // Upscaling is not supported. Return the original size if the client + // requests an upscale. + if (desiredScale >= 1.0f) { + return this->dimensions(); + } + return this->onGetScaledDimensions(desiredScale); + } + + /** + * Return (via desiredSubset) a subset which can decoded from this codec, + * or false if this codec cannot decode subsets or anything similar to + * desiredSubset. + * + * @param desiredSubset In/out parameter. As input, a desired subset of + * the original bounds (as specified by getInfo). 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 this codec supports decoding desiredSubset (as + * returned, potentially modified) + */ + bool getValidSubset(SkIRect* desiredSubset) const { + return this->onGetValidSubset(desiredSubset); + } + + /** + * Format of the encoded data. + */ + SkEncodedImageFormat getEncodedFormat() const { return this->onGetEncodedFormat(); } + + /** + * Return the underlying encoded data stream. This may be nullptr if the original + * stream could not be duplicated. + */ + virtual std::unique_ptr getEncodedData() const; + + /** + * Whether or not the memory passed to getPixels is zero initialized. + */ + enum ZeroInitialized { + /** + * The memory passed to getPixels is zero initialized. The SkCodec + * may take advantage of this by skipping writing zeroes. + */ + kYes_ZeroInitialized, + /** + * The memory passed to getPixels has not been initialized to zero, + * so the SkCodec must write all zeroes to memory. + * + * This is the default. It will be used if no Options struct is used. + */ + kNo_ZeroInitialized, + }; + + /** + * Additional options to pass to getPixels. + */ + struct Options { + Options() + : fZeroInitialized(kNo_ZeroInitialized) + , fSubset(nullptr) + , fFrameIndex(0) + , fPriorFrame(kNoFrame) + {} + + ZeroInitialized fZeroInitialized; + /** + * If not NULL, represents a subset of the original image to decode. + * Must be within the bounds returned by getInfo(). + * If the EncodedFormat is SkEncodedImageFormat::kWEBP (the only one which + * currently supports subsets), the top and left values must be even. + * + * In getPixels and incremental decode, we will attempt to decode the + * exact rectangular subset specified by fSubset. + * + * In a scanline decode, it does not make sense to specify a subset + * top or subset height, since the client already controls which rows + * to get and which rows to skip. During scanline decodes, we will + * require that the subset top be zero and the subset height be equal + * to the full height. We will, however, use the values of + * subset left and subset width to decode partial scanlines on calls + * to getScanlines(). + */ + const SkIRect* fSubset; + + /** + * The frame to decode. + * + * Only meaningful for multi-frame images. + */ + int fFrameIndex; + + /** + * If not kNoFrame, the dst already contains the prior frame at this index. + * + * Only meaningful for multi-frame images. + * + * If fFrameIndex needs to be blended with a prior frame (as reported by + * getFrameInfo[fFrameIndex].fRequiredFrame), the client can set this to + * any non-kRestorePrevious frame in [fRequiredFrame, fFrameIndex) to + * indicate that that frame is already in the dst. Options.fZeroInitialized + * is ignored in this case. + * + * If set to kNoFrame, the codec will decode any necessary required frame(s) first. + */ + int fPriorFrame; + }; + + /** + * 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. If the generator cannot perform this scale, + * it will return kInvalidScale. + * + * If the info contains a non-null SkColorSpace, the codec + * will perform the appropriate color space transformation. + * + * If the caller passes in the SkColorSpace that maps to the + * ICC profile reported by getICCProfile(), the color space + * transformation is a no-op. + * + * If the caller passes a null SkColorSpace, no color space + * transformation will be done. + * + * If a scanline decode is in progress, scanline mode will end, requiring the client to call + * startScanlineDecode() in order to return to decoding scanlines. + * + * @return Result kSuccess, or another value explaining the type of failure. + */ + Result getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, const Options*); + + /** + * Simplified version of getPixels() that uses the default Options. + */ + Result getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) { + return this->getPixels(info, pixels, rowBytes, nullptr); + } + + Result getPixels(const SkPixmap& pm, const Options* opts = nullptr) { + return this->getPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), opts); + } + + /** + * Return an image containing the pixels. If the codec's origin is not "upper left", + * This will rotate the output image accordingly. + */ + std::tuple, SkCodec::Result> getImage(const SkImageInfo& info, + const Options* opts = nullptr); + std::tuple, SkCodec::Result> getImage(); + + /** + * 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 kSuccess, or another value explaining the type of 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(). + */ + Result getYUVAPlanes(const SkYUVAPixmaps& yuvaPixmaps); + + /** + * Prepare for an incremental decode with the specified options. + * + * This may require a rewind. + * + * If kIncompleteInput is returned, may be called again after more data has + * been provided to the source SkStream. + * + * @param dstInfo Info of the destination. If the dimensions do not match + * those of getInfo, this implies a scale. + * @param dst Memory to write to. Needs to be large enough to hold the subset, + * if present, or the full image as described in dstInfo. + * @param options Contains decoding options, including if memory is zero + * initialized and whether to decode a subset. + * @return Enum representing success or reason for failure. + */ + Result startIncrementalDecode(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, + const Options*); + + Result startIncrementalDecode(const SkImageInfo& dstInfo, void* dst, size_t rowBytes) { + return this->startIncrementalDecode(dstInfo, dst, rowBytes, nullptr); + } + + /** + * Start/continue the incremental decode. + * + * Not valid to call before a call to startIncrementalDecode() returns + * kSuccess. + * + * If kIncompleteInput is returned, may be called again after more data has + * been provided to the source SkStream. + * + * Unlike getPixels and getScanlines, this does not do any filling. This is + * left up to the caller, since they may be skipping lines or continuing the + * decode later. In the latter case, they may choose to initialize all lines + * first, or only initialize the remaining lines after the first call. + * + * @param rowsDecoded Optional output variable returning the total number of + * lines initialized. Only meaningful if this method returns kIncompleteInput. + * Otherwise the implementation may not set it. + * Note that some implementations may have initialized this many rows, but + * not necessarily finished those rows (e.g. interlaced PNG). This may be + * useful for determining what rows the client needs to initialize. + * @return kSuccess if all lines requested in startIncrementalDecode have + * been completely decoded. kIncompleteInput otherwise. + */ + Result incrementalDecode(int* rowsDecoded = nullptr) { + if (!fStartedIncrementalDecode) { + return kInvalidParameters; + } + return this->onIncrementalDecode(rowsDecoded); + } + + /** + * The remaining functions revolve around decoding scanlines. + */ + + /** + * Prepare for a scanline decode with the specified options. + * + * After this call, this class will be ready to decode the first scanline. + * + * This must be called in order to call getScanlines or skipScanlines. + * + * This may require rewinding the stream. + * + * Not all SkCodecs support this. + * + * @param dstInfo Info of the destination. If the dimensions do not match + * those of getInfo, this implies a scale. + * @param options Contains decoding options, including if memory is zero + * initialized. + * @return Enum representing success or reason for failure. + */ + Result startScanlineDecode(const SkImageInfo& dstInfo, const Options* options); + + /** + * Simplified version of startScanlineDecode() that uses the default Options. + */ + Result startScanlineDecode(const SkImageInfo& dstInfo) { + return this->startScanlineDecode(dstInfo, nullptr); + } + + /** + * Write the next countLines scanlines into dst. + * + * Not valid to call before calling startScanlineDecode(). + * + * @param dst Must be non-null, and large enough to hold countLines + * scanlines of size rowBytes. + * @param countLines Number of lines to write. + * @param rowBytes Number of bytes per row. Must be large enough to hold + * a scanline based on the SkImageInfo used to create this object. + * @return the number of lines successfully decoded. If this value is + * less than countLines, this will fill the remaining lines with a + * default value. + */ + int getScanlines(void* dst, int countLines, size_t rowBytes); + + /** + * Skip count scanlines. + * + * Not valid to call before calling startScanlineDecode(). + * + * The default version just calls onGetScanlines and discards the dst. + * NOTE: If skipped lines are the only lines with alpha, this default + * will make reallyHasAlpha return true, when it could have returned + * false. + * + * @return true if the scanlines were successfully skipped + * false on failure, possible reasons for failure include: + * An incomplete input image stream. + * Calling this function before calling startScanlineDecode(). + * If countLines is less than zero or so large that it moves + * the current scanline past the end of the image. + */ + bool skipScanlines(int countLines); + + /** + * The order in which rows are output from the scanline decoder is not the + * same for all variations of all image types. This explains the possible + * output row orderings. + */ + enum SkScanlineOrder { + /* + * By far the most common, this indicates that the image can be decoded + * reliably using the scanline decoder, and that rows will be output in + * the logical order. + */ + kTopDown_SkScanlineOrder, + + /* + * This indicates that the scanline decoder reliably outputs rows, but + * they will be returned in reverse order. If the scanline format is + * kBottomUp, the nextScanline() API can be used to determine the actual + * y-coordinate of the next output row, but the client is not forced + * to take advantage of this, given that it's not too tough to keep + * track independently. + * + * For full image decodes, it is safe to get all of the scanlines at + * once, since the decoder will handle inverting the rows as it + * decodes. + * + * For subset decodes and sampling, it is simplest to get and skip + * scanlines one at a time, using the nextScanline() API. It is + * possible to ask for larger chunks at a time, but this should be used + * with caution. As with full image decodes, the decoder will handle + * inverting the requested rows, but rows will still be delivered + * starting from the bottom of the image. + * + * Upside down bmps are an example. + */ + kBottomUp_SkScanlineOrder, + }; + + /** + * An enum representing the order in which scanlines will be returned by + * the scanline decoder. + * + * This is undefined before startScanlineDecode() is called. + */ + SkScanlineOrder getScanlineOrder() const { return this->onGetScanlineOrder(); } + + /** + * Returns the y-coordinate of the next row to be returned by the scanline + * decoder. + * + * This will equal fCurrScanline, except in the case of strangely + * encoded image types (bottom-up bmps). + * + * Results are undefined when not in scanline decoding mode. + */ + int nextScanline() const { return this->outputScanline(fCurrScanline); } + + /** + * Returns the output y-coordinate of the row that corresponds to an input + * y-coordinate. The input y-coordinate represents where the scanline + * is located in the encoded data. + * + * This will equal inputScanline, except in the case of strangely + * encoded image types (bottom-up bmps, interlaced gifs). + */ + int outputScanline(int inputScanline) const; + + /** + * Return the number of frames in the image. + * + * May require reading through the stream. + */ + int getFrameCount() { + return this->onGetFrameCount(); + } + + // Sentinel value used when a frame index implies "no frame": + // - FrameInfo::fRequiredFrame set to this value means the frame + // is independent. + // - Options::fPriorFrame set to this value means no (relevant) prior frame + // is residing in dst's memory. + static constexpr int kNoFrame = -1; + + // This transitional definition was added in August 2018, and will eventually be removed. +#ifdef SK_LEGACY_SKCODEC_NONE_ENUM + static constexpr int kNone = kNoFrame; +#endif + + /** + * Information about individual frames in a multi-framed image. + */ + struct FrameInfo { + /** + * The frame that this frame needs to be blended with, or + * kNoFrame if this frame is independent (so it can be + * drawn over an uninitialized buffer). + * + * Note that this is the *earliest* frame that can be used + * for blending. Any frame from [fRequiredFrame, i) can be + * used, unless its fDisposalMethod is kRestorePrevious. + */ + int fRequiredFrame; + + /** + * Number of milliseconds to show this frame. + */ + int fDuration; + + /** + * Whether the end marker for this frame is contained in the stream. + * + * Note: this does not guarantee that an attempt to decode will be complete. + * There could be an error in the stream. + */ + bool fFullyReceived; + + /** + * This is conservative; it will still return non-opaque if e.g. a + * color index-based frame has a color with alpha but does not use it. + */ + SkAlphaType fAlphaType; + + /** + * Whether the updated rectangle contains alpha. + * + * This is conservative; it will still be set to true if e.g. a color + * index-based frame has a color with alpha but does not use it. In + * addition, it may be set to true, even if the final frame, after + * blending, is opaque. + */ + bool fHasAlphaWithinBounds; + + /** + * How this frame should be modified before decoding the next one. + */ + SkCodecAnimation::DisposalMethod fDisposalMethod; + + /** + * How this frame should blend with the prior frame. + */ + SkCodecAnimation::Blend fBlend; + + /** + * The rectangle updated by this frame. + * + * It may be empty, if the frame does not change the image. It will + * always be contained by SkCodec::dimensions(). + */ + SkIRect fFrameRect; + }; + + /** + * Return info about a single frame. + * + * Does not read through the stream, so it should be called after + * getFrameCount() to parse any frames that have not already been parsed. + * + * Only supported by animated (multi-frame) codecs. Note that this is a + * property of the codec (the SkCodec subclass), not the image. + * + * To elaborate, some codecs support animation (e.g. GIF). Others do not + * (e.g. BMP). Animated codecs can still represent single frame images. + * Calling getFrameInfo(0, etc) will return true for a single frame GIF + * even if the overall image is not animated (in that the pixels on screen + * do not change over time). When incrementally decoding a GIF image, we + * might only know that there's a single frame *so far*. + * + * For non-animated SkCodec subclasses, it's sufficient but not necessary + * for this method to always return false. + */ + bool getFrameInfo(int index, FrameInfo* info) const { + if (index < 0) { + return false; + } + return this->onGetFrameInfo(index, info); + } + + /** + * Return info about all the frames in the image. + * + * May require reading through the stream to determine info about the + * frames (including the count). + * + * As such, future decoding calls may require a rewind. + * + * This may return an empty vector for non-animated codecs. See the + * getFrameInfo(int, FrameInfo*) comment. + */ + std::vector getFrameInfo(); + + static constexpr int kRepetitionCountInfinite = -1; + + /** + * Return the number of times to repeat, if this image is animated. This number does not + * include the first play through of each frame. For example, a repetition count of 4 means + * that each frame is played 5 times and then the animation stops. + * + * It can return kRepetitionCountInfinite, a negative number, meaning that the animation + * should loop forever. + * + * May require reading the stream to find the repetition count. + * + * As such, future decoding calls may require a rewind. + * + * For still (non-animated) image codecs, this will return 0. + */ + int getRepetitionCount() { + return this->onGetRepetitionCount(); + } + + // Register a decoder at runtime by passing two function pointers: + // - peek() to return true if the span of bytes appears to be your encoded format; + // - make() to attempt to create an SkCodec from the given stream. + // Not thread safe. + static void Register( + bool (*peek)(const void*, size_t), + std::unique_ptr (*make)(std::unique_ptr, SkCodec::Result*)); + +protected: + const SkEncodedInfo& getEncodedInfo() const { return fEncodedInfo; } + + using XformFormat = skcms_PixelFormat; + + SkCodec(SkEncodedInfo&&, + XformFormat srcFormat, + std::unique_ptr, + SkEncodedOrigin = kTopLeft_SkEncodedOrigin); + + void setSrcXformFormat(XformFormat pixelFormat); + + XformFormat getSrcXformFormat() const { + return fSrcXformFormat; + } + + virtual bool onGetGainmapInfo(SkGainmapInfo*, std::unique_ptr*) { return false; } + + virtual SkISize onGetScaledDimensions(float /*desiredScale*/) const { + // By default, scaling is not supported. + return this->dimensions(); + } + + // FIXME: What to do about subsets?? + /** + * Subclasses should override if they support dimensions other than the + * srcInfo's. + */ + virtual bool onDimensionsSupported(const SkISize&) { + return false; + } + + virtual SkEncodedImageFormat onGetEncodedFormat() const = 0; + + /** + * @param rowsDecoded When the encoded image stream is incomplete, this function + * will return kIncompleteInput and rowsDecoded will be set to + * the number of scanlines that were successfully decoded. + * This will allow getPixels() to fill the uninitialized memory. + */ + virtual Result onGetPixels(const SkImageInfo& info, + void* pixels, size_t rowBytes, const Options&, + int* rowsDecoded) = 0; + + virtual bool onQueryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes&, + SkYUVAPixmapInfo*) const { return false; } + + virtual Result onGetYUVAPlanes(const SkYUVAPixmaps&) { return kUnimplemented; } + + virtual bool onGetValidSubset(SkIRect* /*desiredSubset*/) const { + // By default, subsets are not supported. + return false; + } + + /** + * If the stream was previously read, attempt to rewind. + * + * If the stream needed to be rewound, call onRewind. + * @returns true if the codec is at the right position and can be used. + * false if there was a failure to rewind. + * + * This is called by getPixels(), getYUV8Planes(), startIncrementalDecode() and + * startScanlineDecode(). Subclasses may call if they need to rewind at another time. + */ + [[nodiscard]] bool rewindIfNeeded(); + + /** + * Called by rewindIfNeeded, if the stream needed to be rewound. + * + * Subclasses should do any set up needed after a rewind. + */ + virtual bool onRewind() { + return true; + } + + /** + * Get method for the input stream + */ + SkStream* stream() { + return fStream.get(); + } + + /** + * The remaining functions revolve around decoding scanlines. + */ + + /** + * Most images types will be kTopDown and will not need to override this function. + */ + virtual SkScanlineOrder onGetScanlineOrder() const { return kTopDown_SkScanlineOrder; } + + const SkImageInfo& dstInfo() const { return fDstInfo; } + + const Options& options() const { return fOptions; } + + /** + * Returns the number of scanlines that have been decoded so far. + * This is unaffected by the SkScanlineOrder. + * + * Returns -1 if we have not started a scanline decode. + */ + int currScanline() const { return fCurrScanline; } + + virtual int onOutputScanline(int inputScanline) const; + + /** + * Return whether we can convert to dst. + * + * Will be called for the appropriate frame, prior to initializing the colorXform. + */ + virtual bool conversionSupported(const SkImageInfo& dst, bool srcIsOpaque, + bool needsColorXform); + + // Some classes never need a colorXform e.g. + // - ICO uses its embedded codec's colorXform + // - WBMP is just Black/White + virtual bool usesColorXform() const { return true; } + void applyColorXform(void* dst, const void* src, int count) const; + + bool colorXform() const { return fXformTime != kNo_XformTime; } + bool xformOnDecode() const { return fXformTime == kDecodeRow_XformTime; } + + virtual int onGetFrameCount() { + return 1; + } + + virtual bool onGetFrameInfo(int, FrameInfo*) const { + return false; + } + + virtual int onGetRepetitionCount() { + return 0; + } + +private: + const SkEncodedInfo fEncodedInfo; + XformFormat fSrcXformFormat; + std::unique_ptr fStream; + bool fNeedsRewind = false; + const SkEncodedOrigin fOrigin; + + SkImageInfo fDstInfo; + Options fOptions; + + enum XformTime { + kNo_XformTime, + kPalette_XformTime, + kDecodeRow_XformTime, + }; + XformTime fXformTime; + XformFormat fDstXformFormat; // Based on fDstInfo. + skcms_ICCProfile fDstProfile; + skcms_AlphaFormat fDstXformAlphaFormat; + + // Only meaningful during scanline decodes. + int fCurrScanline = -1; + + bool fStartedIncrementalDecode = false; + + // Allows SkAndroidCodec to call handleFrameIndex (potentially decoding a prior frame and + // clearing to transparent) without SkCodec itself calling it, too. + bool fUsingCallbackForHandleFrameIndex = false; + + bool initializeColorXform(const SkImageInfo& dstInfo, SkEncodedInfo::Alpha, bool srcIsOpaque); + + /** + * Return whether these dimensions are supported as a scale. + * + * The codec may choose to cache the information about scale and subset. + * Either way, the same information will be passed to onGetPixels/onStart + * on success. + * + * This must return true for a size returned from getScaledDimensions. + */ + bool dimensionsSupported(const SkISize& dim) { + return dim == this->dimensions() || this->onDimensionsSupported(dim); + } + + /** + * For multi-framed images, return the object with information about the frames. + */ + virtual const SkFrameHolder* getFrameHolder() const { + return nullptr; + } + + // Callback for decoding a prior frame. The `Options::fFrameIndex` is ignored, + // being replaced by frameIndex. This allows opts to actually be a subclass of + // SkCodec::Options which SkCodec itself does not know how to copy or modify, + // but just passes through to the caller (where it can be reinterpret_cast'd). + using GetPixelsCallback = std::function; + + /** + * Check for a valid Options.fFrameIndex, and decode prior frames if necessary. + * + * If GetPixelsCallback is not null, it will be used to decode a prior frame instead + * of using this SkCodec directly. It may also be used recursively, if that in turn + * depends on a prior frame. This is used by SkAndroidCodec. + */ + Result handleFrameIndex(const SkImageInfo&, void* pixels, size_t rowBytes, const Options&, + GetPixelsCallback = nullptr); + + // Methods for scanline decoding. + virtual Result onStartScanlineDecode(const SkImageInfo& /*dstInfo*/, + const Options& /*options*/) { + return kUnimplemented; + } + + virtual Result onStartIncrementalDecode(const SkImageInfo& /*dstInfo*/, void*, size_t, + const Options&) { + return kUnimplemented; + } + + virtual Result onIncrementalDecode(int*) { + return kUnimplemented; + } + + + virtual bool onSkipScanlines(int /*countLines*/) { return false; } + + virtual int onGetScanlines(void* /*dst*/, int /*countLines*/, size_t /*rowBytes*/) { return 0; } + + /** + * On an incomplete decode, getPixels() and getScanlines() will call this function + * to fill any uinitialized memory. + * + * @param dstInfo Contains the destination color type + * Contains the destination alpha type + * Contains the destination width + * The height stored in this info is unused + * @param dst Pointer to the start of destination pixel memory + * @param rowBytes Stride length in destination pixel memory + * @param zeroInit Indicates if memory is zero initialized + * @param linesRequested Number of lines that the client requested + * @param linesDecoded Number of lines that were successfully decoded + */ + void fillIncompleteImage(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, + ZeroInitialized zeroInit, int linesRequested, int linesDecoded); + + /** + * Return an object which will allow forcing scanline decodes to sample in X. + * + * May create a sampler, if one is not currently being used. Otherwise, does + * not affect ownership. + * + * Only valid during scanline decoding or incremental decoding. + */ + virtual SkSampler* getSampler(bool /*createIfNecessary*/) { return nullptr; } + + friend class DM::CodecSrc; // for fillIncompleteImage + friend class PNGCodecGM; // for fillIncompleteImage + friend class SkSampledCodec; + friend class SkIcoCodec; + friend class SkAndroidCodec; // for fEncodedInfo + friend class SkPDFBitmap; // for fEncodedInfo +}; + +namespace SkCodecs { + +using DecodeContext = void*; +using IsFormatCallback = bool (*)(const void* data, size_t len); +using MakeFromStreamCallback = std::unique_ptr (*)(std::unique_ptr, + SkCodec::Result*, + DecodeContext); + +struct SK_API Decoder { + // By convention, we use all lowercase letters and go with the primary filename extension. + // For example "png", "jpg", "ico", "webp", etc + std::string_view id; + IsFormatCallback isFormat; + MakeFromStreamCallback makeFromStream; +}; + +// Add the decoder to the end of a linked list of decoders, which will be used to identify calls to +// SkCodec::MakeFromStream. If a decoder with the same id already exists, this new decoder +// will replace the existing one (in the same position). This is not thread-safe, so make sure all +// initialization is done before the first call. +void SK_API Register(Decoder d); + +/** + * Return a SkImage produced by the codec, but attempts to defer image allocation 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. + * + * @param codec A non-null codec (e.g. from SkPngDecoder::Decode) + * @return created SkImage, or nullptr + */ +SK_API sk_sp DeferredImage(std::unique_ptr codec, + std::optional alphaType = std::nullopt); +} + +#endif // SkCodec_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkCodecAnimation.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkCodecAnimation.h new file mode 100644 index 0000000000..c5883e2af2 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkCodecAnimation.h @@ -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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkEncodedImageFormat.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkEncodedImageFormat.h new file mode 100644 index 0000000000..e664c7db02 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkEncodedImageFormat.h @@ -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 + +/** + * 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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkEncodedOrigin.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkEncodedOrigin.h new file mode 100644 index 0000000000..19d083672f --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkEncodedOrigin.h @@ -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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkGifDecoder.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkGifDecoder.h new file mode 100644 index 0000000000..7344b26647 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkGifDecoder.h @@ -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 + +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 Decode(std::unique_ptr, + SkCodec::Result*, + SkCodecs::DecodeContext = nullptr); +SK_API std::unique_ptr Decode(sk_sp, + SkCodec::Result*, + SkCodecs::DecodeContext = nullptr); + +inline constexpr SkCodecs::Decoder Decoder() { + return { "gif", IsGif, Decode }; +} + +} // namespace SkGifDecoder + +#endif // SkGifDecoder_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkIcoDecoder.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkIcoDecoder.h new file mode 100644 index 0000000000..e0d361d685 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkIcoDecoder.h @@ -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 + +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 Decode(std::unique_ptr, + SkCodec::Result*, + SkCodecs::DecodeContext = nullptr); +SK_API std::unique_ptr Decode(sk_sp, + SkCodec::Result*, + SkCodecs::DecodeContext = nullptr); + +inline constexpr SkCodecs::Decoder Decoder() { + return { "ico", IsIco, Decode }; +} + +} // namespace SkIcoDecoder + +#endif // SkIcoDecoder_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkJpegDecoder.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkJpegDecoder.h new file mode 100644 index 0000000000..10a340f5bf --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkJpegDecoder.h @@ -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 + +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 Decode(std::unique_ptr, + SkCodec::Result*, + SkCodecs::DecodeContext = nullptr); +SK_API std::unique_ptr Decode(sk_sp, + SkCodec::Result*, + SkCodecs::DecodeContext = nullptr); + +inline constexpr SkCodecs::Decoder Decoder() { + return { "jpeg", IsJpeg, Decode }; +} + +} // namespace SkJpegDecoder + +#endif // SkJpegDecoder_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkJpegxlDecoder.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkJpegxlDecoder.h new file mode 100644 index 0000000000..4ab73f8270 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkJpegxlDecoder.h @@ -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 + +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 Decode(std::unique_ptr, + SkCodec::Result*, + SkCodecs::DecodeContext = nullptr); +SK_API std::unique_ptr Decode(sk_sp, + SkCodec::Result*, + SkCodecs::DecodeContext = nullptr); + +inline constexpr SkCodecs::Decoder Decoder() { + return { "jpegxl", IsJpegxl, Decode }; +} + +} // namespace SkJpegxlDecoder + +#endif // SkJpegxlDecoder_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkPixmapUtils.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkPixmapUtils.h new file mode 100644 index 0000000000..0df4a36f0c --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkPixmapUtils.h @@ -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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkPngChunkReader.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkPngChunkReader.h new file mode 100644 index 0000000000..0ee8a9ecc7 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkPngChunkReader.h @@ -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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkPngDecoder.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkPngDecoder.h new file mode 100644 index 0000000000..e761d2e216 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkPngDecoder.h @@ -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 + +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 Decode(std::unique_ptr, + SkCodec::Result*, + SkCodecs::DecodeContext = nullptr); +SK_API std::unique_ptr Decode(sk_sp, + SkCodec::Result*, + SkCodecs::DecodeContext = nullptr); + +inline constexpr SkCodecs::Decoder Decoder() { + return { "png", IsPng, Decode }; +} + +} // namespace SkPngDecoder + +#endif // SkPngDecoder_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkRawDecoder.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkRawDecoder.h new file mode 100644 index 0000000000..3f56012212 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkRawDecoder.h @@ -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 + +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 Decode(std::unique_ptr, + SkCodec::Result*, + SkCodecs::DecodeContext = nullptr); +SK_API std::unique_ptr Decode(sk_sp, + 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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkWbmpDecoder.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkWbmpDecoder.h new file mode 100644 index 0000000000..7e5e7706df --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkWbmpDecoder.h @@ -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 + +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 Decode(std::unique_ptr, + SkCodec::Result*, + SkCodecs::DecodeContext = nullptr); +SK_API std::unique_ptr Decode(sk_sp, + SkCodec::Result*, + SkCodecs::DecodeContext = nullptr); + +inline constexpr SkCodecs::Decoder Decoder() { + return { "wbmp", IsWbmp, Decode }; +} + +} // namespace SkWbmpDecoder + +#endif // SkWbmpDecoder_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkWebpDecoder.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkWebpDecoder.h new file mode 100644 index 0000000000..5f8032f0fe --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/codec/SkWebpDecoder.h @@ -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 + +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 Decode(std::unique_ptr, + SkCodec::Result*, + SkCodecs::DecodeContext = nullptr); +SK_API std::unique_ptr Decode(sk_sp, + SkCodec::Result*, + SkCodecs::DecodeContext = nullptr); + +inline constexpr SkCodecs::Decoder Decoder() { + return { "webp", IsWebp, Decode }; +} + +} // namespace SkWebpDecoder + +#endif // SkWebpDecoder_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/config/OWNERS b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/config/OWNERS new file mode 100644 index 0000000000..25b714bb27 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/config/OWNERS @@ -0,0 +1,2 @@ +bungeman@google.com +kjlubick@google.com \ No newline at end of file diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/config/SkUserConfig.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/config/SkUserConfig.h new file mode 100644 index 0000000000..8ac155b481 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/config/SkUserConfig.h @@ -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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkAlphaType.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkAlphaType.h new file mode 100644 index 0000000000..0c99906dfd --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkAlphaType.h @@ -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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkAnnotation.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkAnnotation.h new file mode 100644 index 0000000000..2006f309e9 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkAnnotation.h @@ -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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkArc.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkArc.h new file mode 100644 index 0000000000..9e530ebd2b --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkArc.h @@ -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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkBBHFactory.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkBBHFactory.h new file mode 100644 index 0000000000..5d9f9009ac --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkBBHFactory.h @@ -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 +#include + +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* 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 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 operator()() const override; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkBitmap.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkBitmap.h new file mode 100644 index 0000000000..1875c5f37e --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkBitmap.h @@ -0,0 +1,1275 @@ +/* + * 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 SkBitmap_DEFINED +#define SkBitmap_DEFINED + +#include "include/core/SkAlphaType.h" +#include "include/core/SkColor.h" +#include "include/core/SkImageInfo.h" +#include "include/core/SkPixmap.h" +#include "include/core/SkPoint.h" +#include "include/core/SkRect.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkSamplingOptions.h" +#include "include/core/SkSize.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkCPUTypes.h" +#include "include/private/base/SkDebug.h" + +#include +#include + +class SkColorSpace; +class SkImage; +class SkMatrix; +class SkMipmap; +class SkPaint; +class SkPixelRef; +class SkShader; +enum SkColorType : int; +enum class SkTileMode; +struct SkMaskBuilder; + +/** \class SkBitmap + SkBitmap describes a two-dimensional raster pixel array. SkBitmap is built on + SkImageInfo, containing integer width and height, SkColorType and SkAlphaType + describing the pixel format, and SkColorSpace describing the range of colors. + SkBitmap points to SkPixelRef, which describes the physical array of pixels. + SkImageInfo bounds may be located anywhere fully inside SkPixelRef bounds. + + SkBitmap can be drawn using SkCanvas. SkBitmap can be a drawing destination for SkCanvas + draw member functions. SkBitmap flexibility as a pixel container limits some + optimizations available to the target platform. + + If pixel array is primarily read-only, use SkImage for better performance. + If pixel array is primarily written to, use SkSurface for better performance. + + Declaring SkBitmap const prevents altering SkImageInfo: the SkBitmap height, width, + and so on cannot change. It does not affect SkPixelRef: a caller may write its + pixels. Declaring SkBitmap const affects SkBitmap configuration, not its contents. + + SkBitmap is not thread safe. Each thread must have its own copy of SkBitmap fields, + although threads may share the underlying pixel array. +*/ +class SK_API SkBitmap { +public: + class SK_API Allocator; + + /** Creates an empty SkBitmap without pixels, with kUnknown_SkColorType, + kUnknown_SkAlphaType, and with a width and height of zero. SkPixelRef origin is + set to (0, 0). + + Use setInfo() to associate SkColorType, SkAlphaType, width, and height + after SkBitmap has been created. + + @return empty SkBitmap + + example: https://fiddle.skia.org/c/@Bitmap_empty_constructor + */ + SkBitmap(); + + /** Copies settings from src to returned SkBitmap. Shares pixels if src has pixels + allocated, so both bitmaps reference the same pixels. + + @param src SkBitmap to copy SkImageInfo, and share SkPixelRef + @return copy of src + + example: https://fiddle.skia.org/c/@Bitmap_copy_const_SkBitmap + */ + SkBitmap(const SkBitmap& src); + + /** Copies settings from src to returned SkBitmap. Moves ownership of src pixels to + SkBitmap. + + @param src SkBitmap to copy SkImageInfo, and reassign SkPixelRef + @return copy of src + + example: https://fiddle.skia.org/c/@Bitmap_move_SkBitmap + */ + SkBitmap(SkBitmap&& src); + + /** Decrements SkPixelRef reference count, if SkPixelRef is not nullptr. + */ + ~SkBitmap(); + + /** Copies settings from src to returned SkBitmap. Shares pixels if src has pixels + allocated, so both bitmaps reference the same pixels. + + @param src SkBitmap to copy SkImageInfo, and share SkPixelRef + @return copy of src + + example: https://fiddle.skia.org/c/@Bitmap_copy_operator + */ + SkBitmap& operator=(const SkBitmap& src); + + /** Copies settings from src to returned SkBitmap. Moves ownership of src pixels to + SkBitmap. + + @param src SkBitmap to copy SkImageInfo, and reassign SkPixelRef + @return copy of src + + example: https://fiddle.skia.org/c/@Bitmap_move_operator + */ + SkBitmap& operator=(SkBitmap&& src); + + /** Swaps the fields of the two bitmaps. + + @param other SkBitmap exchanged with original + + example: https://fiddle.skia.org/c/@Bitmap_swap + */ + void swap(SkBitmap& other); + + /** Returns a constant reference to the SkPixmap holding the SkBitmap pixel + address, row bytes, and SkImageInfo. + + @return reference to SkPixmap describing this SkBitmap + */ + const SkPixmap& pixmap() const { return fPixmap; } + + /** Returns width, height, SkAlphaType, SkColorType, and SkColorSpace. + + @return reference to SkImageInfo + */ + const SkImageInfo& info() const { return fPixmap.info(); } + + /** Returns pixel count in each row. Should be equal or less than + rowBytes() / info().bytesPerPixel(). + + May be less than pixelRef().width(). Will not exceed pixelRef().width() less + pixelRefOrigin().fX. + + @return pixel width in SkImageInfo + */ + int width() const { return fPixmap.width(); } + + /** Returns pixel row count. + + Maybe be less than pixelRef().height(). Will not exceed pixelRef().height() less + pixelRefOrigin().fY. + + @return pixel height in SkImageInfo + */ + int height() const { return fPixmap.height(); } + + SkColorType colorType() const { return fPixmap.colorType(); } + + SkAlphaType alphaType() const { return fPixmap.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 refColorSpace() 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 fPixmap.info().bytesPerPixel(); } + + /** 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 fPixmap.rowBytesAsPixels(); } + + /** 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 fPixmap.shiftPerPixel(); } + + /** Returns true if either width() or height() are zero. + + Does not check if SkPixelRef is nullptr; call drawsNothing() to check width(), + height(), and SkPixelRef. + + @return true if dimensions do not enclose area + */ + bool empty() const { return fPixmap.info().isEmpty(); } + + /** Returns true if SkPixelRef is nullptr. + + Does not check if width() or height() are zero; call drawsNothing() to check + width(), height(), and SkPixelRef. + + @return true if no SkPixelRef is associated + */ + bool isNull() const { return nullptr == fPixelRef; } + + /** Returns true if width() or height() are zero, or if SkPixelRef is nullptr. + If true, SkBitmap has no effect when drawn or drawn into. + + @return true if drawing has no effect + */ + bool drawsNothing() const { + return this->empty() || this->isNull(); + } + + /** 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, or if row bytes supplied to + setInfo() is not large enough to hold a row of pixels. + + @return byte length of pixel row + */ + size_t rowBytes() const { return fPixmap.rowBytes(); } + + /** Sets SkAlphaType, if alphaType is compatible with SkColorType. + Returns true unless alphaType is kUnknown_SkAlphaType and current SkAlphaType + is not kUnknown_SkAlphaType. + + Returns true if SkColorType is kUnknown_SkColorType. alphaType is ignored, and + SkAlphaType remains kUnknown_SkAlphaType. + + Returns true if SkColorType is kRGB_565_SkColorType or kGray_8_SkColorType. + alphaType is ignored, and SkAlphaType remains kOpaque_SkAlphaType. + + If SkColorType is kARGB_4444_SkColorType, kRGBA_8888_SkColorType, + kBGRA_8888_SkColorType, or kRGBA_F16_SkColorType: returns true unless + alphaType is kUnknown_SkAlphaType and SkAlphaType is not kUnknown_SkAlphaType. + If SkAlphaType is kUnknown_SkAlphaType, alphaType is ignored. + + If SkColorType is kAlpha_8_SkColorType, returns true unless + alphaType is kUnknown_SkAlphaType and SkAlphaType is not kUnknown_SkAlphaType. + If SkAlphaType is kUnknown_SkAlphaType, alphaType is ignored. If alphaType is + kUnpremul_SkAlphaType, it is treated as kPremul_SkAlphaType. + + This changes SkAlphaType in SkPixelRef; all bitmaps sharing SkPixelRef + are affected. + + @return true if SkAlphaType is set + + example: https://fiddle.skia.org/c/@Bitmap_setAlphaType + */ + bool setAlphaType(SkAlphaType alphaType); + + /** Sets the SkColorSpace associated with this SkBitmap. + + The raw pixel data is not altered by this call; no conversion is + performed. + + This changes SkColorSpace in SkPixelRef; all bitmaps sharing SkPixelRef + are affected. + */ + void setColorSpace(sk_sp colorSpace); + + /** Returns pixel address, the base address corresponding to the pixel origin. + + @return pixel address + */ + void* getPixels() const { return fPixmap.writable_addr(); } + + /** 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 fPixmap.computeByteSize(); } + + /** Returns true if pixels can not change. + + Most immutable SkBitmap checks trigger an assert only on debug builds. + + @return true if pixels are immutable + + example: https://fiddle.skia.org/c/@Bitmap_isImmutable + */ + bool isImmutable() const; + + /** Sets internal flag to mark SkBitmap as immutable. Once set, pixels can not change. + Any other bitmap sharing the same SkPixelRef are also marked as immutable. + Once SkPixelRef is marked immutable, the setting cannot be cleared. + + Writing to immutable SkBitmap pixels triggers an assert on debug builds. + + example: https://fiddle.skia.org/c/@Bitmap_setImmutable + */ + void setImmutable(); + + /** 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 SkImageInfo SkAlphaType is kOpaque_SkAlphaType + */ + bool isOpaque() const { + return SkAlphaTypeIsOpaque(this->alphaType()); + } + + /** Resets to its initial state; all fields are set to zero, as if SkBitmap had + been initialized by SkBitmap(). + + Sets width, height, row bytes to zero; pixel address to nullptr; SkColorType to + kUnknown_SkColorType; and SkAlphaType to kUnknown_SkAlphaType. + + If SkPixelRef is allocated, its reference count is decreased by one, releasing + its memory if SkBitmap is the sole owner. + + example: https://fiddle.skia.org/c/@Bitmap_reset + */ + void reset(); + + /** 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. + + @param bm SkBitmap to check + @return true if all pixels have opaque values or SkColorType is opaque + */ + static bool ComputeIsOpaque(const SkBitmap& bm) { + return bm.pixmap().computeIsOpaque(); + } + + /** Returns SkRect { 0, 0, width(), height() }. + + @param bounds container for floating point rectangle + + example: https://fiddle.skia.org/c/@Bitmap_getBounds + */ + void getBounds(SkRect* bounds) const; + + /** Returns SkIRect { 0, 0, width(), height() }. + + @param bounds container for integral rectangle + + example: https://fiddle.skia.org/c/@Bitmap_getBounds_2 + */ + void getBounds(SkIRect* bounds) const; + + /** Returns SkIRect { 0, 0, width(), height() }. + + @return integral rectangle from origin to width() and height() + */ + SkIRect bounds() const { return fPixmap.info().bounds(); } + + /** Returns SkISize { width(), height() }. + + @return integral size of width() and height() + */ + SkISize dimensions() const { return fPixmap.info().dimensions(); } + + /** Returns the bounds of this bitmap, offset by its SkPixelRef origin. + + @return bounds within SkPixelRef bounds + */ + SkIRect getSubset() const { + SkIPoint origin = this->pixelRefOrigin(); + return SkIRect::MakeXYWH(origin.x(), origin.y(), this->width(), this->height()); + } + + /** Sets width, height, SkAlphaType, SkColorType, SkColorSpace, and optional + rowBytes. Frees pixels, and returns true if successful. + + imageInfo.alphaType() may be altered to a value permitted by imageInfo.colorSpace(). + If imageInfo.colorType() is kUnknown_SkColorType, imageInfo.alphaType() is + set to kUnknown_SkAlphaType. + If imageInfo.colorType() is kAlpha_8_SkColorType and imageInfo.alphaType() is + kUnpremul_SkAlphaType, imageInfo.alphaType() is replaced by kPremul_SkAlphaType. + If imageInfo.colorType() is kRGB_565_SkColorType or kGray_8_SkColorType, + imageInfo.alphaType() is set to kOpaque_SkAlphaType. + If imageInfo.colorType() is kARGB_4444_SkColorType, kRGBA_8888_SkColorType, + kBGRA_8888_SkColorType, or kRGBA_F16_SkColorType: imageInfo.alphaType() remains + unchanged. + + rowBytes must equal or exceed imageInfo.minRowBytes(). If imageInfo.colorSpace() is + kUnknown_SkColorType, rowBytes is ignored and treated as zero; for all other + SkColorSpace values, rowBytes of zero is treated as imageInfo.minRowBytes(). + + Calls reset() and returns false if: + - rowBytes exceeds 31 bits + - imageInfo.width() is negative + - imageInfo.height() is negative + - rowBytes is positive and less than imageInfo.width() times imageInfo.bytesPerPixel() + + @param imageInfo contains width, height, SkAlphaType, SkColorType, SkColorSpace + @param rowBytes imageInfo.minRowBytes() or larger; or zero + @return true if SkImageInfo set successfully + + example: https://fiddle.skia.org/c/@Bitmap_setInfo + */ + bool setInfo(const SkImageInfo& imageInfo, size_t rowBytes = 0); + + /** \enum SkBitmap::AllocFlags + AllocFlags is obsolete. We always zero pixel memory when allocated. + */ + enum AllocFlags { + kZeroPixels_AllocFlag = 1 << 0, //!< zero pixel memory. No effect. This is the default. + }; + + /** Sets SkImageInfo to info following the rules in setInfo() and allocates pixel + memory. Memory is zeroed. + + Returns false and calls reset() if SkImageInfo could not be set, or memory could + not be allocated, or memory could not optionally be zeroed. + + On most platforms, allocating pixel memory may succeed even though there is + not sufficient memory to hold pixels; allocation does not take place + until the pixels are written to. The actual behavior depends on the platform + implementation of calloc(). + + @param info contains width, height, SkAlphaType, SkColorType, SkColorSpace + @param flags kZeroPixels_AllocFlag, or zero + @return true if pixels allocation is successful + */ + [[nodiscard]] bool tryAllocPixelsFlags(const SkImageInfo& info, uint32_t flags); + + /** Sets SkImageInfo to info following the rules in setInfo() and allocates pixel + memory. Memory is zeroed. + + Aborts execution if SkImageInfo could not be set, or memory could + not be allocated, or memory could not optionally + be zeroed. Abort steps may be provided by the user at compile time by defining + SK_ABORT. + + On most platforms, allocating pixel memory may succeed even though there is + not sufficient memory to hold pixels; allocation does not take place + until the pixels are written to. The actual behavior depends on the platform + implementation of calloc(). + + @param info contains width, height, SkAlphaType, SkColorType, SkColorSpace + @param flags kZeroPixels_AllocFlag, or zero + + example: https://fiddle.skia.org/c/@Bitmap_allocPixelsFlags + */ + void allocPixelsFlags(const SkImageInfo& info, uint32_t flags); + + /** Sets SkImageInfo to info following the rules in setInfo() and allocates pixel + memory. rowBytes must equal or exceed info.width() times info.bytesPerPixel(), + or equal zero. Pass in zero for rowBytes to compute the minimum valid value. + + Returns false and calls reset() if SkImageInfo could not be set, or memory could + not be allocated. + + On most platforms, allocating pixel memory may succeed even though there is + not sufficient memory to hold pixels; allocation does not take place + until the pixels are written to. The actual behavior depends on the platform + implementation of malloc(). + + @param info contains width, height, SkAlphaType, SkColorType, SkColorSpace + @param rowBytes size of pixel row or larger; may be zero + @return true if pixel storage is allocated + */ + [[nodiscard]] bool tryAllocPixels(const SkImageInfo& info, size_t rowBytes); + + /** Sets SkImageInfo to info following the rules in setInfo() and allocates pixel + memory. rowBytes must equal or exceed info.width() times info.bytesPerPixel(), + or equal zero. Pass in zero for rowBytes to compute the minimum valid value. + + Aborts execution if SkImageInfo could not be set, or memory could + not be allocated. Abort steps may be provided by + the user at compile time by defining SK_ABORT. + + On most platforms, allocating pixel memory may succeed even though there is + not sufficient memory to hold pixels; allocation does not take place + until the pixels are written to. The actual behavior depends on the platform + implementation of malloc(). + + @param info contains width, height, SkAlphaType, SkColorType, SkColorSpace + @param rowBytes size of pixel row or larger; may be zero + + example: https://fiddle.skia.org/c/@Bitmap_allocPixels + */ + void allocPixels(const SkImageInfo& info, size_t rowBytes); + + /** Sets SkImageInfo to info following the rules in setInfo() and allocates pixel + memory. + + Returns false and calls reset() if SkImageInfo could not be set, or memory could + not be allocated. + + On most platforms, allocating pixel memory may succeed even though there is + not sufficient memory to hold pixels; allocation does not take place + until the pixels are written to. The actual behavior depends on the platform + implementation of malloc(). + + @param info contains width, height, SkAlphaType, SkColorType, SkColorSpace + @return true if pixel storage is allocated + */ + [[nodiscard]] bool tryAllocPixels(const SkImageInfo& info) { + return this->tryAllocPixels(info, info.minRowBytes()); + } + + /** Sets SkImageInfo to info following the rules in setInfo() and allocates pixel + memory. + + Aborts execution if SkImageInfo could not be set, or memory could + not be allocated. Abort steps may be provided by + the user at compile time by defining SK_ABORT. + + On most platforms, allocating pixel memory may succeed even though there is + not sufficient memory to hold pixels; allocation does not take place + until the pixels are written to. The actual behavior depends on the platform + implementation of malloc(). + + @param info contains width, height, SkAlphaType, SkColorType, SkColorSpace + + example: https://fiddle.skia.org/c/@Bitmap_allocPixels_2 + */ + void allocPixels(const SkImageInfo& info); + + /** Sets SkImageInfo to width, height, and native color type; and allocates + pixel memory. If isOpaque is true, sets SkImageInfo to kOpaque_SkAlphaType; + otherwise, sets to kPremul_SkAlphaType. + + Calls reset() and returns false if width exceeds 29 bits or is negative, + or height is negative. + + Returns false if allocation fails. + + Use to create SkBitmap that matches SkPMColor, the native pixel arrangement on + the platform. SkBitmap drawn to output device skips converting its pixel format. + + @param width pixel column count; must be zero or greater + @param height pixel row count; must be zero or greater + @param isOpaque true if pixels do not have transparency + @return true if pixel storage is allocated + */ + [[nodiscard]] bool tryAllocN32Pixels(int width, int height, bool isOpaque = false); + + /** Sets SkImageInfo to width, height, and the native color type; and allocates + pixel memory. If isOpaque is true, sets SkImageInfo to kOpaque_SkAlphaType; + otherwise, sets to kPremul_SkAlphaType. + + Aborts if width exceeds 29 bits or is negative, or height is negative, or + allocation fails. Abort steps may be provided by the user at compile time by + defining SK_ABORT. + + Use to create SkBitmap that matches SkPMColor, the native pixel arrangement on + the platform. SkBitmap drawn to output device skips converting its pixel format. + + @param width pixel column count; must be zero or greater + @param height pixel row count; must be zero or greater + @param isOpaque true if pixels do not have transparency + + example: https://fiddle.skia.org/c/@Bitmap_allocN32Pixels + */ + void allocN32Pixels(int width, int height, bool isOpaque = false); + + /** Sets SkImageInfo to info following the rules in setInfo(), and creates SkPixelRef + containing pixels and rowBytes. releaseProc, if not nullptr, is called + immediately on failure or when pixels are no longer referenced. context may be + nullptr. + + If SkImageInfo could not be set, or rowBytes is less than info.minRowBytes(): + calls releaseProc if present, calls reset(), and returns false. + + Otherwise, if pixels equals nullptr: sets SkImageInfo, calls releaseProc if + present, returns true. + + If SkImageInfo is set, pixels is not nullptr, and releaseProc is not nullptr: + when pixels are no longer referenced, calls releaseProc with pixels and context + as parameters. + + @param info contains width, height, SkAlphaType, SkColorType, SkColorSpace + @param pixels address or pixel storage; may be nullptr + @param rowBytes size of pixel row or larger + @param releaseProc function called when pixels can be deleted; may be nullptr + @param context caller state passed to releaseProc; may be nullptr + @return true if SkImageInfo is set to info + */ + bool installPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, + void (*releaseProc)(void* addr, void* context), void* context); + + /** Sets SkImageInfo to info following the rules in setInfo(), and creates SkPixelRef + containing pixels and rowBytes. + + If SkImageInfo could not be set, or rowBytes is less than info.minRowBytes(): + calls reset(), and returns false. + + Otherwise, if pixels equals nullptr: sets SkImageInfo, returns true. + + Caller must ensure that pixels are valid for the lifetime of SkBitmap and SkPixelRef. + + @param info contains width, height, SkAlphaType, SkColorType, SkColorSpace + @param pixels address or pixel storage; may be nullptr + @param rowBytes size of pixel row or larger + @return true if SkImageInfo is set to info + */ + bool installPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) { + return this->installPixels(info, pixels, rowBytes, nullptr, nullptr); + } + + /** Sets SkImageInfo to pixmap.info() following the rules in setInfo(), and creates + SkPixelRef containing pixmap.addr() and pixmap.rowBytes(). + + If SkImageInfo could not be set, or pixmap.rowBytes() is less than + SkImageInfo::minRowBytes(): calls reset(), and returns false. + + Otherwise, if pixmap.addr() equals nullptr: sets SkImageInfo, returns true. + + Caller must ensure that pixmap is valid for the lifetime of SkBitmap and SkPixelRef. + + @param pixmap SkImageInfo, pixel address, and rowBytes() + @return true if SkImageInfo was set to pixmap.info() + + example: https://fiddle.skia.org/c/@Bitmap_installPixels_3 + */ + bool installPixels(const SkPixmap& pixmap); + + /** Deprecated. + */ + bool installMaskPixels(SkMaskBuilder& mask); + + /** Replaces SkPixelRef with pixels, preserving SkImageInfo and rowBytes(). + Sets SkPixelRef origin to (0, 0). + + If pixels is nullptr, or if info().colorType() equals kUnknown_SkColorType; + release reference to SkPixelRef, and set SkPixelRef to nullptr. + + Caller is responsible for handling ownership pixel memory for the lifetime + of SkBitmap and SkPixelRef. + + @param pixels address of pixel storage, managed by caller + + example: https://fiddle.skia.org/c/@Bitmap_setPixels + */ + void setPixels(void* pixels); + + /** Allocates pixel memory with HeapAllocator, and replaces existing SkPixelRef. + The allocation size is determined by SkImageInfo width, height, and SkColorType. + + Returns false if info().colorType() is kUnknown_SkColorType, or allocation fails. + + @return true if the allocation succeeds + */ + [[nodiscard]] bool tryAllocPixels() { + return this->tryAllocPixels((Allocator*)nullptr); + } + + /** Allocates pixel memory with HeapAllocator, and replaces existing SkPixelRef. + The allocation size is determined by SkImageInfo width, height, and SkColorType. + + Aborts if info().colorType() is kUnknown_SkColorType, or allocation fails. + Abort steps may be provided by the user at compile + time by defining SK_ABORT. + + example: https://fiddle.skia.org/c/@Bitmap_allocPixels_3 + */ + void allocPixels(); + + /** Allocates pixel memory with allocator, and replaces existing SkPixelRef. + The allocation size is determined by SkImageInfo width, height, and SkColorType. + If allocator is nullptr, use HeapAllocator instead. + + Returns false if Allocator::allocPixelRef return false. + + @param allocator instance of SkBitmap::Allocator instantiation + @return true if custom allocator reports success + */ + [[nodiscard]] bool tryAllocPixels(Allocator* allocator); + + /** Allocates pixel memory with allocator, and replaces existing SkPixelRef. + The allocation size is determined by SkImageInfo width, height, and SkColorType. + If allocator is nullptr, use HeapAllocator instead. + + Aborts if Allocator::allocPixelRef return false. Abort steps may be provided by + the user at compile time by defining SK_ABORT. + + @param allocator instance of SkBitmap::Allocator instantiation + + example: https://fiddle.skia.org/c/@Bitmap_allocPixels_4 + */ + void allocPixels(Allocator* allocator); + + /** Returns SkPixelRef, which contains: pixel base address; its dimensions; and + rowBytes(), the interval from one row to the next. Does not change SkPixelRef + reference count. SkPixelRef may be shared by multiple bitmaps. + If SkPixelRef has not been set, returns nullptr. + + @return SkPixelRef, or nullptr + */ + SkPixelRef* pixelRef() const { return fPixelRef.get(); } + + /** Returns origin of pixels within SkPixelRef. SkBitmap bounds is always contained + by SkPixelRef bounds, which may be the same size or larger. Multiple SkBitmap + can share the same SkPixelRef, where each SkBitmap has different bounds. + + The returned origin added to SkBitmap dimensions equals or is smaller than the + SkPixelRef dimensions. + + Returns (0, 0) if SkPixelRef is nullptr. + + @return pixel origin within SkPixelRef + + example: https://fiddle.skia.org/c/@Bitmap_pixelRefOrigin + */ + SkIPoint pixelRefOrigin() const; + + /** Replaces pixelRef and origin in SkBitmap. dx and dy specify the offset + within the SkPixelRef pixels for the top-left corner of the bitmap. + + Asserts in debug builds if dx or dy are out of range. Pins dx and dy + to legal range in release builds. + + The caller is responsible for ensuring that the pixels match the + SkColorType and SkAlphaType in SkImageInfo. + + @param pixelRef SkPixelRef describing pixel address and rowBytes() + @param dx column offset in SkPixelRef for bitmap origin + @param dy row offset in SkPixelRef for bitmap origin + + example: https://fiddle.skia.org/c/@Bitmap_setPixelRef + */ + void setPixelRef(sk_sp pixelRef, int dx, int dy); + + /** Returns true if SkBitmap is can be drawn. + + @return true if getPixels() is not nullptr + */ + bool readyToDraw() const { + return this->getPixels() != nullptr; + } + + /** Returns a unique value corresponding to the pixels in SkPixelRef. + Returns a different value after notifyPixelsChanged() has been called. + Returns zero if SkPixelRef is nullptr. + + Determines if pixels have changed since last examined. + + @return unique value for pixels in SkPixelRef + + example: https://fiddle.skia.org/c/@Bitmap_getGenerationID + */ + uint32_t getGenerationID() const; + + /** Marks that pixels in SkPixelRef have changed. Subsequent calls to + getGenerationID() return a different value. + + example: https://fiddle.skia.org/c/@Bitmap_notifyPixelsChanged + */ + void notifyPixelsChanged() const; + + /** Replaces pixel values with c, interpreted as being in the sRGB SkColorSpace. + All pixels contained by bounds() are affected. If the colorType() is + kGray_8_SkColorType or kRGB_565_SkColorType, then alpha is ignored; RGB is + treated as opaque. If colorType() is kAlpha_8_SkColorType, then RGB is ignored. + + @param c unpremultiplied color + + example: https://fiddle.skia.org/c/@Bitmap_eraseColor + */ + void eraseColor(SkColor4f) const; + + /** Replaces pixel values with c, interpreted as being in the sRGB SkColorSpace. + All pixels contained by bounds() are affected. If the colorType() is + kGray_8_SkColorType or kRGB_565_SkColorType, then alpha is ignored; RGB is + treated as opaque. If colorType() is kAlpha_8_SkColorType, then RGB is ignored. + + Input color is ultimately converted to an SkColor4f, so eraseColor(SkColor4f c) + will have higher color resolution. + + @param c unpremultiplied color. + + example: https://fiddle.skia.org/c/@Bitmap_eraseColor + */ + void eraseColor(SkColor c) const; + + /** Replaces pixel values with unpremultiplied color built from a, r, g, and b, + interpreted as being in the sRGB SkColorSpace. All pixels contained by + bounds() are affected. If the colorType() is kGray_8_SkColorType or + kRGB_565_SkColorType, then a is ignored; r, g, and b are treated as opaque. + If colorType() is kAlpha_8_SkColorType, then r, g, and b are ignored. + + @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) + */ + void eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) const { + this->eraseColor(SkColorSetARGB(a, r, g, b)); + } + + /** Replaces pixel values inside area with c. interpreted as being in the sRGB + SkColorSpace. If area does not intersect bounds(), call has no effect. + + If the colorType() is kGray_8_SkColorType or kRGB_565_SkColorType, then alpha + is ignored; RGB is treated as opaque. If colorType() is kAlpha_8_SkColorType, + then RGB is ignored. + + @param c unpremultiplied color + @param area rectangle to fill + + example: https://fiddle.skia.org/c/@Bitmap_erase + */ + void erase(SkColor4f c, const SkIRect& area) const; + + /** Replaces pixel values inside area with c. interpreted as being in the sRGB + SkColorSpace. If area does not intersect bounds(), call has no effect. + + If the colorType() is kGray_8_SkColorType or kRGB_565_SkColorType, then alpha + is ignored; RGB is treated as opaque. If colorType() is kAlpha_8_SkColorType, + then RGB is ignored. + + Input color is ultimately converted to an SkColor4f, so erase(SkColor4f c) + will have higher color resolution. + + @param c unpremultiplied color + @param area rectangle to fill + + example: https://fiddle.skia.org/c/@Bitmap_erase + */ + void erase(SkColor c, const SkIRect& area) const; + + /** Deprecated. + */ + void eraseArea(const SkIRect& area, SkColor c) const { + this->erase(c, area); + } + + /** 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 + */ + SkColor getColor(int x, int y) const { + return this->pixmap().getColor(x, y); + } + + /** Returns pixel at (x, y) as unpremultiplied float 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. + + @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 + */ + SkColor4f getColor4f(int x, int y) const { return this->pixmap().getColor4f(x, y); } + + /** 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 { + return this->pixmap().getAlphaf(x, y); + } + + /** Returns pixel address at (x, y). + + Input is not validated: out of bounds values of x or y, or kUnknown_SkColorType, + trigger an assert() if built with SK_DEBUG defined. Returns nullptr if + SkColorType is kUnknown_SkColorType, or SkPixelRef is nullptr. + + Performs a lookup of pixel size; for better performance, call + one of: getAddr8(), getAddr16(), or getAddr32(). + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return generic pointer to pixel + + example: https://fiddle.skia.org/c/@Bitmap_getAddr + */ + void* getAddr(int x, int y) const; + + /** Returns address at (x, y). + + Input is not validated. Triggers an assert() if built with SK_DEBUG defined and: + - SkPixelRef is nullptr + - bytesPerPixel() is not four + - x is negative, or not less than width() + - y is negative, or not less than height() + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return unsigned 32-bit pointer to pixel at (x, y) + */ + inline uint32_t* getAddr32(int x, int y) const; + + /** Returns address at (x, y). + + Input is not validated. Triggers an assert() if built with SK_DEBUG defined and: + - SkPixelRef is nullptr + - bytesPerPixel() is not two + - x is negative, or not less than width() + - y is negative, or not less than height() + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return unsigned 16-bit pointer to pixel at (x, y) + */ + inline uint16_t* getAddr16(int x, int y) const; + + /** Returns address at (x, y). + + Input is not validated. Triggers an assert() if built with SK_DEBUG defined and: + - SkPixelRef is nullptr + - bytesPerPixel() is not one + - x is negative, or not less than width() + - y is negative, or not less than height() + + @param x column index, zero or greater, and less than width() + @param y row index, zero or greater, and less than height() + @return unsigned 8-bit pointer to pixel at (x, y) + */ + inline uint8_t* getAddr8(int x, int y) const; + + /** Shares SkPixelRef with dst. Pixels are not copied; SkBitmap and dst point + to the same pixels; dst bounds() are set to the intersection of subset + and the original bounds(). + + subset may be larger than bounds(). Any area outside of bounds() is ignored. + + Any contents of dst are discarded. + + Return false if: + - dst is nullptr + - SkPixelRef is nullptr + - subset does not intersect bounds() + + @param dst SkBitmap set to subset + @param subset rectangle of pixels to reference + @return true if dst is replaced by subset + + example: https://fiddle.skia.org/c/@Bitmap_extractSubset + */ + bool extractSubset(SkBitmap* dst, const SkIRect& subset) const; + + /** Copies a SkRect of pixels from SkBitmap to dstPixels. Copy starts at (srcX, srcY), + and does not exceed SkBitmap (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 has no address + - dstRowBytes is less than dstInfo.minRowBytes() + - SkPixelRef is nullptr + + Pixels are copied only if pixel conversion is possible. If SkBitmap colorType() is + kGray_8_SkColorType, or kAlpha_8_SkColorType; dstInfo.colorType() must match. + If SkBitmap colorType() is kGray_8_SkColorType, dstInfo.colorSpace() must match. + If SkBitmap alphaType() is kOpaque_SkAlphaType, dstInfo.alphaType() must + match. If SkBitmap 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 width() or height() is zero or negative. + Returns false if abs(srcX) >= Bitmap width(), or if abs(srcY) >= Bitmap 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 from SkBitmap to dst. Copy starts at (srcX, srcY), and + does not exceed SkBitmap (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 SkBitmap colorType() is + kGray_8_SkColorType, or kAlpha_8_SkColorType; dst SkColorType must match. + If SkBitmap colorType() is kGray_8_SkColorType, dst SkColorSpace must match. + If SkBitmap alphaType() is kOpaque_SkAlphaType, dst SkAlphaType must + match. If SkBitmap colorSpace() is nullptr, dst SkColorSpace 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) >= Bitmap width(), or if abs(srcY) >= Bitmap height(). + + @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() + @return true if pixels are copied to dst + + example: https://fiddle.skia.org/c/@Bitmap_readPixels_2 + */ + bool readPixels(const SkPixmap& dst, int srcX, int srcY) const; + + /** Copies a SkRect of pixels from SkBitmap to dst. Copy starts at (0, 0), and + does not exceed SkBitmap (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 SkBitmap colorType() is + kGray_8_SkColorType, or kAlpha_8_SkColorType; dst SkColorType must match. + If SkBitmap colorType() is kGray_8_SkColorType, dst SkColorSpace must match. + If SkBitmap alphaType() is kOpaque_SkAlphaType, dst SkAlphaType must + match. If SkBitmap colorSpace() is nullptr, dst SkColorSpace must match. Returns + false if pixel conversion is not possible. + + @param dst destination SkPixmap: SkImageInfo, pixels, row bytes + @return true if pixels are copied to dst + */ + bool readPixels(const SkPixmap& dst) const { + return this->readPixels(dst, 0, 0); + } + + /** Copies a SkRect of pixels from src. Copy starts at (dstX, dstY), and does not exceed + (src.width(), src.height()). + + src specifies width, height, SkColorType, SkAlphaType, SkColorSpace, pixel storage, + and row bytes of source. src.rowBytes() specifics the gap from one source + row to the next. Returns true if pixels are copied. Returns false if: + - src pixel storage equals nullptr + - src.rowBytes is less than SkImageInfo::minRowBytes() + - SkPixelRef is nullptr + + Pixels are copied only if pixel conversion is possible. If SkBitmap colorType() is + kGray_8_SkColorType, or kAlpha_8_SkColorType; src SkColorType must match. + If SkBitmap colorType() is kGray_8_SkColorType, src SkColorSpace must match. + If SkBitmap alphaType() is kOpaque_SkAlphaType, src SkAlphaType must + match. If SkBitmap colorSpace() is nullptr, src SkColorSpace must match. Returns + false if pixel conversion is not possible. + + dstX and dstY 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(dstX) >= Bitmap width(), or if abs(dstY) >= Bitmap height(). + + @param src source SkPixmap: SkImageInfo, pixels, row bytes + @param dstX column index whose absolute value is less than width() + @param dstY row index whose absolute value is less than height() + @return true if src pixels are copied to SkBitmap + + example: https://fiddle.skia.org/c/@Bitmap_writePixels + */ + bool writePixels(const SkPixmap& src, int dstX, int dstY); + + /** Copies a SkRect of pixels from src. Copy starts at (0, 0), and does not exceed + (src.width(), src.height()). + + src specifies width, height, SkColorType, SkAlphaType, SkColorSpace, pixel storage, + and row bytes of source. src.rowBytes() specifics the gap from one source + row to the next. Returns true if pixels are copied. Returns false if: + - src pixel storage equals nullptr + - src.rowBytes is less than SkImageInfo::minRowBytes() + - SkPixelRef is nullptr + + Pixels are copied only if pixel conversion is possible. If SkBitmap colorType() is + kGray_8_SkColorType, or kAlpha_8_SkColorType; src SkColorType must match. + If SkBitmap colorType() is kGray_8_SkColorType, src SkColorSpace must match. + If SkBitmap alphaType() is kOpaque_SkAlphaType, src SkAlphaType must + match. If SkBitmap colorSpace() is nullptr, src SkColorSpace must match. Returns + false if pixel conversion is not possible. + + @param src source SkPixmap: SkImageInfo, pixels, row bytes + @return true if src pixels are copied to SkBitmap + */ + bool writePixels(const SkPixmap& src) { + return this->writePixels(src, 0, 0); + } + + /** Sets dst to alpha described by pixels. Returns false if dst cannot be written to + or dst pixels cannot be allocated. + + Uses HeapAllocator to reserve memory for dst SkPixelRef. + + @param dst holds SkPixelRef to fill with alpha layer + @return true if alpha layer was constructed in dst SkPixelRef + */ + bool extractAlpha(SkBitmap* dst) const { + return this->extractAlpha(dst, nullptr, nullptr, nullptr); + } + + /** Sets dst to alpha described by pixels. Returns false if dst cannot be written to + or dst pixels cannot be allocated. + + If paint is not nullptr and contains SkMaskFilter, SkMaskFilter + generates mask alpha from SkBitmap. Uses HeapAllocator to reserve memory for dst + SkPixelRef. Sets offset to top-left position for dst for alignment with SkBitmap; + (0, 0) unless SkMaskFilter generates mask. + + @param dst holds SkPixelRef to fill with alpha layer + @param paint holds optional SkMaskFilter; may be nullptr + @param offset top-left position for dst; may be nullptr + @return true if alpha layer was constructed in dst SkPixelRef + */ + bool extractAlpha(SkBitmap* dst, const SkPaint* paint, + SkIPoint* offset) const { + return this->extractAlpha(dst, paint, nullptr, offset); + } + + /** Sets dst to alpha described by pixels. Returns false if dst cannot be written to + or dst pixels cannot be allocated. + + If paint is not nullptr and contains SkMaskFilter, SkMaskFilter + generates mask alpha from SkBitmap. allocator may reference a custom allocation + class or be set to nullptr to use HeapAllocator. Sets offset to top-left + position for dst for alignment with SkBitmap; (0, 0) unless SkMaskFilter generates + mask. + + @param dst holds SkPixelRef to fill with alpha layer + @param paint holds optional SkMaskFilter; may be nullptr + @param allocator function to reserve memory for SkPixelRef; may be nullptr + @param offset top-left position for dst; may be nullptr + @return true if alpha layer was constructed in dst SkPixelRef + */ + bool extractAlpha(SkBitmap* dst, const SkPaint* paint, Allocator* allocator, + SkIPoint* offset) const; + + /** Copies SkBitmap 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. + + pixmap contents become invalid on any future change to SkBitmap. + + @param pixmap storage for pixel state if pixels are readable; otherwise, ignored + @return true if SkBitmap has direct access to pixels + + example: https://fiddle.skia.org/c/@Bitmap_peekPixels + */ + bool peekPixels(SkPixmap* pixmap) const; + + /** + * Make a shader with the specified tiling, matrix and sampling. + */ + sk_sp makeShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions&, + const SkMatrix* localMatrix = nullptr) const; + sk_sp makeShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions& sampling, + const SkMatrix& lm) const; + /** Defaults to clamp in both X and Y. */ + sk_sp makeShader(const SkSamplingOptions& sampling, const SkMatrix& lm) const; + sk_sp makeShader(const SkSamplingOptions& sampling, + const SkMatrix* lm = nullptr) const; + + /** + * Returns a new image from the bitmap. If the bitmap is marked immutable, this will + * share the pixel buffer. If not, it will make a copy of the pixels for the image. + */ + sk_sp asImage() const; + + /** Asserts if internal values are illegal or inconsistent. Only available if + SK_DEBUG is defined at compile time. + */ + SkDEBUGCODE(void validate() const;) + + /** \class SkBitmap::Allocator + Abstract subclass of HeapAllocator. + */ + class Allocator : public SkRefCnt { + public: + + /** Allocates the pixel memory for the bitmap, given its dimensions and + SkColorType. Returns true on success, where success means either setPixels() + or setPixelRef() was called. + + @param bitmap SkBitmap containing SkImageInfo as input, and SkPixelRef as output + @return true if SkPixelRef was allocated + */ + virtual bool allocPixelRef(SkBitmap* bitmap) = 0; + private: + using INHERITED = SkRefCnt; + }; + + /** \class SkBitmap::HeapAllocator + Subclass of SkBitmap::Allocator that returns a SkPixelRef that allocates its pixel + memory from the heap. This is the default SkBitmap::Allocator invoked by + allocPixels(). + */ + class HeapAllocator : public Allocator { + public: + + /** Allocates the pixel memory for the bitmap, given its dimensions and + SkColorType. Returns true on success, where success means either setPixels() + or setPixelRef() was called. + + @param bitmap SkBitmap containing SkImageInfo as input, and SkPixelRef as output + @return true if pixels are allocated + + example: https://fiddle.skia.org/c/@Bitmap_HeapAllocator_allocPixelRef + */ + bool allocPixelRef(SkBitmap* bitmap) override; + }; + +private: + sk_sp fPixelRef; + SkPixmap fPixmap; + sk_sp fMips; + + friend class SkImage_Raster; + friend class SkReadBuffer; // unflatten + friend class GrProxyProvider; // fMips +}; + +/////////////////////////////////////////////////////////////////////////////// + +inline uint32_t* SkBitmap::getAddr32(int x, int y) const { + SkASSERT(fPixmap.addr()); + return fPixmap.writable_addr32(x, y); +} + +inline uint16_t* SkBitmap::getAddr16(int x, int y) const { + SkASSERT(fPixmap.addr()); + return fPixmap.writable_addr16(x, y); +} + +inline uint8_t* SkBitmap::getAddr8(int x, int y) const { + SkASSERT(fPixmap.addr()); + return fPixmap.writable_addr8(x, y); +} + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkBlendMode.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkBlendMode.h new file mode 100644 index 0000000000..4abe915762 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkBlendMode.h @@ -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(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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkBlender.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkBlender.h new file mode 100644 index 0000000000..741c4614df --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkBlender.h @@ -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 Mode(SkBlendMode mode); + +private: + SkBlender() = default; + friend class SkBlenderBase; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkBlurTypes.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkBlurTypes.h new file mode 100644 index 0000000000..f0dde10f25 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkBlurTypes.h @@ -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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkCanvas.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkCanvas.h new file mode 100644 index 0000000000..02ad95aa19 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkCanvas.h @@ -0,0 +1,2686 @@ +/* + * 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 SkCanvas_DEFINED +#define SkCanvas_DEFINED + +#include "include/core/SkArc.h" +#include "include/core/SkBlendMode.h" +#include "include/core/SkClipOp.h" +#include "include/core/SkColor.h" +#include "include/core/SkFontTypes.h" +#include "include/core/SkImageFilter.h" +#include "include/core/SkImageInfo.h" +#include "include/core/SkM44.h" +#include "include/core/SkMatrix.h" +#include "include/core/SkPaint.h" +#include "include/core/SkPoint.h" +#include "include/core/SkRasterHandleAllocator.h" +#include "include/core/SkRect.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkSamplingOptions.h" +#include "include/core/SkScalar.h" +#include "include/core/SkSize.h" +#include "include/core/SkSpan.h" +#include "include/core/SkString.h" +#include "include/core/SkSurfaceProps.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkCPUTypes.h" +#include "include/private/base/SkDeque.h" +#include "include/private/base/SkTArray.h" + +#include +#include +#include +#include + +#ifndef SK_SUPPORT_LEGACY_GETTOTALMATRIX +#define SK_SUPPORT_LEGACY_GETTOTALMATRIX +#endif + +namespace sktext { +class GlyphRunBuilder; +class GlyphRunList; +} + +class AutoLayerForImageFilter; +class GrRecordingContext; + +class SkBitmap; +class SkBlender; +class SkColorSpace; +class SkData; +class SkDevice; +class SkDrawable; +class SkFont; +class SkImage; +class SkMesh; +class SkPaintFilterCanvas; +class SkPath; +class SkPicture; +class SkPixmap; +class SkRRect; +class SkRegion; +class SkShader; +class SkSpecialImage; +class SkSurface; +class SkSurface_Base; +class SkTextBlob; +class SkVertices; +struct SkDrawShadowRec; +struct SkRSXform; + +template +class SkEnumBitMask; + +namespace skgpu::graphite { class Recorder; } +namespace sktext::gpu { class Slug; } +namespace SkRecords { class Draw; } + +/** \class SkCanvas + SkCanvas provides an interface for drawing, and how the drawing is clipped and transformed. + SkCanvas contains a stack of SkMatrix and clip values. + + SkCanvas and SkPaint together provide the state to draw into SkSurface or SkDevice. + Each SkCanvas draw call transforms the geometry of the object by the concatenation of all + SkMatrix values in the stack. The transformed geometry is clipped by the intersection + of all of clip values in the stack. The SkCanvas draw calls use SkPaint to supply drawing + state such as color, SkTypeface, text size, stroke width, SkShader and so on. + + To draw to a pixel-based destination, create raster surface or GPU surface. + Request SkCanvas from SkSurface to obtain the interface to draw. + SkCanvas generated by raster surface draws to memory visible to the CPU. + SkCanvas generated by GPU surface uses Vulkan or OpenGL to draw to the GPU. + + To draw to a document, obtain SkCanvas from SVG canvas, document PDF, or SkPictureRecorder. + SkDocument based SkCanvas and other SkCanvas subclasses reference SkDevice describing the + destination. + + SkCanvas can be constructed to draw to SkBitmap without first creating raster surface. + This approach may be deprecated in the future. +*/ +class SK_API SkCanvas { +public: + + /** Allocates raster SkCanvas that will draw directly into pixels. + + SkCanvas is returned if all parameters are valid. + Valid parameters include: + info dimensions are zero or positive; + info contains SkColorType and SkAlphaType supported by raster surface; + pixels is not nullptr; + rowBytes is zero or large enough to contain info width pixels of SkColorType. + + Pass zero for rowBytes to compute rowBytes from info width and size of pixel. + If rowBytes is greater than zero, it must be equal to or greater than + info width times bytes required for SkColorType. + + Pixel buffer size should be info height times computed rowBytes. + Pixels are not initialized. + To access pixels after drawing, call flush() or peekPixels(). + + @param info width, height, SkColorType, SkAlphaType, SkColorSpace, of raster surface; + width, or height, or both, may be zero + @param pixels pointer to destination pixels buffer + @param rowBytes interval from one SkSurface row to the next, or zero + @param props LCD striping orientation and setting for device independent fonts; + may be nullptr + @return SkCanvas if all parameters are valid; otherwise, nullptr + */ + static std::unique_ptr MakeRasterDirect(const SkImageInfo& info, void* pixels, + size_t rowBytes, + const SkSurfaceProps* props = nullptr); + + /** Allocates raster SkCanvas specified by inline image specification. Subsequent SkCanvas + calls draw into pixels. + SkColorType is set to kN32_SkColorType. + SkAlphaType is set to kPremul_SkAlphaType. + To access pixels after drawing, call flush() or peekPixels(). + + SkCanvas is returned if all parameters are valid. + Valid parameters include: + width and height are zero or positive; + pixels is not nullptr; + rowBytes is zero or large enough to contain width pixels of kN32_SkColorType. + + Pass zero for rowBytes to compute rowBytes from width and size of pixel. + If rowBytes is greater than zero, it must be equal to or greater than + width times bytes required for SkColorType. + + Pixel buffer size should be height times rowBytes. + + @param width pixel column count on raster surface created; must be zero or greater + @param height pixel row count on raster surface created; must be zero or greater + @param pixels pointer to destination pixels buffer; buffer size should be height + times rowBytes + @param rowBytes interval from one SkSurface row to the next, or zero + @return SkCanvas if all parameters are valid; otherwise, nullptr + */ + static std::unique_ptr MakeRasterDirectN32(int width, int height, SkPMColor* pixels, + size_t rowBytes) { + return MakeRasterDirect(SkImageInfo::MakeN32Premul(width, height), pixels, rowBytes); + } + + /** Creates an empty SkCanvas with no backing device or pixels, with + a width and height of zero. + + @return empty SkCanvas + + example: https://fiddle.skia.org/c/@Canvas_empty_constructor + */ + SkCanvas(); + + /** Creates SkCanvas of the specified dimensions without a SkSurface. + Used by subclasses with custom implementations for draw member functions. + + If props equals nullptr, SkSurfaceProps are created with + SkSurfaceProps::InitType settings, which choose the pixel striping + direction and order. Since a platform may dynamically change its direction when + the device is rotated, and since a platform may have multiple monitors with + different characteristics, it is best not to rely on this legacy behavior. + + @param width zero or greater + @param height zero or greater + @param props LCD striping orientation and setting for device independent fonts; + may be nullptr + @return SkCanvas placeholder with dimensions + + example: https://fiddle.skia.org/c/@Canvas_int_int_const_SkSurfaceProps_star + */ + SkCanvas(int width, int height, const SkSurfaceProps* props = nullptr); + + /** Private. For internal use only. + */ + explicit SkCanvas(sk_sp device); + + /** Constructs a canvas that draws into bitmap. + Sets kUnknown_SkPixelGeometry in constructed SkSurface. + + SkBitmap is copied so that subsequently editing bitmap will not affect + constructed SkCanvas. + + May be deprecated in the future. + + @param bitmap width, height, SkColorType, SkAlphaType, and pixel + storage of raster surface + @return SkCanvas that can be used to draw into bitmap + + example: https://fiddle.skia.org/c/@Canvas_copy_const_SkBitmap + */ + explicit SkCanvas(const SkBitmap& bitmap); + +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + /** Private. + */ + enum class ColorBehavior { + kLegacy, //!< placeholder + }; + + /** Private. For use by Android framework only. + + @param bitmap specifies a bitmap for the canvas to draw into + @param behavior specializes this constructor; value is unused + @return SkCanvas that can be used to draw into bitmap + */ + SkCanvas(const SkBitmap& bitmap, ColorBehavior behavior); +#endif + + /** Constructs a canvas that draws into bitmap. + Use props to match the device characteristics, like LCD striping. + + bitmap is copied so that subsequently editing bitmap will not affect + constructed SkCanvas. + + @param bitmap width, height, SkColorType, SkAlphaType, + and pixel storage of raster surface + @param props order and orientation of RGB striping; and whether to use + device independent fonts + @return SkCanvas that can be used to draw into bitmap + + example: https://fiddle.skia.org/c/@Canvas_const_SkBitmap_const_SkSurfaceProps + */ + SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props); + + /** Draws saved layers, if any. + Frees up resources used by SkCanvas. + + example: https://fiddle.skia.org/c/@Canvas_destructor + */ + virtual ~SkCanvas(); + + /** Returns SkImageInfo for SkCanvas. If SkCanvas is not associated with raster surface or + GPU surface, returned SkColorType is set to kUnknown_SkColorType. + + @return dimensions and SkColorType of SkCanvas + + example: https://fiddle.skia.org/c/@Canvas_imageInfo + */ + SkImageInfo imageInfo() const; + + /** Copies SkSurfaceProps, if SkCanvas is associated with raster surface or + GPU surface, and returns true. Otherwise, returns false and leave props unchanged. + + @param props storage for writable SkSurfaceProps + @return true if SkSurfaceProps was copied + + DEPRECATED: Replace usage with getBaseProps() or getTopProps() + + example: https://fiddle.skia.org/c/@Canvas_getProps + */ + bool getProps(SkSurfaceProps* props) const; + + /** Returns the SkSurfaceProps associated with the canvas (i.e., at the base of the layer + stack). + + @return base SkSurfaceProps + */ + SkSurfaceProps getBaseProps() const; + + /** Returns the SkSurfaceProps associated with the canvas that are currently active (i.e., at + the top of the layer stack). This can differ from getBaseProps depending on the flags + passed to saveLayer (see SaveLayerFlagsSet). + + @return SkSurfaceProps active in the current/top layer + */ + SkSurfaceProps getTopProps() const; + + /** Gets the size of the base or root layer in global canvas coordinates. The + origin of the base layer is always (0,0). The area available for drawing may be + smaller (due to clipping or saveLayer). + + @return integral width and height of base layer + + example: https://fiddle.skia.org/c/@Canvas_getBaseLayerSize + */ + virtual SkISize getBaseLayerSize() const; + + /** Creates SkSurface matching info and props, and associates it with SkCanvas. + Returns nullptr if no match found. + + If props is nullptr, matches SkSurfaceProps in SkCanvas. If props is nullptr and SkCanvas + does not have SkSurfaceProps, creates SkSurface with default SkSurfaceProps. + + @param info width, height, SkColorType, SkAlphaType, and SkColorSpace + @param props SkSurfaceProps to match; may be nullptr to match SkCanvas + @return SkSurface matching info and props, or nullptr if no match is available + + example: https://fiddle.skia.org/c/@Canvas_makeSurface + */ + sk_sp makeSurface(const SkImageInfo& info, const SkSurfaceProps* props = nullptr); + + /** Returns Ganesh context of the GPU surface associated with SkCanvas. + + @return GPU context, if available; nullptr otherwise + + example: https://fiddle.skia.org/c/@Canvas_recordingContext + */ + virtual GrRecordingContext* recordingContext() const; + + + /** Returns Recorder for the GPU surface associated with SkCanvas. + + @return Recorder, if available; nullptr otherwise + */ + virtual skgpu::graphite::Recorder* recorder() const; + + /** Sometimes a canvas is owned by a surface. If it is, getSurface() will return a bare + * pointer to that surface, else this will return nullptr. + */ + SkSurface* getSurface() const; + + /** Returns the pixel base address, SkImageInfo, rowBytes, and origin if the pixels + can be read directly. The returned address is only valid + while SkCanvas is in scope and unchanged. Any SkCanvas call or SkSurface call + may invalidate the returned address and other returned values. + + If pixels are inaccessible, info, rowBytes, and origin are unchanged. + + @param info storage for writable pixels' SkImageInfo; may be nullptr + @param rowBytes storage for writable pixels' row bytes; may be nullptr + @param origin storage for SkCanvas top layer origin, its top-left corner; + may be nullptr + @return address of pixels, or nullptr if inaccessible + + example: https://fiddle.skia.org/c/@Canvas_accessTopLayerPixels_a + example: https://fiddle.skia.org/c/@Canvas_accessTopLayerPixels_b + */ + void* accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin = nullptr); + + /** Returns custom context that tracks the SkMatrix and clip. + + Use SkRasterHandleAllocator to blend Skia drawing with custom drawing, typically performed + by the host platform user interface. The custom context returned is generated by + SkRasterHandleAllocator::MakeCanvas, which creates a custom canvas with raster storage for + the drawing destination. + + @return context of custom allocation + + example: https://fiddle.skia.org/c/@Canvas_accessTopRasterHandle + */ + SkRasterHandleAllocator::Handle accessTopRasterHandle() const; + + /** Returns true if SkCanvas has direct access to its pixels. + + Pixels are readable when SkDevice is raster. Pixels are not readable when SkCanvas + is returned from GPU surface, returned by SkDocument::beginPage, returned by + SkPictureRecorder::beginRecording, or SkCanvas is the base of a utility class + like DebugCanvas. + + pixmap is valid only while SkCanvas is in scope and unchanged. Any + SkCanvas or SkSurface call may invalidate the pixmap values. + + @param pixmap storage for pixel state if pixels are readable; otherwise, ignored + @return true if SkCanvas has direct access to pixels + + example: https://fiddle.skia.org/c/@Canvas_peekPixels + */ + bool peekPixels(SkPixmap* pixmap); + + /** Copies SkRect of pixels from SkCanvas into dstPixels. SkMatrix and clip are + ignored. + + Source SkRect corners are (srcX, srcY) and (imageInfo().width(), imageInfo().height()). + Destination SkRect corners are (0, 0) and (dstInfo.width(), dstInfo.height()). + Copies each readable pixel intersecting both rectangles, without scaling, + converting to dstInfo.colorType() and dstInfo.alphaType() if required. + + Pixels are readable when SkDevice is raster, or backed by a GPU. + Pixels are not readable when SkCanvas is returned by SkDocument::beginPage, + returned by SkPictureRecorder::beginRecording, or SkCanvas is the base of a utility + class like DebugCanvas. + + The destination pixel storage must be allocated by the caller. + + Pixel values are converted only if SkColorType and SkAlphaType + do not match. Only pixels within both source and destination rectangles + are copied. dstPixels contents outside SkRect intersection are unchanged. + + Pass negative values for srcX or srcY to offset pixels across or down destination. + + Does not copy, and returns false if: + - Source and destination rectangles do not intersect. + - SkCanvas pixels could not be converted to dstInfo.colorType() or dstInfo.alphaType(). + - SkCanvas pixels are not readable; for instance, SkCanvas is document-based. + - dstRowBytes is too small to contain one row of pixels. + + @param dstInfo width, height, SkColorType, and SkAlphaType of dstPixels + @param dstPixels storage for pixels; dstInfo.height() times dstRowBytes, or larger + @param dstRowBytes size of one destination row; dstInfo.width() times pixel size, or larger + @param srcX offset into readable pixels on x-axis; may be negative + @param srcY offset into readable pixels on y-axis; may be negative + @return true if pixels were copied + */ + bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, + int srcX, int srcY); + + /** Copies SkRect of pixels from SkCanvas into pixmap. SkMatrix and clip are + ignored. + + Source SkRect corners are (srcX, srcY) and (imageInfo().width(), imageInfo().height()). + Destination SkRect corners are (0, 0) and (pixmap.width(), pixmap.height()). + Copies each readable pixel intersecting both rectangles, without scaling, + converting to pixmap.colorType() and pixmap.alphaType() if required. + + Pixels are readable when SkDevice is raster, or backed by a GPU. + Pixels are not readable when SkCanvas is returned by SkDocument::beginPage, + returned by SkPictureRecorder::beginRecording, or SkCanvas is the base of a utility + class like DebugCanvas. + + Caller must allocate pixel storage in pixmap if needed. + + Pixel values are converted only if SkColorType and SkAlphaType + do not match. Only pixels within both source and destination SkRect + are copied. pixmap pixels contents outside SkRect intersection are unchanged. + + Pass negative values for srcX or srcY to offset pixels across or down pixmap. + + Does not copy, and returns false if: + - Source and destination rectangles do not intersect. + - SkCanvas pixels could not be converted to pixmap.colorType() or pixmap.alphaType(). + - SkCanvas pixels are not readable; for instance, SkCanvas is document-based. + - SkPixmap pixels could not be allocated. + - pixmap.rowBytes() is too small to contain one row of pixels. + + @param pixmap storage for pixels copied from SkCanvas + @param srcX offset into readable pixels on x-axis; may be negative + @param srcY offset into readable pixels on y-axis; may be negative + @return true if pixels were copied + + example: https://fiddle.skia.org/c/@Canvas_readPixels_2 + */ + bool readPixels(const SkPixmap& pixmap, int srcX, int srcY); + + /** Copies SkRect of pixels from SkCanvas into bitmap. SkMatrix and clip are + ignored. + + Source SkRect corners are (srcX, srcY) and (imageInfo().width(), imageInfo().height()). + Destination SkRect corners are (0, 0) and (bitmap.width(), bitmap.height()). + Copies each readable pixel intersecting both rectangles, without scaling, + converting to bitmap.colorType() and bitmap.alphaType() if required. + + Pixels are readable when SkDevice is raster, or backed by a GPU. + Pixels are not readable when SkCanvas is returned by SkDocument::beginPage, + returned by SkPictureRecorder::beginRecording, or SkCanvas is the base of a utility + class like DebugCanvas. + + Caller must allocate pixel storage in bitmap if needed. + + SkBitmap values are converted only if SkColorType and SkAlphaType + do not match. Only pixels within both source and destination rectangles + are copied. SkBitmap pixels outside SkRect intersection are unchanged. + + Pass negative values for srcX or srcY to offset pixels across or down bitmap. + + Does not copy, and returns false if: + - Source and destination rectangles do not intersect. + - SkCanvas pixels could not be converted to bitmap.colorType() or bitmap.alphaType(). + - SkCanvas pixels are not readable; for instance, SkCanvas is document-based. + - bitmap pixels could not be allocated. + - bitmap.rowBytes() is too small to contain one row of pixels. + + @param bitmap storage for pixels copied from SkCanvas + @param srcX offset into readable pixels on x-axis; may be negative + @param srcY offset into readable pixels on y-axis; may be negative + @return true if pixels were copied + + example: https://fiddle.skia.org/c/@Canvas_readPixels_3 + */ + bool readPixels(const SkBitmap& bitmap, int srcX, int srcY); + + /** Copies SkRect from pixels to SkCanvas. SkMatrix and clip are ignored. + Source SkRect corners are (0, 0) and (info.width(), info.height()). + Destination SkRect corners are (x, y) and + (imageInfo().width(), imageInfo().height()). + + Copies each readable pixel intersecting both rectangles, without scaling, + converting to imageInfo().colorType() and imageInfo().alphaType() if required. + + Pixels are writable when SkDevice is raster, or backed by a GPU. + Pixels are not writable when SkCanvas is returned by SkDocument::beginPage, + returned by SkPictureRecorder::beginRecording, or SkCanvas is the base of a utility + class like DebugCanvas. + + Pixel values are converted only if SkColorType and SkAlphaType + do not match. Only pixels within both source and destination rectangles + are copied. SkCanvas pixels outside SkRect intersection are unchanged. + + Pass negative values for x or y to offset pixels to the left or + above SkCanvas pixels. + + Does not copy, and returns false if: + - Source and destination rectangles do not intersect. + - pixels could not be converted to SkCanvas imageInfo().colorType() or + imageInfo().alphaType(). + - SkCanvas pixels are not writable; for instance, SkCanvas is document-based. + - rowBytes is too small to contain one row of pixels. + + @param info width, height, SkColorType, and SkAlphaType of pixels + @param pixels pixels to copy, of size info.height() times rowBytes, or larger + @param rowBytes size of one row of pixels; info.width() times pixel size, or larger + @param x offset into SkCanvas writable pixels on x-axis; may be negative + @param y offset into SkCanvas writable pixels on y-axis; may be negative + @return true if pixels were written to SkCanvas + + example: https://fiddle.skia.org/c/@Canvas_writePixels + */ + bool writePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes, int x, int y); + + /** Copies SkRect from pixels to SkCanvas. SkMatrix and clip are ignored. + Source SkRect corners are (0, 0) and (bitmap.width(), bitmap.height()). + + Destination SkRect corners are (x, y) and + (imageInfo().width(), imageInfo().height()). + + Copies each readable pixel intersecting both rectangles, without scaling, + converting to imageInfo().colorType() and imageInfo().alphaType() if required. + + Pixels are writable when SkDevice is raster, or backed by a GPU. + Pixels are not writable when SkCanvas is returned by SkDocument::beginPage, + returned by SkPictureRecorder::beginRecording, or SkCanvas is the base of a utility + class like DebugCanvas. + + Pixel values are converted only if SkColorType and SkAlphaType + do not match. Only pixels within both source and destination rectangles + are copied. SkCanvas pixels outside SkRect intersection are unchanged. + + Pass negative values for x or y to offset pixels to the left or + above SkCanvas pixels. + + Does not copy, and returns false if: + - Source and destination rectangles do not intersect. + - bitmap does not have allocated pixels. + - bitmap pixels could not be converted to SkCanvas imageInfo().colorType() or + imageInfo().alphaType(). + - SkCanvas pixels are not writable; for instance, SkCanvas is document based. + - bitmap pixels are inaccessible; for instance, bitmap wraps a texture. + + @param bitmap contains pixels copied to SkCanvas + @param x offset into SkCanvas writable pixels on x-axis; may be negative + @param y offset into SkCanvas writable pixels on y-axis; may be negative + @return true if pixels were written to SkCanvas + + example: https://fiddle.skia.org/c/@Canvas_writePixels_2 + example: https://fiddle.skia.org/c/@State_Stack_a + example: https://fiddle.skia.org/c/@State_Stack_b + */ + bool writePixels(const SkBitmap& bitmap, int x, int y); + + /** Saves SkMatrix and clip. + Calling restore() discards changes to SkMatrix and clip, + restoring the SkMatrix and clip to their state when save() was called. + + SkMatrix may be changed by translate(), scale(), rotate(), skew(), concat(), setMatrix(), + and resetMatrix(). Clip may be changed by clipRect(), clipRRect(), clipPath(), clipRegion(). + + Saved SkCanvas state is put on a stack; multiple calls to save() should be balance + by an equal number of calls to restore(). + + Call restoreToCount() with result to restore this and subsequent saves. + + @return depth of saved stack + + example: https://fiddle.skia.org/c/@Canvas_save + */ + int save(); + + /** Saves SkMatrix and clip, and allocates a SkSurface for subsequent drawing. + Calling restore() discards changes to SkMatrix and clip, and draws the SkSurface. + + SkMatrix may be changed by translate(), scale(), rotate(), skew(), concat(), + setMatrix(), and resetMatrix(). Clip may be changed by clipRect(), clipRRect(), + clipPath(), clipRegion(). + + SkRect bounds suggests but does not define the SkSurface size. To clip drawing to + a specific rectangle, use clipRect(). + + Optional SkPaint paint applies alpha, SkColorFilter, SkImageFilter, and + SkBlendMode when restore() is called. + + Call restoreToCount() with returned value to restore this and subsequent saves. + + @param bounds hint to limit the size of the layer; may be nullptr + @param paint graphics state for layer; may be nullptr + @return depth of saved stack + + example: https://fiddle.skia.org/c/@Canvas_saveLayer + example: https://fiddle.skia.org/c/@Canvas_saveLayer_4 + */ + int saveLayer(const SkRect* bounds, const SkPaint* paint); + + /** Saves SkMatrix and clip, and allocates a SkSurface for subsequent drawing. + Calling restore() discards changes to SkMatrix and clip, and draws the SkSurface. + + SkMatrix may be changed by translate(), scale(), rotate(), skew(), concat(), + setMatrix(), and resetMatrix(). Clip may be changed by clipRect(), clipRRect(), + clipPath(), clipRegion(). + + SkRect bounds suggests but does not define the layer size. To clip drawing to + a specific rectangle, use clipRect(). + + Optional SkPaint paint applies alpha, SkColorFilter, SkImageFilter, and + SkBlendMode when restore() is called. + + Call restoreToCount() with returned value to restore this and subsequent saves. + + @param bounds hint to limit the size of layer; may be nullptr + @param paint graphics state for layer; may be nullptr + @return depth of saved stack + */ + int saveLayer(const SkRect& bounds, const SkPaint* paint) { + return this->saveLayer(&bounds, paint); + } + + /** Saves SkMatrix and clip, and allocates SkSurface for subsequent drawing. + + Calling restore() discards changes to SkMatrix and clip, + and blends layer with alpha opacity onto prior layer. + + SkMatrix may be changed by translate(), scale(), rotate(), skew(), concat(), + setMatrix(), and resetMatrix(). Clip may be changed by clipRect(), clipRRect(), + clipPath(), clipRegion(). + + SkRect bounds suggests but does not define layer size. To clip drawing to + a specific rectangle, use clipRect(). + + alpha of zero is fully transparent, 1.0f is fully opaque. + + Call restoreToCount() with returned value to restore this and subsequent saves. + + @param bounds hint to limit the size of layer; may be nullptr + @param alpha opacity of layer + @return depth of saved stack + + example: https://fiddle.skia.org/c/@Canvas_saveLayerAlpha + */ + int saveLayerAlphaf(const SkRect* bounds, float alpha); + // Helper that accepts an int between 0 and 255, and divides it by 255.0 + int saveLayerAlpha(const SkRect* bounds, U8CPU alpha) { + return this->saveLayerAlphaf(bounds, alpha * (1.0f / 255)); + } + + /** \enum SkCanvas::SaveLayerFlagsSet + SaveLayerFlags provides options that may be used in any combination in SaveLayerRec, + defining how layer allocated by saveLayer() operates. It may be set to zero, + kPreserveLCDText_SaveLayerFlag, kInitWithPrevious_SaveLayerFlag, or both flags. + */ + enum SaveLayerFlagsSet { + kPreserveLCDText_SaveLayerFlag = 1 << 1, + kInitWithPrevious_SaveLayerFlag = 1 << 2, //!< initializes with previous contents + // instead of matching previous layer's colortype, use F16 + kF16ColorType = 1 << 4, + }; + + using SaveLayerFlags = uint32_t; + using FilterSpan = SkSpan>; + static constexpr int kMaxFiltersPerLayer = 16; + + /** \struct SkCanvas::SaveLayerRec + SaveLayerRec contains the state used to create the layer. + */ + struct SaveLayerRec { + /** Sets fBounds, fPaint, and fBackdrop to nullptr. Clears fSaveLayerFlags. + + @return empty SaveLayerRec + */ + SaveLayerRec() {} + + /** Sets fBounds, fPaint, and fSaveLayerFlags; sets fBackdrop to nullptr. + + @param bounds layer dimensions; may be nullptr + @param paint applied to layer when overlaying prior layer; may be nullptr + @param saveLayerFlags SaveLayerRec options to modify layer + @return SaveLayerRec with empty fBackdrop + */ + SaveLayerRec(const SkRect* bounds, const SkPaint* paint, SaveLayerFlags saveLayerFlags = 0) + : SaveLayerRec(bounds, paint, nullptr, nullptr, 1.f, saveLayerFlags, /*filters=*/{}) {} + + /** Sets fBounds, fPaint, fBackdrop, and fSaveLayerFlags. + + @param bounds layer dimensions; may be nullptr + @param paint applied to layer when overlaying prior layer; + may be nullptr + @param backdrop If not null, this causes the current layer to be filtered by + backdrop, and then drawn into the new layer + (respecting the current clip). + If null, the new layer is initialized with transparent-black. + @param saveLayerFlags SaveLayerRec options to modify layer + @return SaveLayerRec fully specified + */ + SaveLayerRec(const SkRect* bounds, const SkPaint* paint, const SkImageFilter* backdrop, + SaveLayerFlags saveLayerFlags) + : SaveLayerRec(bounds, paint, backdrop, nullptr, 1.f, saveLayerFlags, /*filters=*/{}) {} + + /** Sets fBounds, fColorSpace, and fSaveLayerFlags. + + @param bounds layer dimensions; may be nullptr + @param paint applied to layer when overlaying prior layer; + may be nullptr + @param backdrop If not null, this causes the current layer to be filtered by + backdrop, and then drawn into the new layer + (respecting the current clip). + If null, the new layer is initialized with transparent-black. + @param colorSpace If not null, when the layer is restored, a color space + conversion will be applied from this color space to the + parent's color space. The restore paint and backdrop filters will + be applied in this color space. + If null, the new layer will inherit the color space from its + parent. + @param saveLayerFlags SaveLayerRec options to modify layer + @return SaveLayerRec fully specified + */ + SaveLayerRec(const SkRect* bounds, const SkPaint* paint, const SkImageFilter* backdrop, + const SkColorSpace* colorSpace, SaveLayerFlags saveLayerFlags) + : SaveLayerRec(bounds, paint, backdrop, colorSpace, 1.f, saveLayerFlags, /*filters=*/{}) {} + + /** hints at layer size limit */ + const SkRect* fBounds = nullptr; + + /** modifies overlay */ + const SkPaint* fPaint = nullptr; + + FilterSpan fFilters = {}; + + /** + * If not null, this triggers the same initialization behavior as setting + * kInitWithPrevious_SaveLayerFlag on fSaveLayerFlags: the current layer is copied into + * the new layer, rather than initializing the new layer with transparent-black. + * This is then filtered by fBackdrop (respecting the current clip). + */ + const SkImageFilter* fBackdrop = nullptr; + + /** + * If not null, this triggers a color space conversion when the layer is restored. It + * will be as if the layer's contents are drawn in this color space. Filters from + * fBackdrop and fPaint will be applied in this color space. + */ + const SkColorSpace* fColorSpace = nullptr; + + /** preserves LCD text, creates with prior layer contents */ + SaveLayerFlags fSaveLayerFlags = 0; + + private: + friend class SkCanvas; + friend class SkCanvasPriv; + + SaveLayerRec(const SkRect* bounds, + const SkPaint* paint, + const SkImageFilter* backdrop, + const SkColorSpace* colorSpace, + SkScalar backdropScale, + SaveLayerFlags saveLayerFlags, + FilterSpan filters) + : fBounds(bounds) + , fPaint(paint) + , fFilters(filters) + , fBackdrop(backdrop) + , fColorSpace(colorSpace) + , fSaveLayerFlags(saveLayerFlags) + , fExperimentalBackdropScale(backdropScale) { + // We only allow the paint's image filter or the side-car list of filters -- not both. + SkASSERT(fFilters.empty() || !paint || !paint->getImageFilter()); + // To keep things reasonable (during deserialization), we limit filter list size. + SkASSERT(fFilters.size() <= kMaxFiltersPerLayer); + } + + // Relative scale factor that the image content used to initialize the layer when the + // kInitFromPrevious flag or a backdrop filter is used. + SkScalar fExperimentalBackdropScale = 1.f; + }; + + /** Saves SkMatrix and clip, and allocates SkSurface for subsequent drawing. + + Calling restore() discards changes to SkMatrix and clip, + and blends SkSurface with alpha opacity onto the prior layer. + + SkMatrix may be changed by translate(), scale(), rotate(), skew(), concat(), + setMatrix(), and resetMatrix(). Clip may be changed by clipRect(), clipRRect(), + clipPath(), clipRegion(). + + SaveLayerRec contains the state used to create the layer. + + Call restoreToCount() with returned value to restore this and subsequent saves. + + @param layerRec layer state + @return depth of save state stack before this call was made. + + example: https://fiddle.skia.org/c/@Canvas_saveLayer_3 + */ + int saveLayer(const SaveLayerRec& layerRec); + + /** Removes changes to SkMatrix and clip since SkCanvas state was + last saved. The state is removed from the stack. + + Does nothing if the stack is empty. + + example: https://fiddle.skia.org/c/@AutoCanvasRestore_restore + + example: https://fiddle.skia.org/c/@Canvas_restore + */ + void restore(); + + /** Returns the number of saved states, each containing: SkMatrix and clip. + Equals the number of save() calls less the number of restore() calls plus one. + The save count of a new canvas is one. + + @return depth of save state stack + + example: https://fiddle.skia.org/c/@Canvas_getSaveCount + */ + int getSaveCount() const; + + /** Restores state to SkMatrix and clip values when save(), saveLayer(), + saveLayerPreserveLCDTextRequests(), or saveLayerAlpha() returned saveCount. + + Does nothing if saveCount is greater than state stack count. + Restores state to initial values if saveCount is less than or equal to one. + + @param saveCount depth of state stack to restore + + example: https://fiddle.skia.org/c/@Canvas_restoreToCount + */ + void restoreToCount(int saveCount); + + /** Translates SkMatrix by dx along the x-axis and dy along the y-axis. + + Mathematically, replaces SkMatrix with a translation matrix + premultiplied with SkMatrix. + + This has the effect of moving the drawing by (dx, dy) before transforming + the result with SkMatrix. + + @param dx distance to translate on x-axis + @param dy distance to translate on y-axis + + example: https://fiddle.skia.org/c/@Canvas_translate + */ + void translate(SkScalar dx, SkScalar dy); + + /** Scales SkMatrix by sx on the x-axis and sy on the y-axis. + + Mathematically, replaces SkMatrix with a scale matrix + premultiplied with SkMatrix. + + This has the effect of scaling the drawing by (sx, sy) before transforming + the result with SkMatrix. + + @param sx amount to scale on x-axis + @param sy amount to scale on y-axis + + example: https://fiddle.skia.org/c/@Canvas_scale + */ + void scale(SkScalar sx, SkScalar sy); + + /** Rotates SkMatrix by degrees. Positive degrees rotates clockwise. + + Mathematically, replaces SkMatrix with a rotation matrix + premultiplied with SkMatrix. + + This has the effect of rotating the drawing by degrees before transforming + the result with SkMatrix. + + @param degrees amount to rotate, in degrees + + example: https://fiddle.skia.org/c/@Canvas_rotate + */ + void rotate(SkScalar degrees); + + /** Rotates SkMatrix by degrees about a point at (px, py). Positive degrees rotates + clockwise. + + Mathematically, constructs a rotation matrix; premultiplies the rotation matrix by + a translation matrix; then replaces SkMatrix with the resulting matrix + premultiplied with SkMatrix. + + This has the effect of rotating the drawing about a given point before + transforming the result with SkMatrix. + + @param degrees amount to rotate, in degrees + @param px x-axis value of the point to rotate about + @param py y-axis value of the point to rotate about + + example: https://fiddle.skia.org/c/@Canvas_rotate_2 + */ + void rotate(SkScalar degrees, SkScalar px, SkScalar py); + + /** Skews SkMatrix by sx on the x-axis and sy on the y-axis. A positive value of sx + skews the drawing right as y-axis values increase; a positive value of sy skews + the drawing down as x-axis values increase. + + Mathematically, replaces SkMatrix with a skew matrix premultiplied with SkMatrix. + + This has the effect of skewing the drawing by (sx, sy) before transforming + the result with SkMatrix. + + @param sx amount to skew on x-axis + @param sy amount to skew on y-axis + + example: https://fiddle.skia.org/c/@Canvas_skew + */ + void skew(SkScalar sx, SkScalar sy); + + /** Replaces SkMatrix with matrix premultiplied with existing SkMatrix. + + This has the effect of transforming the drawn geometry by matrix, before + transforming the result with existing SkMatrix. + + @param matrix matrix to premultiply with existing SkMatrix + + example: https://fiddle.skia.org/c/@Canvas_concat + */ + void concat(const SkMatrix& matrix); + void concat(const SkM44&); + + /** Replaces SkMatrix with matrix. + Unlike concat(), any prior matrix state is overwritten. + + @param matrix matrix to copy, replacing existing SkMatrix + + example: https://fiddle.skia.org/c/@Canvas_setMatrix + */ + void setMatrix(const SkM44& matrix); + + // DEPRECATED -- use SkM44 version + void setMatrix(const SkMatrix& matrix); + + /** Sets SkMatrix to the identity matrix. + Any prior matrix state is overwritten. + + example: https://fiddle.skia.org/c/@Canvas_resetMatrix + */ + void resetMatrix(); + + /** Replaces clip with the intersection or difference of clip and rect, + with an aliased or anti-aliased clip edge. rect is transformed by SkMatrix + before it is combined with clip. + + @param rect SkRect to combine with clip + @param op SkClipOp to apply to clip + @param doAntiAlias true if clip is to be anti-aliased + + example: https://fiddle.skia.org/c/@Canvas_clipRect + */ + void clipRect(const SkRect& rect, SkClipOp op, bool doAntiAlias); + + /** Replaces clip with the intersection or difference of clip and rect. + Resulting clip is aliased; pixels are fully contained by the clip. + rect is transformed by SkMatrix before it is combined with clip. + + @param rect SkRect to combine with clip + @param op SkClipOp to apply to clip + */ + void clipRect(const SkRect& rect, SkClipOp op) { + this->clipRect(rect, op, false); + } + + /** Replaces clip with the intersection of clip and rect. + Resulting clip is aliased; pixels are fully contained by the clip. + rect is transformed by SkMatrix + before it is combined with clip. + + @param rect SkRect to combine with clip + @param doAntiAlias true if clip is to be anti-aliased + */ + void clipRect(const SkRect& rect, bool doAntiAlias = false) { + this->clipRect(rect, SkClipOp::kIntersect, doAntiAlias); + } + + void clipIRect(const SkIRect& irect, SkClipOp op = SkClipOp::kIntersect) { + this->clipRect(SkRect::Make(irect), op, false); + } + + /** Sets the maximum clip rectangle, which can be set by clipRect(), clipRRect() and + clipPath() and intersect the current clip with the specified rect. + The maximum clip affects only future clipping operations; it is not retroactive. + The clip restriction is not recorded in pictures. + + Pass an empty rect to disable maximum clip. + This private API is for use by Android framework only. + + DEPRECATED: Replace usage with SkAndroidFrameworkUtils::replaceClip() + + @param rect maximum allowed clip in device coordinates + */ + void androidFramework_setDeviceClipRestriction(const SkIRect& rect); + + /** Replaces clip with the intersection or difference of clip and rrect, + with an aliased or anti-aliased clip edge. + rrect is transformed by SkMatrix + before it is combined with clip. + + @param rrect SkRRect to combine with clip + @param op SkClipOp to apply to clip + @param doAntiAlias true if clip is to be anti-aliased + + example: https://fiddle.skia.org/c/@Canvas_clipRRect + */ + void clipRRect(const SkRRect& rrect, SkClipOp op, bool doAntiAlias); + + /** Replaces clip with the intersection or difference of clip and rrect. + Resulting clip is aliased; pixels are fully contained by the clip. + rrect is transformed by SkMatrix before it is combined with clip. + + @param rrect SkRRect to combine with clip + @param op SkClipOp to apply to clip + */ + void clipRRect(const SkRRect& rrect, SkClipOp op) { + this->clipRRect(rrect, op, false); + } + + /** Replaces clip with the intersection of clip and rrect, + with an aliased or anti-aliased clip edge. + rrect is transformed by SkMatrix before it is combined with clip. + + @param rrect SkRRect to combine with clip + @param doAntiAlias true if clip is to be anti-aliased + */ + void clipRRect(const SkRRect& rrect, bool doAntiAlias = false) { + this->clipRRect(rrect, SkClipOp::kIntersect, doAntiAlias); + } + + /** Replaces clip with the intersection or difference of clip and path, + with an aliased or anti-aliased clip edge. SkPath::FillType determines if path + describes the area inside or outside its contours; and if path contour overlaps + itself or another path contour, whether the overlaps form part of the area. + path is transformed by SkMatrix before it is combined with clip. + + @param path SkPath to combine with clip + @param op SkClipOp to apply to clip + @param doAntiAlias true if clip is to be anti-aliased + + example: https://fiddle.skia.org/c/@Canvas_clipPath + */ + void clipPath(const SkPath& path, SkClipOp op, bool doAntiAlias); + + /** Replaces clip with the intersection or difference of clip and path. + Resulting clip is aliased; pixels are fully contained by the clip. + SkPath::FillType determines if path + describes the area inside or outside its contours; and if path contour overlaps + itself or another path contour, whether the overlaps form part of the area. + path is transformed by SkMatrix + before it is combined with clip. + + @param path SkPath to combine with clip + @param op SkClipOp to apply to clip + */ + void clipPath(const SkPath& path, SkClipOp op) { + this->clipPath(path, op, false); + } + + /** Replaces clip with the intersection of clip and path. + Resulting clip is aliased; pixels are fully contained by the clip. + SkPath::FillType determines if path + describes the area inside or outside its contours; and if path contour overlaps + itself or another path contour, whether the overlaps form part of the area. + path is transformed by SkMatrix before it is combined with clip. + + @param path SkPath to combine with clip + @param doAntiAlias true if clip is to be anti-aliased + */ + void clipPath(const SkPath& path, bool doAntiAlias = false) { + this->clipPath(path, SkClipOp::kIntersect, doAntiAlias); + } + + void clipShader(sk_sp, SkClipOp = SkClipOp::kIntersect); + + /** Replaces clip with the intersection or difference of clip and SkRegion deviceRgn. + Resulting clip is aliased; pixels are fully contained by the clip. + deviceRgn is unaffected by SkMatrix. + + @param deviceRgn SkRegion to combine with clip + @param op SkClipOp to apply to clip + + example: https://fiddle.skia.org/c/@Canvas_clipRegion + */ + void clipRegion(const SkRegion& deviceRgn, SkClipOp op = SkClipOp::kIntersect); + + /** Returns true if SkRect rect, transformed by SkMatrix, can be quickly determined to be + outside of clip. May return false even though rect is outside of clip. + + Use to check if an area to be drawn is clipped out, to skip subsequent draw calls. + + @param rect SkRect to compare with clip + @return true if rect, transformed by SkMatrix, does not intersect clip + + example: https://fiddle.skia.org/c/@Canvas_quickReject + */ + bool quickReject(const SkRect& rect) const; + + /** Returns true if path, transformed by SkMatrix, can be quickly determined to be + outside of clip. May return false even though path is outside of clip. + + Use to check if an area to be drawn is clipped out, to skip subsequent draw calls. + + @param path SkPath to compare with clip + @return true if path, transformed by SkMatrix, does not intersect clip + + example: https://fiddle.skia.org/c/@Canvas_quickReject_2 + */ + bool quickReject(const SkPath& path) const; + + /** Returns bounds of clip, transformed by inverse of SkMatrix. If clip is empty, + return SkRect::MakeEmpty, where all SkRect sides equal zero. + + SkRect returned is outset by one to account for partial pixel coverage if clip + is anti-aliased. + + @return bounds of clip in local coordinates + + example: https://fiddle.skia.org/c/@Canvas_getLocalClipBounds + */ + SkRect getLocalClipBounds() const; + + /** Returns bounds of clip, transformed by inverse of SkMatrix. If clip is empty, + return false, and set bounds to SkRect::MakeEmpty, where all SkRect sides equal zero. + + bounds is outset by one to account for partial pixel coverage if clip + is anti-aliased. + + @param bounds SkRect of clip in local coordinates + @return true if clip bounds is not empty + */ + bool getLocalClipBounds(SkRect* bounds) const { + *bounds = this->getLocalClipBounds(); + return !bounds->isEmpty(); + } + + /** Returns SkIRect bounds of clip, unaffected by SkMatrix. If clip is empty, + return SkRect::MakeEmpty, where all SkRect sides equal zero. + + Unlike getLocalClipBounds(), returned SkIRect is not outset. + + @return bounds of clip in base device coordinates + + example: https://fiddle.skia.org/c/@Canvas_getDeviceClipBounds + */ + SkIRect getDeviceClipBounds() const; + + /** Returns SkIRect bounds of clip, unaffected by SkMatrix. If clip is empty, + return false, and set bounds to SkRect::MakeEmpty, where all SkRect sides equal zero. + + Unlike getLocalClipBounds(), bounds is not outset. + + @param bounds SkRect of clip in device coordinates + @return true if clip bounds is not empty + */ + bool getDeviceClipBounds(SkIRect* bounds) const { + *bounds = this->getDeviceClipBounds(); + return !bounds->isEmpty(); + } + + /** Fills clip with color color. + mode determines how ARGB is combined with destination. + + @param color unpremultiplied ARGB + @param mode SkBlendMode used to combine source color and destination + + example: https://fiddle.skia.org/c/@Canvas_drawColor + */ + void drawColor(SkColor color, SkBlendMode mode = SkBlendMode::kSrcOver) { + this->drawColor(SkColor4f::FromColor(color), mode); + } + + /** Fills clip with color color. + mode determines how ARGB is combined with destination. + + @param color SkColor4f representing unpremultiplied color. + @param mode SkBlendMode used to combine source color and destination + */ + void drawColor(const SkColor4f& color, SkBlendMode mode = SkBlendMode::kSrcOver); + + /** Fills clip with color color using SkBlendMode::kSrc. + This has the effect of replacing all pixels contained by clip with color. + + @param color unpremultiplied ARGB + */ + void clear(SkColor color) { + this->clear(SkColor4f::FromColor(color)); + } + + /** Fills clip with color color using SkBlendMode::kSrc. + This has the effect of replacing all pixels contained by clip with color. + + @param color SkColor4f representing unpremultiplied color. + */ + void clear(const SkColor4f& color) { + this->drawColor(color, SkBlendMode::kSrc); + } + + /** Makes SkCanvas contents undefined. Subsequent calls that read SkCanvas pixels, + such as drawing with SkBlendMode, return undefined results. discard() does + not change clip or SkMatrix. + + discard() may do nothing, depending on the implementation of SkSurface or SkDevice + that created SkCanvas. + + discard() allows optimized performance on subsequent draws by removing + cached data associated with SkSurface or SkDevice. + It is not necessary to call discard() once done with SkCanvas; + any cached data is deleted when owning SkSurface or SkDevice is deleted. + */ + void discard() { this->onDiscard(); } + + /** Fills clip with SkPaint paint. SkPaint components, SkShader, + SkColorFilter, SkImageFilter, and SkBlendMode affect drawing; + SkMaskFilter and SkPathEffect in paint are ignored. + + @param paint graphics state used to fill SkCanvas + + example: https://fiddle.skia.org/c/@Canvas_drawPaint + */ + void drawPaint(const SkPaint& paint); + + /** \enum SkCanvas::PointMode + Selects if an array of points are drawn as discrete points, as lines, or as + an open polygon. + */ + enum PointMode { + kPoints_PointMode, //!< draw each point separately + kLines_PointMode, //!< draw each pair of points as a line segment + kPolygon_PointMode, //!< draw the array of points as a open polygon + }; + + /** Draws pts using clip, SkMatrix and SkPaint paint. + count is the number of points; if count is less than one, has no effect. + mode may be one of: kPoints_PointMode, kLines_PointMode, or kPolygon_PointMode. + + If mode is kPoints_PointMode, the shape of point drawn depends on paint + SkPaint::Cap. If paint is set to SkPaint::kRound_Cap, each point draws a + circle of diameter SkPaint stroke width. If paint is set to SkPaint::kSquare_Cap + or SkPaint::kButt_Cap, each point draws a square of width and height + SkPaint stroke width. + + If mode is kLines_PointMode, each pair of points draws a line segment. + One line is drawn for every two points; each point is used once. If count is odd, + the final point is ignored. + + If mode is kPolygon_PointMode, each adjacent pair of points draws a line segment. + count minus one lines are drawn; the first and last point are used once. + + Each line segment respects paint SkPaint::Cap and SkPaint stroke width. + SkPaint::Style is ignored, as if were set to SkPaint::kStroke_Style. + + Always draws each element one at a time; is not affected by + SkPaint::Join, and unlike drawPath(), does not create a mask from all points + and lines before drawing. + + @param mode whether pts draws points or lines + @param count number of points in the array + @param pts array of points to draw + @param paint stroke, blend, color, and so on, used to draw + + example: https://fiddle.skia.org/c/@Canvas_drawPoints + */ + void drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint); + + /** Draws point at (x, y) using clip, SkMatrix and SkPaint paint. + + The shape of point drawn depends on paint SkPaint::Cap. + If paint is set to SkPaint::kRound_Cap, draw a circle of diameter + SkPaint stroke width. If paint is set to SkPaint::kSquare_Cap or SkPaint::kButt_Cap, + draw a square of width and height SkPaint stroke width. + SkPaint::Style is ignored, as if were set to SkPaint::kStroke_Style. + + @param x left edge of circle or square + @param y top edge of circle or square + @param paint stroke, blend, color, and so on, used to draw + + example: https://fiddle.skia.org/c/@Canvas_drawPoint + */ + void drawPoint(SkScalar x, SkScalar y, const SkPaint& paint); + + /** Draws point p using clip, SkMatrix and SkPaint paint. + + The shape of point drawn depends on paint SkPaint::Cap. + If paint is set to SkPaint::kRound_Cap, draw a circle of diameter + SkPaint stroke width. If paint is set to SkPaint::kSquare_Cap or SkPaint::kButt_Cap, + draw a square of width and height SkPaint stroke width. + SkPaint::Style is ignored, as if were set to SkPaint::kStroke_Style. + + @param p top-left edge of circle or square + @param paint stroke, blend, color, and so on, used to draw + */ + void drawPoint(SkPoint p, const SkPaint& paint) { + this->drawPoint(p.x(), p.y(), paint); + } + + /** Draws line segment from (x0, y0) to (x1, y1) using clip, SkMatrix, and SkPaint paint. + In paint: SkPaint stroke width describes the line thickness; + SkPaint::Cap draws the end rounded or square; + SkPaint::Style is ignored, as if were set to SkPaint::kStroke_Style. + + @param x0 start of line segment on x-axis + @param y0 start of line segment on y-axis + @param x1 end of line segment on x-axis + @param y1 end of line segment on y-axis + @param paint stroke, blend, color, and so on, used to draw + + example: https://fiddle.skia.org/c/@Canvas_drawLine + */ + void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint); + + /** Draws line segment from p0 to p1 using clip, SkMatrix, and SkPaint paint. + In paint: SkPaint stroke width describes the line thickness; + SkPaint::Cap draws the end rounded or square; + SkPaint::Style is ignored, as if were set to SkPaint::kStroke_Style. + + @param p0 start of line segment + @param p1 end of line segment + @param paint stroke, blend, color, and so on, used to draw + */ + void drawLine(SkPoint p0, SkPoint p1, const SkPaint& paint) { + this->drawLine(p0.x(), p0.y(), p1.x(), p1.y(), paint); + } + + /** Draws SkRect rect using clip, SkMatrix, and SkPaint paint. + In paint: SkPaint::Style determines if rectangle is stroked or filled; + if stroked, SkPaint stroke width describes the line thickness, and + SkPaint::Join draws the corners rounded or square. + + @param rect rectangle to draw + @param paint stroke or fill, blend, color, and so on, used to draw + + example: https://fiddle.skia.org/c/@Canvas_drawRect + */ + void drawRect(const SkRect& rect, const SkPaint& paint); + + /** Draws SkIRect rect using clip, SkMatrix, and SkPaint paint. + In paint: SkPaint::Style determines if rectangle is stroked or filled; + if stroked, SkPaint stroke width describes the line thickness, and + SkPaint::Join draws the corners rounded or square. + + @param rect rectangle to draw + @param paint stroke or fill, blend, color, and so on, used to draw + */ + void drawIRect(const SkIRect& rect, const SkPaint& paint) { + SkRect r; + r.set(rect); // promotes the ints to scalars + this->drawRect(r, paint); + } + + /** Draws SkRegion region using clip, SkMatrix, and SkPaint paint. + In paint: SkPaint::Style determines if rectangle is stroked or filled; + if stroked, SkPaint stroke width describes the line thickness, and + SkPaint::Join draws the corners rounded or square. + + @param region region to draw + @param paint SkPaint stroke or fill, blend, color, and so on, used to draw + + example: https://fiddle.skia.org/c/@Canvas_drawRegion + */ + void drawRegion(const SkRegion& region, const SkPaint& paint); + + /** Draws oval oval using clip, SkMatrix, and SkPaint. + In paint: SkPaint::Style determines if oval is stroked or filled; + if stroked, SkPaint stroke width describes the line thickness. + + @param oval SkRect bounds of oval + @param paint SkPaint stroke or fill, blend, color, and so on, used to draw + + example: https://fiddle.skia.org/c/@Canvas_drawOval + */ + void drawOval(const SkRect& oval, const SkPaint& paint); + + /** Draws SkRRect rrect using clip, SkMatrix, and SkPaint paint. + In paint: SkPaint::Style determines if rrect is stroked or filled; + if stroked, SkPaint stroke width describes the line thickness. + + rrect may represent a rectangle, circle, oval, uniformly rounded rectangle, or + may have any combination of positive non-square radii for the four corners. + + @param rrect SkRRect with up to eight corner radii to draw + @param paint SkPaint stroke or fill, blend, color, and so on, used to draw + + example: https://fiddle.skia.org/c/@Canvas_drawRRect + */ + void drawRRect(const SkRRect& rrect, const SkPaint& paint); + + /** Draws SkRRect outer and inner + using clip, SkMatrix, and SkPaint paint. + outer must contain inner or the drawing is undefined. + In paint: SkPaint::Style determines if SkRRect is stroked or filled; + if stroked, SkPaint stroke width describes the line thickness. + If stroked and SkRRect corner has zero length radii, SkPaint::Join can + draw corners rounded or square. + + GPU-backed platforms optimize drawing when both outer and inner are + concave and outer contains inner. These platforms may not be able to draw + SkPath built with identical data as fast. + + @param outer SkRRect outer bounds to draw + @param inner SkRRect inner bounds to draw + @param paint SkPaint stroke or fill, blend, color, and so on, used to draw + + example: https://fiddle.skia.org/c/@Canvas_drawDRRect_a + example: https://fiddle.skia.org/c/@Canvas_drawDRRect_b + */ + void drawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint); + + /** Draws circle at (cx, cy) with radius using clip, SkMatrix, and SkPaint paint. + If radius is zero or less, nothing is drawn. + In paint: SkPaint::Style determines if circle is stroked or filled; + if stroked, SkPaint stroke width describes the line thickness. + + @param cx circle center on the x-axis + @param cy circle center on the y-axis + @param radius half the diameter of circle + @param paint SkPaint stroke or fill, blend, color, and so on, used to draw + + example: https://fiddle.skia.org/c/@Canvas_drawCircle + */ + void drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint); + + /** Draws circle at center with radius using clip, SkMatrix, and SkPaint paint. + If radius is zero or less, nothing is drawn. + In paint: SkPaint::Style determines if circle is stroked or filled; + if stroked, SkPaint stroke width describes the line thickness. + + @param center circle center + @param radius half the diameter of circle + @param paint SkPaint stroke or fill, blend, color, and so on, used to draw + */ + void drawCircle(SkPoint center, SkScalar radius, const SkPaint& paint) { + this->drawCircle(center.x(), center.y(), radius, paint); + } + + /** Draws arc using clip, SkMatrix, and SkPaint paint. + + Arc is part of oval bounded by oval, sweeping from startAngle to startAngle plus + sweepAngle. startAngle and sweepAngle are in degrees. + + startAngle of zero places start point at the right middle edge of oval. + A positive sweepAngle places arc end point clockwise from start point; + a negative sweepAngle places arc end point counterclockwise from start point. + sweepAngle may exceed 360 degrees, a full circle. + If useCenter is true, draw a wedge that includes lines from oval + center to arc end points. If useCenter is false, draw arc between end points. + + If SkRect oval is empty or sweepAngle is zero, nothing is drawn. + + @param oval SkRect bounds of oval containing arc to draw + @param startAngle angle in degrees where arc begins + @param sweepAngle sweep angle in degrees; positive is clockwise + @param useCenter if true, include the center of the oval + @param paint SkPaint stroke or fill, blend, color, and so on, used to draw + */ + void drawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, + bool useCenter, const SkPaint& paint); + + /** Draws arc using clip, SkMatrix, and SkPaint paint. + + Arc is part of oval bounded by oval, sweeping from startAngle to startAngle plus + sweepAngle. startAngle and sweepAngle are in degrees. + + startAngle of zero places start point at the right middle edge of oval. + A positive sweepAngle places arc end point clockwise from start point; + a negative sweepAngle places arc end point counterclockwise from start point. + sweepAngle may exceed 360 degrees, a full circle. + If useCenter is true, draw a wedge that includes lines from oval + center to arc end points. If useCenter is false, draw arc between end points. + + If SkRect oval is empty or sweepAngle is zero, nothing is drawn. + + @param arc SkArc specifying oval, startAngle, sweepAngle, and arc-vs-wedge + @param paint SkPaint stroke or fill, blend, color, and so on, used to draw + */ + void drawArc(const SkArc& arc, const SkPaint& paint) { + this->drawArc(arc.fOval, arc.fStartAngle, arc.fSweepAngle, arc.isWedge(), paint); + } + + /** Draws SkRRect bounded by SkRect rect, with corner radii (rx, ry) using clip, + SkMatrix, and SkPaint paint. + + In paint: SkPaint::Style determines if SkRRect is stroked or filled; + if stroked, SkPaint stroke width describes the line thickness. + If rx or ry are less than zero, they are treated as if they are zero. + If rx plus ry exceeds rect width or rect height, radii are scaled down to fit. + If rx and ry are zero, SkRRect is drawn as SkRect and if stroked is affected by + SkPaint::Join. + + @param rect SkRect bounds of SkRRect to draw + @param rx axis length on x-axis of oval describing rounded corners + @param ry axis length on y-axis of oval describing rounded corners + @param paint stroke, blend, color, and so on, used to draw + + example: https://fiddle.skia.org/c/@Canvas_drawRoundRect + */ + void drawRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, const SkPaint& paint); + + /** Draws SkPath path using clip, SkMatrix, and SkPaint paint. + SkPath contains an array of path contour, each of which may be open or closed. + + In paint: SkPaint::Style determines if SkRRect is stroked or filled: + if filled, SkPath::FillType determines whether path contour describes inside or + outside of fill; if stroked, SkPaint stroke width describes the line thickness, + SkPaint::Cap describes line ends, and SkPaint::Join describes how + corners are drawn. + + @param path SkPath to draw + @param paint stroke, blend, color, and so on, used to draw + + example: https://fiddle.skia.org/c/@Canvas_drawPath + */ + void drawPath(const SkPath& path, const SkPaint& paint); + + void drawImage(const SkImage* image, SkScalar left, SkScalar top) { + this->drawImage(image, left, top, SkSamplingOptions(), nullptr); + } + void drawImage(const sk_sp& image, SkScalar left, SkScalar top) { + this->drawImage(image.get(), left, top, SkSamplingOptions(), nullptr); + } + + /** \enum SkCanvas::SrcRectConstraint + SrcRectConstraint controls the behavior at the edge of source SkRect, + provided to drawImageRect() when there is any filtering. If kStrict is set, + then extra code is used to ensure it never samples outside of the src-rect. + kStrict_SrcRectConstraint disables the use of mipmaps and anisotropic filtering. + */ + enum SrcRectConstraint { + kStrict_SrcRectConstraint, //!< sample only inside bounds; slower + kFast_SrcRectConstraint, //!< sample outside bounds; faster + }; + + void drawImage(const SkImage*, SkScalar x, SkScalar y, const SkSamplingOptions&, + const SkPaint* = nullptr); + void drawImage(const sk_sp& image, SkScalar x, SkScalar y, + const SkSamplingOptions& sampling, const SkPaint* paint = nullptr) { + this->drawImage(image.get(), x, y, sampling, paint); + } + void drawImageRect(const SkImage*, const SkRect& src, const SkRect& dst, + const SkSamplingOptions&, const SkPaint*, SrcRectConstraint); + void drawImageRect(const SkImage*, const SkRect& dst, const SkSamplingOptions&, + const SkPaint* = nullptr); + void drawImageRect(const sk_sp& image, const SkRect& src, const SkRect& dst, + const SkSamplingOptions& sampling, const SkPaint* paint, + SrcRectConstraint constraint) { + this->drawImageRect(image.get(), src, dst, sampling, paint, constraint); + } + void drawImageRect(const sk_sp& image, const SkRect& dst, + const SkSamplingOptions& sampling, const SkPaint* paint = nullptr) { + this->drawImageRect(image.get(), dst, sampling, paint); + } + + /** Draws SkImage image stretched proportionally to fit into SkRect dst. + SkIRect center divides the image into nine sections: four sides, four corners, and + the center. Corners are unmodified or scaled down proportionately if their sides + are larger than dst; center and four sides are scaled to fit remaining space, if any. + + Additionally transform draw using clip, SkMatrix, and optional SkPaint paint. + + If SkPaint paint is supplied, apply SkColorFilter, alpha, SkImageFilter, and + SkBlendMode. If image is kAlpha_8_SkColorType, apply SkShader. + If paint contains SkMaskFilter, generate mask from image bounds. + Any SkMaskFilter on paint is ignored as is paint anti-aliasing state. + + If generated mask extends beyond image bounds, replicate image edge colors, just + as SkShader made from SkImage::makeShader with SkShader::kClamp_TileMode set + replicates the image edge color when it samples outside of its bounds. + + @param image SkImage containing pixels, dimensions, and format + @param center SkIRect edge of image corners and sides + @param dst destination SkRect of image to draw to + @param filter what technique to use when sampling the image + @param paint SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter, + and so on; or nullptr + */ + void drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst, + SkFilterMode filter, const SkPaint* paint = nullptr); + + /** \struct SkCanvas::Lattice + SkCanvas::Lattice divides SkBitmap or SkImage into a rectangular grid. + Grid entries on even columns and even rows are fixed; these entries are + always drawn at their original size if the destination is large enough. + If the destination side is too small to hold the fixed entries, all fixed + entries are proportionately scaled down to fit. + The grid entries not on even columns and rows are scaled to fit the + remaining space, if any. + */ + struct Lattice { + + /** \enum SkCanvas::Lattice::RectType + Optional setting per rectangular grid entry to make it transparent, + or to fill the grid entry with a color. + */ + enum RectType : uint8_t { + kDefault = 0, //!< draws SkBitmap into lattice rectangle + kTransparent, //!< skips lattice rectangle by making it transparent + kFixedColor, //!< draws one of fColors into lattice rectangle + }; + + const int* fXDivs; //!< x-axis values dividing bitmap + const int* fYDivs; //!< y-axis values dividing bitmap + const RectType* fRectTypes; //!< array of fill types + int fXCount; //!< number of x-coordinates + int fYCount; //!< number of y-coordinates + const SkIRect* fBounds; //!< source bounds to draw from + const SkColor* fColors; //!< array of colors + }; + + /** Draws SkImage image stretched proportionally to fit into SkRect dst. + + SkCanvas::Lattice lattice divides image into a rectangular grid. + Each intersection of an even-numbered row and column is fixed; + fixed lattice elements never scale larger than their initial + size and shrink proportionately when all fixed elements exceed the bitmap + dimension. All other grid elements scale to fill the available space, if any. + + Additionally transform draw using clip, SkMatrix, and optional SkPaint paint. + + If SkPaint paint is supplied, apply SkColorFilter, alpha, SkImageFilter, and + SkBlendMode. If image is kAlpha_8_SkColorType, apply SkShader. + If paint contains SkMaskFilter, generate mask from image bounds. + Any SkMaskFilter on paint is ignored as is paint anti-aliasing state. + + If generated mask extends beyond bitmap bounds, replicate bitmap edge colors, + just as SkShader made from SkShader::MakeBitmapShader with + SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples + outside of its bounds. + + @param image SkImage containing pixels, dimensions, and format + @param lattice division of bitmap into fixed and variable rectangles + @param dst destination SkRect of image to draw to + @param filter what technique to use when sampling the image + @param paint SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter, + and so on; or nullptr + */ + void drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst, + SkFilterMode filter, const SkPaint* paint = nullptr); + void drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst) { + this->drawImageLattice(image, lattice, dst, SkFilterMode::kNearest, nullptr); + } + + /** + * Experimental. Controls anti-aliasing of each edge of images in an image-set. + */ + enum QuadAAFlags : unsigned { + kLeft_QuadAAFlag = 0b0001, + kTop_QuadAAFlag = 0b0010, + kRight_QuadAAFlag = 0b0100, + kBottom_QuadAAFlag = 0b1000, + + kNone_QuadAAFlags = 0b0000, + kAll_QuadAAFlags = 0b1111, + }; + + /** This is used by the experimental API below. */ + struct SK_API ImageSetEntry { + ImageSetEntry(sk_sp image, const SkRect& srcRect, const SkRect& dstRect, + int matrixIndex, float alpha, unsigned aaFlags, bool hasClip); + + ImageSetEntry(sk_sp image, const SkRect& srcRect, const SkRect& dstRect, + float alpha, unsigned aaFlags); + + ImageSetEntry(); + ~ImageSetEntry(); + ImageSetEntry(const ImageSetEntry&); + ImageSetEntry& operator=(const ImageSetEntry&); + + sk_sp fImage; + SkRect fSrcRect; + SkRect fDstRect; + int fMatrixIndex = -1; // Index into the preViewMatrices arg, or < 0 + float fAlpha = 1.f; + unsigned fAAFlags = kNone_QuadAAFlags; // QuadAAFlags + bool fHasClip = false; // True to use next 4 points in dstClip arg as quad + }; + + /** + * This is an experimental API for the SkiaRenderer Chromium project, and its API will surely + * evolve if it is not removed outright. + * + * This behaves very similarly to drawRect() combined with a clipPath() formed by clip + * quadrilateral. 'rect' and 'clip' are in the same coordinate space. If 'clip' is null, then it + * is as if the rectangle was not clipped (or, alternatively, clipped to itself). If not null, + * then it must provide 4 points. + * + * In addition to combining the draw and clipping into one operation, this function adds the + * additional capability of controlling each of the rectangle's edges anti-aliasing + * independently. The edges of the clip will respect the per-edge AA flags. It is required that + * 'clip' be contained inside 'rect'. In terms of mapping to edge labels, the 'clip' points + * should be ordered top-left, top-right, bottom-right, bottom-left so that the edge between [0] + * and [1] is "top", [1] and [2] is "right", [2] and [3] is "bottom", and [3] and [0] is "left". + * This ordering matches SkRect::toQuad(). + * + * This API only draws solid color, filled rectangles so it does not accept a full SkPaint. + */ + void experimental_DrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4], QuadAAFlags aaFlags, + const SkColor4f& color, SkBlendMode mode); + void experimental_DrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4], QuadAAFlags aaFlags, + SkColor color, SkBlendMode mode) { + this->experimental_DrawEdgeAAQuad(rect, clip, aaFlags, SkColor4f::FromColor(color), mode); + } + + /** + * This is an bulk variant of experimental_DrawEdgeAAQuad() that renders 'cnt' textured quads. + * For each entry, 'fDstRect' is rendered with its clip (determined by entry's 'fHasClip' and + * the current index in 'dstClip'). The entry's fImage is applied to the destination rectangle + * by sampling from 'fSrcRect' sub-image. The corners of 'fSrcRect' map to the corners of + * 'fDstRect', just like in drawImageRect(), and they will be properly interpolated when + * applying a clip. + * + * Like experimental_DrawEdgeAAQuad(), each entry can specify edge AA flags that apply to both + * the destination rect and its clip. + * + * If provided, the 'dstClips' array must have length equal 4 * the number of entries with + * fHasClip true. If 'dstClips' is null, every entry must have 'fHasClip' set to false. The + * destination clip coordinates will be read consecutively with the image set entries, advancing + * by 4 points every time an entry with fHasClip is passed. + * + * This entry point supports per-entry manipulations to the canvas's current matrix. If an + * entry provides 'fMatrixIndex' >= 0, it will be drawn as if the canvas's CTM was + * canvas->getTotalMatrix() * preViewMatrices[fMatrixIndex]. If 'fMatrixIndex' is less than 0, + * the pre-view matrix transform is implicitly the identity, so it will be drawn using just the + * current canvas matrix. The pre-view matrix modifies the canvas's view matrix, it does not + * affect the local coordinates of each entry. + * + * An optional paint may be provided, which supports the same subset of features usable with + * drawImageRect (i.e. assumed to be filled and no path effects). When a paint is provided, the + * image set is drawn as if each image used the applied paint independently, so each is affected + * by the image, color, and/or mask filter. + */ + void experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[], int cnt, + const SkPoint dstClips[], const SkMatrix preViewMatrices[], + const SkSamplingOptions&, const SkPaint* paint = nullptr, + SrcRectConstraint constraint = kStrict_SrcRectConstraint); + + /** Draws text, with origin at (x, y), using clip, SkMatrix, SkFont font, + and SkPaint paint. + + When encoding is SkTextEncoding::kUTF8, SkTextEncoding::kUTF16, or + SkTextEncoding::kUTF32, this function uses the default + character-to-glyph mapping from the SkTypeface in font. It does not + perform typeface fallback for characters not found in the SkTypeface. + It does not perform kerning or other complex shaping; glyphs are + positioned based on their default advances. + + Text meaning depends on SkTextEncoding. + + Text size is affected by SkMatrix and SkFont text size. Default text + size is 12 point. + + All elements of paint: SkPathEffect, SkMaskFilter, SkShader, + SkColorFilter, and SkImageFilter; apply to text. By + default, draws filled black glyphs. + + @param text character code points or glyphs drawn + @param byteLength byte length of text array + @param encoding text encoding used in the text array + @param x start of text on x-axis + @param y start of text on y-axis + @param font typeface, text size and so, used to describe the text + @param paint blend, color, and so on, used to draw + */ + void drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding, + SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint); + + /** Draws null terminated string, with origin at (x, y), using clip, SkMatrix, + SkFont font, and SkPaint paint. + + This function uses the default character-to-glyph mapping from the + SkTypeface in font. It does not perform typeface fallback for + characters not found in the SkTypeface. It does not perform kerning; + glyphs are positioned based on their default advances. + + String str is encoded as UTF-8. + + Text size is affected by SkMatrix and font text size. Default text + size is 12 point. + + All elements of paint: SkPathEffect, SkMaskFilter, SkShader, + SkColorFilter, and SkImageFilter; apply to text. By + default, draws filled black glyphs. + + @param str character code points drawn, + ending with a char value of zero + @param x start of string on x-axis + @param y start of string on y-axis + @param font typeface, text size and so, used to describe the text + @param paint blend, color, and so on, used to draw + */ + void drawString(const char str[], SkScalar x, SkScalar y, const SkFont& font, + const SkPaint& paint) { + this->drawSimpleText(str, strlen(str), SkTextEncoding::kUTF8, x, y, font, paint); + } + + /** Draws SkString, with origin at (x, y), using clip, SkMatrix, SkFont font, + and SkPaint paint. + + This function uses the default character-to-glyph mapping from the + SkTypeface in font. It does not perform typeface fallback for + characters not found in the SkTypeface. It does not perform kerning; + glyphs are positioned based on their default advances. + + SkString str is encoded as UTF-8. + + Text size is affected by SkMatrix and SkFont text size. Default text + size is 12 point. + + All elements of paint: SkPathEffect, SkMaskFilter, SkShader, + SkColorFilter, and SkImageFilter; apply to text. By + default, draws filled black glyphs. + + @param str character code points drawn, + ending with a char value of zero + @param x start of string on x-axis + @param y start of string on y-axis + @param font typeface, text size and so, used to describe the text + @param paint blend, color, and so on, used to draw + */ + void drawString(const SkString& str, SkScalar x, SkScalar y, const SkFont& font, + const SkPaint& paint) { + this->drawSimpleText(str.c_str(), str.size(), SkTextEncoding::kUTF8, x, y, font, paint); + } + + /** Draws count glyphs, at positions relative to origin styled with font and paint with + supporting utf8 and cluster information. + + This function draw glyphs at the given positions relative to the given origin. + It does not perform typeface fallback for glyphs not found in the SkTypeface in font. + + The drawing obeys the current transform matrix and clipping. + + All elements of paint: SkPathEffect, SkMaskFilter, SkShader, + SkColorFilter, and SkImageFilter; apply to text. By + default, draws filled black glyphs. + + @param count number of glyphs to draw + @param glyphs the array of glyphIDs to draw + @param positions where to draw each glyph relative to origin + @param clusters array of size count of cluster information + @param textByteCount size of the utf8text + @param utf8text utf8text supporting information for the glyphs + @param origin the origin of all the positions + @param font typeface, text size and so, used to describe the text + @param paint blend, color, and so on, used to draw + */ + void drawGlyphs(int count, const SkGlyphID glyphs[], const SkPoint positions[], + const uint32_t clusters[], int textByteCount, const char utf8text[], + SkPoint origin, const SkFont& font, const SkPaint& paint); + + /** Draws count glyphs, at positions relative to origin styled with font and paint. + + This function draw glyphs at the given positions relative to the given origin. + It does not perform typeface fallback for glyphs not found in the SkTypeface in font. + + The drawing obeys the current transform matrix and clipping. + + All elements of paint: SkPathEffect, SkMaskFilter, SkShader, + SkColorFilter, and SkImageFilter; apply to text. By + default, draws filled black glyphs. + + @param count number of glyphs to draw + @param glyphs the array of glyphIDs to draw + @param positions where to draw each glyph relative to origin + @param origin the origin of all the positions + @param font typeface, text size and so, used to describe the text + @param paint blend, color, and so on, used to draw + */ + void drawGlyphs(int count, const SkGlyphID glyphs[], const SkPoint positions[], + SkPoint origin, const SkFont& font, const SkPaint& paint); + + /** Draws count glyphs, at positions relative to origin styled with font and paint. + + This function draw glyphs using the given scaling and rotations. They are positioned + relative to the given origin. It does not perform typeface fallback for glyphs not found + in the SkTypeface in font. + + The drawing obeys the current transform matrix and clipping. + + All elements of paint: SkPathEffect, SkMaskFilter, SkShader, + SkColorFilter, and SkImageFilter; apply to text. By + default, draws filled black glyphs. + + @param count number of glyphs to draw + @param glyphs the array of glyphIDs to draw + @param xforms where to draw and orient each glyph + @param origin the origin of all the positions + @param font typeface, text size and so, used to describe the text + @param paint blend, color, and so on, used to draw + */ + void drawGlyphs(int count, const SkGlyphID glyphs[], const SkRSXform xforms[], + SkPoint origin, const SkFont& font, const SkPaint& paint); + + /** Draws SkTextBlob blob at (x, y), using clip, SkMatrix, and SkPaint paint. + + blob contains glyphs, their positions, and paint attributes specific to text: + SkTypeface, SkPaint text size, SkPaint text scale x, + SkPaint text skew x, SkPaint::Align, SkPaint::Hinting, anti-alias, SkPaint fake bold, + SkPaint font embedded bitmaps, SkPaint full hinting spacing, LCD text, SkPaint linear text, + and SkPaint subpixel text. + + SkTextEncoding must be set to SkTextEncoding::kGlyphID. + + Elements of paint: anti-alias, SkBlendMode, color including alpha, + SkColorFilter, SkPaint dither, SkMaskFilter, SkPathEffect, SkShader, and + SkPaint::Style; apply to blob. If SkPaint contains SkPaint::kStroke_Style: + SkPaint miter limit, SkPaint::Cap, SkPaint::Join, and SkPaint stroke width; + apply to SkPath created from blob. + + @param blob glyphs, positions, and their paints' text size, typeface, and so on + @param x horizontal offset applied to blob + @param y vertical offset applied to blob + @param paint blend, color, stroking, and so on, used to draw + + example: https://fiddle.skia.org/c/@Canvas_drawTextBlob + */ + void drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint); + + /** Draws SkTextBlob blob at (x, y), using clip, SkMatrix, and SkPaint paint. + + blob contains glyphs, their positions, and paint attributes specific to text: + SkTypeface, SkPaint text size, SkPaint text scale x, + SkPaint text skew x, SkPaint::Align, SkPaint::Hinting, anti-alias, SkPaint fake bold, + SkPaint font embedded bitmaps, SkPaint full hinting spacing, LCD text, SkPaint linear text, + and SkPaint subpixel text. + + SkTextEncoding must be set to SkTextEncoding::kGlyphID. + + Elements of paint: SkPathEffect, SkMaskFilter, SkShader, SkColorFilter, + and SkImageFilter; apply to blob. + + @param blob glyphs, positions, and their paints' text size, typeface, and so on + @param x horizontal offset applied to blob + @param y vertical offset applied to blob + @param paint blend, color, stroking, and so on, used to draw + */ + void drawTextBlob(const sk_sp& blob, SkScalar x, SkScalar y, const SkPaint& paint) { + this->drawTextBlob(blob.get(), x, y, paint); + } + + /** Draws SkPicture picture, using clip and SkMatrix. + Clip and SkMatrix are unchanged by picture contents, as if + save() was called before and restore() was called after drawPicture(). + + SkPicture records a series of draw commands for later playback. + + @param picture recorded drawing commands to play + */ + void drawPicture(const SkPicture* picture) { + this->drawPicture(picture, nullptr, nullptr); + } + + /** Draws SkPicture picture, using clip and SkMatrix. + Clip and SkMatrix are unchanged by picture contents, as if + save() was called before and restore() was called after drawPicture(). + + SkPicture records a series of draw commands for later playback. + + @param picture recorded drawing commands to play + */ + void drawPicture(const sk_sp& picture) { + this->drawPicture(picture.get()); + } + + /** Draws SkPicture picture, using clip and SkMatrix; transforming picture with + SkMatrix matrix, if provided; and use SkPaint paint alpha, SkColorFilter, + SkImageFilter, and SkBlendMode, if provided. + + If paint is non-null, then the picture is always drawn into a temporary layer before + actually landing on the canvas. Note that drawing into a layer can also change its + appearance if there are any non-associative blendModes inside any of the pictures elements. + + @param picture recorded drawing commands to play + @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 + + example: https://fiddle.skia.org/c/@Canvas_drawPicture_3 + */ + void drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint); + + /** Draws SkPicture picture, using clip and SkMatrix; transforming picture with + SkMatrix matrix, if provided; and use SkPaint paint alpha, SkColorFilter, + SkImageFilter, and SkBlendMode, if provided. + + If paint is non-null, then the picture is always drawn into a temporary layer before + actually landing on the canvas. Note that drawing into a layer can also change its + appearance if there are any non-associative blendModes inside any of the pictures elements. + + @param picture recorded drawing commands to play + @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 + */ + void drawPicture(const sk_sp& picture, const SkMatrix* matrix, + const SkPaint* paint) { + this->drawPicture(picture.get(), matrix, paint); + } + + /** Draws SkVertices vertices, a triangle mesh, using clip and SkMatrix. + If paint contains an SkShader and vertices does not contain texCoords, the shader + is mapped using the vertices' positions. + + SkBlendMode is ignored if SkVertices does not have colors. Otherwise, it combines + - the SkShader if SkPaint contains SkShader + - or the opaque SkPaint color if SkPaint does not contain SkShader + as the src of the blend and the interpolated vertex colors as the dst. + + SkMaskFilter, SkPathEffect, and antialiasing on SkPaint are ignored. + + @param vertices triangle mesh to draw + @param mode combines vertices' colors with SkShader if present or SkPaint opaque color + if not. Ignored if the vertices do not contain color. + @param paint specifies the SkShader, used as SkVertices texture, and SkColorFilter. + + example: https://fiddle.skia.org/c/@Canvas_drawVertices + */ + void drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint); + + /** Draws SkVertices vertices, a triangle mesh, using clip and SkMatrix. + If paint contains an SkShader and vertices does not contain texCoords, the shader + is mapped using the vertices' positions. + + SkBlendMode is ignored if SkVertices does not have colors. Otherwise, it combines + - the SkShader if SkPaint contains SkShader + - or the opaque SkPaint color if SkPaint does not contain SkShader + as the src of the blend and the interpolated vertex colors as the dst. + + SkMaskFilter, SkPathEffect, and antialiasing on SkPaint are ignored. + + @param vertices triangle mesh to draw + @param mode combines vertices' colors with SkShader if present or SkPaint opaque color + if not. Ignored if the vertices do not contain color. + @param paint specifies the SkShader, used as SkVertices texture, may be nullptr + + example: https://fiddle.skia.org/c/@Canvas_drawVertices_2 + */ + void drawVertices(const sk_sp& vertices, SkBlendMode mode, const SkPaint& paint); + + /** + Experimental, under active development, and subject to change without notice. + + Draws a mesh using a user-defined specification (see SkMeshSpecification). Requires + a GPU backend or SkSL to be compiled in. + + SkBlender is ignored if SkMesh's specification does not output fragment shader color. + Otherwise, it combines + - the SkShader if SkPaint contains SkShader + - or the opaque SkPaint color if SkPaint does not contain SkShader + as the src of the blend and the mesh's fragment color as the dst. + + SkMaskFilter, SkPathEffect, and antialiasing on SkPaint are ignored. + + @param mesh the mesh vertices and compatible specification. + @param blender combines vertices colors with SkShader if present or SkPaint opaque color + if not. Ignored if the custom mesh does not output color. Defaults to + SkBlendMode::kModulate if nullptr. + @param paint specifies the SkShader, used as SkVertices texture, may be nullptr + */ + void drawMesh(const SkMesh& mesh, sk_sp blender, const SkPaint& paint); + + /** Draws a Coons patch: the interpolation of four cubics with shared corners, + associating a color, and optionally a texture SkPoint, with each corner. + + SkPoint array cubics specifies four SkPath cubic starting at the top-left corner, + in clockwise order, sharing every fourth point. The last SkPath cubic ends at the + first point. + + Color array color associates colors with corners in top-left, top-right, + bottom-right, bottom-left order. + + If paint contains SkShader, SkPoint array texCoords maps SkShader as texture to + corners in top-left, top-right, bottom-right, bottom-left order. If texCoords is + nullptr, SkShader is mapped using positions (derived from cubics). + + SkBlendMode is ignored if colors is null. Otherwise, it combines + - the SkShader if SkPaint contains SkShader + - or the opaque SkPaint color if SkPaint does not contain SkShader + as the src of the blend and the interpolated patch colors as the dst. + + SkMaskFilter, SkPathEffect, and antialiasing on SkPaint are ignored. + + @param cubics SkPath cubic array, sharing common points + @param colors color array, one for each corner + @param texCoords SkPoint array of texture coordinates, mapping SkShader to corners; + may be nullptr + @param mode combines patch's colors with SkShader if present or SkPaint opaque color + if not. Ignored if colors is null. + @param paint SkShader, SkColorFilter, SkBlendMode, used to draw + */ + void drawPatch(const SkPoint cubics[12], const SkColor colors[4], + const SkPoint texCoords[4], SkBlendMode mode, const SkPaint& paint); + + /** Draws a set of sprites from atlas, using clip, SkMatrix, and optional SkPaint paint. + paint uses anti-alias, alpha, SkColorFilter, SkImageFilter, and SkBlendMode + to draw, if present. For each entry in the array, SkRect tex locates sprite in + atlas, and SkRSXform xform transforms it into destination space. + + SkMaskFilter and SkPathEffect on paint are ignored. + + xform, tex, and colors if present, must contain count entries. + Optional colors are applied for each sprite using SkBlendMode mode, treating + sprite as source and colors as destination. + Optional cullRect is a conservative bounds of all transformed sprites. + If cullRect is outside of clip, canvas can skip drawing. + + If atlas is nullptr, this draws nothing. + + @param atlas SkImage containing sprites + @param xform SkRSXform mappings for sprites in atlas + @param tex SkRect locations of sprites in atlas + @param colors one per sprite, blended with sprite using SkBlendMode; may be nullptr + @param count number of sprites to draw + @param mode SkBlendMode combining colors and sprites + @param sampling SkSamplingOptions used when sampling from the atlas image + @param cullRect bounds of transformed sprites for efficient clipping; may be nullptr + @param paint SkColorFilter, SkImageFilter, SkBlendMode, and so on; may be nullptr + */ + void drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], + const SkColor colors[], int count, SkBlendMode mode, + const SkSamplingOptions& sampling, const SkRect* cullRect, const SkPaint* paint); + + /** Draws SkDrawable drawable using clip and SkMatrix, concatenated with + optional matrix. + + If SkCanvas has an asynchronous implementation, as is the case + when it is recording into SkPicture, then drawable will be referenced, + so that SkDrawable::draw() can be called when the operation is finalized. To force + immediate drawing, call SkDrawable::draw() instead. + + @param drawable custom struct encapsulating drawing commands + @param matrix transformation applied to drawing; may be nullptr + + example: https://fiddle.skia.org/c/@Canvas_drawDrawable + */ + void drawDrawable(SkDrawable* drawable, const SkMatrix* matrix = nullptr); + + /** Draws SkDrawable drawable using clip and SkMatrix, offset by (x, y). + + If SkCanvas has an asynchronous implementation, as is the case + when it is recording into SkPicture, then drawable will be referenced, + so that SkDrawable::draw() can be called when the operation is finalized. To force + immediate drawing, call SkDrawable::draw() instead. + + @param drawable custom struct encapsulating drawing commands + @param x offset into SkCanvas writable pixels on x-axis + @param y offset into SkCanvas writable pixels on y-axis + + example: https://fiddle.skia.org/c/@Canvas_drawDrawable_2 + */ + void drawDrawable(SkDrawable* drawable, SkScalar x, SkScalar y); + + /** Associates SkRect on SkCanvas with an annotation; a key-value pair, where the key is + a null-terminated UTF-8 string, and optional value is stored as SkData. + + Only some canvas implementations, such as recording to SkPicture, or drawing to + document PDF, use annotations. + + @param rect SkRect extent of canvas to annotate + @param key string used for lookup + @param value data holding value stored in annotation + + example: https://fiddle.skia.org/c/@Canvas_drawAnnotation_2 + */ + void drawAnnotation(const SkRect& rect, const char key[], SkData* value); + + /** Associates SkRect on SkCanvas when an annotation; a key-value pair, where the key is + a null-terminated UTF-8 string, and optional value is stored as SkData. + + Only some canvas implementations, such as recording to SkPicture, or drawing to + document PDF, use annotations. + + @param rect SkRect extent of canvas to annotate + @param key string used for lookup + @param value data holding value stored in annotation + */ + void drawAnnotation(const SkRect& rect, const char key[], const sk_sp& value) { + this->drawAnnotation(rect, key, value.get()); + } + + /** Returns true if clip is empty; that is, nothing will draw. + + May do work when called; it should not be called + more often than needed. However, once called, subsequent calls perform no + work until clip changes. + + @return true if clip is empty + + example: https://fiddle.skia.org/c/@Canvas_isClipEmpty + */ + virtual bool isClipEmpty() const; + + /** Returns true if clip is SkRect and not empty. + Returns false if the clip is empty, or if it is not SkRect. + + @return true if clip is SkRect and not empty + + example: https://fiddle.skia.org/c/@Canvas_isClipRect + */ + virtual bool isClipRect() const; + + /** Returns the current transform from local coordinates to the 'device', which for most + * purposes means pixels. + * + * @return transformation from local coordinates to device / pixels. + */ + SkM44 getLocalToDevice() const; + + /** + * Throws away the 3rd row and column in the matrix, so be warned. + */ + SkMatrix getLocalToDeviceAs3x3() const { + return this->getLocalToDevice().asM33(); + } + +#ifdef SK_SUPPORT_LEGACY_GETTOTALMATRIX + /** DEPRECATED + * Legacy version of getLocalToDevice(), which strips away any Z information, and + * just returns a 3x3 version. + * + * @return 3x3 version of getLocalToDevice() + * + * example: https://fiddle.skia.org/c/@Canvas_getTotalMatrix + * example: https://fiddle.skia.org/c/@Clip + */ + SkMatrix getTotalMatrix() const; +#endif + + /////////////////////////////////////////////////////////////////////////// + + /** + * Returns the global clip as a region. If the clip contains AA, then only the bounds + * of the clip may be returned. + */ + void temporary_internal_getRgnClip(SkRegion* region); + + void private_draw_shadow_rec(const SkPath&, const SkDrawShadowRec&); + + +protected: + // default impl defers to getDevice()->newSurface(info) + virtual sk_sp onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props); + + // default impl defers to its device + virtual bool onPeekPixels(SkPixmap* pixmap); + virtual bool onAccessTopLayerPixels(SkPixmap* pixmap); + virtual SkImageInfo onImageInfo() const; + virtual bool onGetProps(SkSurfaceProps* props, bool top) const; + + // Subclass save/restore notifiers. + // Overriders should call the corresponding INHERITED method up the inheritance chain. + // getSaveLayerStrategy()'s return value may suppress full layer allocation. + enum SaveLayerStrategy { + kFullLayer_SaveLayerStrategy, + kNoLayer_SaveLayerStrategy, + }; + + virtual void willSave() {} + // Overriders should call the corresponding INHERITED method up the inheritance chain. + virtual SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& ) { + return kFullLayer_SaveLayerStrategy; + } + + // returns true if we should actually perform the saveBehind, or false if we should just save. + virtual bool onDoSaveBehind(const SkRect*) { return true; } + virtual void willRestore() {} + virtual void didRestore() {} + + virtual void didConcat44(const SkM44&) {} + virtual void didSetM44(const SkM44&) {} + virtual void didTranslate(SkScalar, SkScalar) {} + virtual void didScale(SkScalar, SkScalar) {} + + // NOTE: If you are adding a new onDraw virtual to SkCanvas, PLEASE add an override to + // SkCanvasVirtualEnforcer (in SkCanvasVirtualEnforcer.h). This ensures that subclasses using + // that mechanism will be required to implement the new function. + virtual void onDrawPaint(const SkPaint& paint); + virtual void onDrawBehind(const SkPaint& paint); + virtual void onDrawRect(const SkRect& rect, const SkPaint& paint); + virtual void onDrawRRect(const SkRRect& rrect, const SkPaint& paint); + virtual void onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint); + virtual void onDrawOval(const SkRect& rect, const SkPaint& paint); + virtual void onDrawArc(const SkRect& rect, SkScalar startAngle, SkScalar sweepAngle, + bool useCenter, const SkPaint& paint); + virtual void onDrawPath(const SkPath& path, const SkPaint& paint); + virtual void onDrawRegion(const SkRegion& region, const SkPaint& paint); + + virtual void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, + const SkPaint& paint); + + virtual void onDrawGlyphRunList(const sktext::GlyphRunList& glyphRunList, const SkPaint& paint); + + virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], + const SkPoint texCoords[4], SkBlendMode mode, const SkPaint& paint); + virtual void onDrawPoints(PointMode mode, size_t count, const SkPoint pts[], + const SkPaint& paint); + + virtual void onDrawImage2(const SkImage*, SkScalar dx, SkScalar dy, const SkSamplingOptions&, + const SkPaint*); + virtual void onDrawImageRect2(const SkImage*, const SkRect& src, const SkRect& dst, + const SkSamplingOptions&, const SkPaint*, SrcRectConstraint); + virtual void onDrawImageLattice2(const SkImage*, const Lattice&, const SkRect& dst, + SkFilterMode, const SkPaint*); + virtual void onDrawAtlas2(const SkImage*, const SkRSXform[], const SkRect src[], + const SkColor[], int count, SkBlendMode, const SkSamplingOptions&, + const SkRect* cull, const SkPaint*); + virtual void onDrawEdgeAAImageSet2(const ImageSetEntry imageSet[], int count, + const SkPoint dstClips[], const SkMatrix preViewMatrices[], + const SkSamplingOptions&, const SkPaint*, + SrcRectConstraint); + + virtual void onDrawVerticesObject(const SkVertices* vertices, SkBlendMode mode, + const SkPaint& paint); + virtual void onDrawMesh(const SkMesh&, sk_sp, const SkPaint&); + virtual void onDrawAnnotation(const SkRect& rect, const char key[], SkData* value); + virtual void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&); + + virtual void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix); + virtual void onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, + const SkPaint* paint); + + virtual void onDrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4], QuadAAFlags aaFlags, + const SkColor4f& color, SkBlendMode mode); + + enum ClipEdgeStyle { + kHard_ClipEdgeStyle, + kSoft_ClipEdgeStyle + }; + + virtual void onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle); + virtual void onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle); + virtual void onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle); + virtual void onClipShader(sk_sp, SkClipOp); + virtual void onClipRegion(const SkRegion& deviceRgn, SkClipOp op); + virtual void onResetClip(); + + virtual void onDiscard(); + + /** + */ + virtual sk_sp onConvertGlyphRunListToSlug( + const sktext::GlyphRunList& glyphRunList, const SkPaint& paint); + + /** + */ + virtual void onDrawSlug(const sktext::gpu::Slug* slug, const SkPaint& paint); + +private: + enum class PredrawFlags : unsigned { + kNone = 0, + kOpaqueShaderOverride = 1, // The paint's shader is overridden with an opaque image + kNonOpaqueShaderOverride = 2, // The paint's shader is overridden but is not opaque + kCheckForOverwrite = 4, // Check if the draw would overwrite the entire surface + kSkipMaskFilterAutoLayer = 8, // Do not apply mask filters in the AutoLayer + }; + // Inlined SK_DECL_BITMASK_OPS_FRIENDS to avoid including SkEnumBitMask.h + friend constexpr SkEnumBitMask operator|(PredrawFlags, PredrawFlags); + friend constexpr SkEnumBitMask operator&(PredrawFlags, PredrawFlags); + friend constexpr SkEnumBitMask operator^(PredrawFlags, PredrawFlags); + friend constexpr SkEnumBitMask operator~(PredrawFlags); + + // notify our surface (if we have one) that we are about to draw, so it + // can perform copy-on-write or invalidate any cached images + // returns false if the copy failed + [[nodiscard]] bool predrawNotify(bool willOverwritesEntireSurface = false); + [[nodiscard]] bool predrawNotify(const SkRect*, const SkPaint*, SkEnumBitMask); + + // call the appropriate predrawNotify and create a layer if needed. + std::optional aboutToDraw( + const SkPaint& paint, + const SkRect* rawBounds, + SkEnumBitMask flags); + std::optional aboutToDraw( + const SkPaint& paint, + const SkRect* rawBounds = nullptr); + + // The bottom-most device in the stack, only changed by init(). Image properties and the final + // canvas pixels are determined by this device. + SkDevice* rootDevice() const { + SkASSERT(fRootDevice); + return fRootDevice.get(); + } + + // The top-most device in the stack, will change within saveLayer()'s. All drawing and clipping + // operations should route to this device. + SkDevice* topDevice() const; + + // Canvases maintain a sparse stack of layers, where the top-most layer receives the drawing, + // clip, and matrix commands. There is a layer per call to saveLayer() using the + // kFullLayer_SaveLayerStrategy. + struct Layer { + sk_sp fDevice; + skia_private::STArray<1, sk_sp> fImageFilters; + SkPaint fPaint; + bool fIsCoverage; + bool fDiscard; + + Layer(sk_sp device, + FilterSpan imageFilters, + const SkPaint& paint, + bool isCoverage); + }; + + // Encapsulate state needed to restore from saveBehind() + struct BackImage { + // Out of line to avoid including SkSpecialImage.h + BackImage(sk_sp, SkIPoint); + BackImage(const BackImage&); + BackImage(BackImage&&); + BackImage& operator=(const BackImage&); + ~BackImage(); + + sk_sp fImage; + SkIPoint fLoc; + }; + + class MCRec { + public: + // If not null, this MCRec corresponds with the saveLayer() record that made the layer. + // The base "layer" is not stored here, since it is stored inline in SkCanvas and has no + // restoration behavior. + std::unique_ptr fLayer; + + // This points to the device of the top-most layer (which may be lower in the stack), or + // to the canvas's fRootDevice. The MCRec does not own the device. + SkDevice* fDevice; + + std::unique_ptr fBackImage; + SkM44 fMatrix; + int fDeferredSaveCount = 0; + + MCRec(SkDevice* device); + MCRec(const MCRec* prev); + ~MCRec(); + + void newLayer(sk_sp layerDevice, + FilterSpan filters, + const SkPaint& restorePaint, + bool layerIsCoverage); + + void reset(SkDevice* device); + }; + + // the first N recs that can fit here mean we won't call malloc + static constexpr int kMCRecSize = 96; // most recent measurement + static constexpr int kMCRecCount = 32; // common depth for save/restores + + intptr_t fMCRecStorage[kMCRecSize * kMCRecCount / sizeof(intptr_t)]; + + SkDeque fMCStack; + // points to top of stack + MCRec* fMCRec; + + // Installed via init() + sk_sp fRootDevice; + const SkSurfaceProps fProps; + + int fSaveCount; // value returned by getSaveCount() + + std::unique_ptr fAllocator; + + SkSurface_Base* fSurfaceBase; + SkSurface_Base* getSurfaceBase() const { return fSurfaceBase; } + void setSurfaceBase(SkSurface_Base* sb) { + fSurfaceBase = sb; + } + friend class SkSurface_Base; + friend class SkSurface_Ganesh; + + SkIRect fClipRestrictionRect = SkIRect::MakeEmpty(); + int fClipRestrictionSaveCount = -1; + + void doSave(); + void checkForDeferredSave(); + void internalSetMatrix(const SkM44&); + + friend class SkAndroidFrameworkUtils; + friend class SkCanvasPriv; // needs to expose android functions for testing outside android + friend class AutoLayerForImageFilter; + friend class SkSurface_Raster; // needs getDevice() + friend class SkNoDrawCanvas; // needs resetForNextPicture() + friend class SkNWayCanvas; + friend class SkPictureRecord; // predrawNotify (why does it need it? ) + friend class SkOverdrawCanvas; + friend class SkRasterHandleAllocator; + friend class SkRecords::Draw; + template + friend class SkTestCanvas; + +protected: + // For use by SkNoDrawCanvas (via SkCanvasVirtualEnforcer, which can't be a friend) + SkCanvas(const SkIRect& bounds); +private: + SkCanvas(const SkBitmap&, std::unique_ptr, + SkRasterHandleAllocator::Handle, const SkSurfaceProps* props); + + SkCanvas(SkCanvas&&) = delete; + SkCanvas(const SkCanvas&) = delete; + SkCanvas& operator=(SkCanvas&&) = delete; + SkCanvas& operator=(const SkCanvas&) = delete; + + friend class sktext::gpu::Slug; + friend class SkPicturePlayback; + /** + * Convert a SkTextBlob to a sktext::gpu::Slug using the current canvas state. + */ + sk_sp convertBlobToSlug(const SkTextBlob& blob, SkPoint origin, + const SkPaint& paint); + + /** + * Draw an sktext::gpu::Slug given the current canvas state. + */ + void drawSlug(const sktext::gpu::Slug* slug, const SkPaint& paint); + + /** Experimental + * Saves the specified subset of the current pixels in the current layer, + * and then clears those pixels to transparent black. + * Restores the pixels on restore() by drawing them in SkBlendMode::kDstOver. + * + * @param subset conservative bounds of the area to be saved / restored. + * @return depth of save state stack before this call was made. + */ + int only_axis_aligned_saveBehind(const SkRect* subset); + + /** + * Like drawPaint, but magically clipped to the most recent saveBehind buffer rectangle. + * If there is no active saveBehind, then this draws nothing. + */ + void drawClippedToSaveBehind(const SkPaint&); + + void resetForNextPicture(const SkIRect& bounds); + + // needs gettotalclip() + friend class SkCanvasStateUtils; + + void init(sk_sp); + + // All base onDrawX() functions should call this and skip drawing if it returns true. + // If 'matrix' is non-null, it maps the paint's fast bounds before checking for quick rejection + bool internalQuickReject(const SkRect& bounds, const SkPaint& paint, + const SkMatrix* matrix = nullptr); + + void internalDrawPaint(const SkPaint& paint); + void internalSaveLayer(const SaveLayerRec&, SaveLayerStrategy, bool coverageOnly=false); + void internalSaveBehind(const SkRect*); + + void internalConcat44(const SkM44&); + + // shared by save() and saveLayer() + void internalSave(); + void internalRestore(); + + enum class DeviceCompatibleWithFilter : bool { + // Check the src device's local-to-device matrix for compatibility with the filter, and if + // it is not compatible, introduce an intermediate image and transformation that allows the + // filter to be evaluated on the modified src content. + kUnknown = false, + // Assume that the src device's local-to-device matrix is compatible with the filter. + kYes = true + }; + /** + * Filters the contents of 'src' and draws the result into 'dst'. The filter is evaluated + * relative to the current canvas matrix, and src is drawn to dst using their relative transform + * 'paint' is applied after the filter and must not have a mask or image filter of its own. + * A null 'filter' behaves as if the identity filter were used. + * + * 'scaleFactor' is an extra uniform scale transform applied to downscale the 'src' image + * before any filtering, or as part of the copy, and is then drawn with 1/scaleFactor to 'dst'. + * Must be 1.0 if 'compat' is kYes (i.e. any scale factor has already been baked into the + * relative transforms between the devices). + */ + void internalDrawDeviceWithFilter(SkDevice* src, SkDevice* dst, + FilterSpan filters, const SkPaint& paint, + DeviceCompatibleWithFilter compat, + const SkColorInfo& filterColorInfo, + SkScalar scaleFactor = 1.f, + bool srcIsCoverageLayer = false); + + /* + * Returns true if drawing the specified rect (or all if it is null) with the specified + * paint (or default if null) would overwrite the entire root device of the canvas + * (i.e. the canvas' surface if it had one). + */ + bool wouldOverwriteEntireSurface(const SkRect*, const SkPaint*, + SkEnumBitMask) const; + + /** + * Returns true if the clip (for any active layer) contains antialiasing. + * If the clip is empty, this will return false. + */ + bool androidFramework_isClipAA() const; + + /** + * Reset the clip to be wide-open (modulo any separately specified device clip restriction). + * This operate within the save/restore clip stack so it can be undone by restoring to an + * earlier save point. + */ + void internal_private_resetClip(); + + virtual SkPaintFilterCanvas* internal_private_asPaintFilterCanvas() const { return nullptr; } + + // Keep track of the device clip bounds in the canvas' global space to reject draws before + // invoking the top-level device. + SkRect fQuickRejectBounds; + + // Compute the clip's bounds based on all clipped SkDevice's reported device bounds transformed + // into the canvas' global space. + SkRect computeDeviceClipBounds(bool outsetForAA=true) const; + + // Attempt to draw a rrect with an analytic blur. If the paint does not contain a blur, or the + // geometry can't be drawn with an analytic blur by the device, a layer is returned for a + // regular draw. If the draw succeeds or predrawNotify fails, nullopt is returned indicating + // that nothing further should be drawn. + std::optional attemptBlurredRRectDraw(const SkRRect&, + const SkPaint&, + SkEnumBitMask); + + class AutoUpdateQRBounds; + void validateClip() const; + + std::unique_ptr fScratchGlyphRunBuilder; +}; + +/** \class SkAutoCanvasRestore + Stack helper class calls SkCanvas::restoreToCount when SkAutoCanvasRestore + goes out of scope. Use this to guarantee that the canvas is restored to a known + state. +*/ +class SkAutoCanvasRestore { +public: + + /** Preserves SkCanvas::save() count. Optionally saves SkCanvas clip and SkCanvas matrix. + + @param canvas SkCanvas to guard + @param doSave call SkCanvas::save() + @return utility to restore SkCanvas state on destructor + */ + SkAutoCanvasRestore(SkCanvas* canvas, bool doSave) : fCanvas(canvas), fSaveCount(0) { + if (fCanvas) { + fSaveCount = canvas->getSaveCount(); + if (doSave) { + canvas->save(); + } + } + } + + /** Restores SkCanvas to saved state. Destructor is called when container goes out of + scope. + */ + ~SkAutoCanvasRestore() { + if (fCanvas) { + fCanvas->restoreToCount(fSaveCount); + } + } + + /** Restores SkCanvas to saved state immediately. Subsequent calls and + ~SkAutoCanvasRestore() have no effect. + */ + void restore() { + if (fCanvas) { + fCanvas->restoreToCount(fSaveCount); + fCanvas = nullptr; + } + } + +private: + SkCanvas* fCanvas; + int fSaveCount; + + SkAutoCanvasRestore(SkAutoCanvasRestore&&) = delete; + SkAutoCanvasRestore(const SkAutoCanvasRestore&) = delete; + SkAutoCanvasRestore& operator=(SkAutoCanvasRestore&&) = delete; + SkAutoCanvasRestore& operator=(const SkAutoCanvasRestore&) = delete; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkCanvasVirtualEnforcer.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkCanvasVirtualEnforcer.h new file mode 100644 index 0000000000..5086b4337d --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkCanvasVirtualEnforcer.h @@ -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, which will make the build fail if you forget +// to override one of SkCanvas' key virtual hooks. +template +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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkCapabilities.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkCapabilities.h new file mode 100644 index 0000000000..3053c57559 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkCapabilities.h @@ -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 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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkClipOp.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkClipOp.h new file mode 100644 index 0000000000..3da6c61131 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkClipOp.h @@ -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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkColor.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkColor.h new file mode 100644 index 0000000000..33352c7a83 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkColor.h @@ -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 +#include + +/** \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(SkColorChannel::kR), + kGreen_SkColorChannelFlag = 1 << static_cast(SkColorChannel::kG), + kBlue_SkColorChannelFlag = 1 << static_cast(SkColorChannel::kB), + kAlpha_SkColorChannelFlag = 1 << static_cast(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. For convenience, this type can also be referred to + as SkColor4f. +*/ +template +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 */ + std::array 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 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 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; + +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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkColorFilter.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkColorFilter.h new file mode 100644 index 0000000000..0898f0acad --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkColorFilter.h @@ -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 +#include +#include + +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 makeComposed(sk_sp 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 makeWithWorkingColorSpace(sk_sp) const; + + static sk_sp 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 Compose(const sk_sp& outer, + sk_sp 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 Blend(const SkColor4f& c, sk_sp, SkBlendMode mode); + static sk_sp Blend(SkColor c, SkBlendMode mode); + + static sk_sp Matrix(const SkColorMatrix&); + static sk_sp 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 HSLAMatrix(const SkColorMatrix&); + static sk_sp HSLAMatrix(const float rowMajor[20]); + + static sk_sp LinearToSRGBGamma(); + static sk_sp SRGBToLinearGamma(); + static sk_sp Lerp(float t, sk_sp dst, sk_sp 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 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 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 Table(sk_sp 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 Lighting(SkColor mul, SkColor add); + +private: + SkColorFilters() = delete; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkColorPriv.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkColorPriv.h new file mode 100644 index 0000000000..f89de9db72 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkColorPriv.h @@ -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 + +/** 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(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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkColorSpace.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkColorSpace.h new file mode 100644 index 0000000000..57c29e222a --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkColorSpace.h @@ -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 +#include + +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 { +public: + /** + * Create the sRGB color space. + */ + static sk_sp MakeSRGB(); + + /** + * Colorspace with the sRGB primaries, but a linear (1.0) gamma. + */ + static sk_sp MakeSRGBLinear(); + + /** + * Create an SkColorSpace from a transfer function and a row-major 3x3 transformation to XYZ. + */ + static sk_sp MakeRGB(const skcms_TransferFunction& transferFn, + const skcms_Matrix3x3& toXYZ); + + /** + * Create an SkColorSpace from a parsed (skcms) ICC profile. + */ + static sk_sp 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 makeLinearGamma() const; + + /** + * Returns a color space with the same gamut as this one, but with the sRGB transfer + * function. + */ + sk_sp 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 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 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 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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkColorTable.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkColorTable.h new file mode 100644 index 0000000000..dc16048a59 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkColorTable.h @@ -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 + +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 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 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 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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkColorType.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkColorType.h new file mode 100644 index 0000000000..2b2837a040 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkColorType.h @@ -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(kLastEnum_SkColorType) + 1; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkContourMeasure.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkContourMeasure.h new file mode 100644 index 0000000000..29e33d84f3 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkContourMeasure.h @@ -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 + +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 fSegments; + const SkTDArray fPts; // Points used to define the segments + + const SkScalar fLength; + const bool fIsClosed; + + SkContourMeasure(SkTDArray&& segs, SkTDArray&& 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 next(); + +private: + class Impl; + + std::unique_ptr fImpl; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkCoverageMode.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkCoverageMode.h new file mode 100644 index 0000000000..aaae60c419 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkCoverageMode.h @@ -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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkCubicMap.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkCubicMap.h new file mode 100644 index 0000000000..863c9333f6 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkCubicMap.h @@ -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 + diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkData.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkData.h new file mode 100644 index 0000000000..2b50cebc81 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkData.h @@ -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 +#include + +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 { +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(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(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 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 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 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 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 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 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 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 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 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 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 MakeFromStream(SkStream*, size_t size); + + /** + * Create a new dataref using a subset of the data in the specified + * src dataref. + */ + static sk_sp 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 MakeEmpty(); + +private: + friend class SkNVRefCnt; + 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 PrivateNewWithCopy(const void* srcOrNull, size_t length); + + static void NoopReleaseProc(const void*, void*); // {} + + using INHERITED = SkRefCnt; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkDataTable.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkDataTable.h new file mode 100644 index 0000000000..3aa48d5f33 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkDataTable.h @@ -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 +#include + +/** + * 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 + const T* atT(int index, size_t* size = nullptr) const { + return reinterpret_cast(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(index, &size); + SkASSERT(strlen(str) + 1 == size); + return str; + } + + typedef void (*FreeProc)(void* context); + + static sk_sp 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 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 MakeCopyArray(const void* array, size_t elemSize, int count); + + static sk_sp 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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkDocument.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkDocument.h new file mode 100644 index 0000000000..c5fe5e850d --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkDocument.h @@ -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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkDrawable.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkDrawable.h new file mode 100644 index 0000000000..764a825449 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkDrawable.h @@ -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 +#include +#include + +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 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 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 Deserialize(const void* data, size_t size, + const SkDeserialProcs* procs = nullptr) { + return sk_sp(static_cast( + 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 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 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 onMakePictureSnapshot(); + +private: + int32_t fGenerationID; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkExecutor.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkExecutor.h new file mode 100644 index 0000000000..88e2ca6e52 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkExecutor.h @@ -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 +#include +#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 MakeFIFOThreadPool(int threads = 0, + bool allowBorrowing = true); + static std::unique_ptr 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) = 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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkFlattenable.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkFlattenable.h new file mode 100644 index 0000000000..892a5933a2 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkFlattenable.h @@ -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 + +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 (*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 serialize(const SkSerialProcs* = nullptr) const; + size_t serialize(void* memory, size_t memory_size, + const SkSerialProcs* = nullptr) const; + static sk_sp 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 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 CreateProc(SkReadBuffer&); \ + friend class SkFlattenable::PrivateInitializer; \ + Factory getFactory() const override { return type::CreateProc; } \ + const char* getTypeName() const override { return #type; } +#endif + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkFont.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkFont.h new file mode 100644 index 0000000000..e0c3533fd6 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkFont.h @@ -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 +#include +#include +#include + +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 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 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 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 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 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 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 fTypeface; + SkScalar fSize; + SkScalar fScaleX; + SkScalar fSkewX; + uint8_t fFlags; + uint8_t fEdging; + uint8_t fHinting; + + static_assert(::sk_is_trivially_relocatable::value); + + SkScalar setupForAsPaths(SkPaint*); + bool hasSomeAntiAliasing() const; + + friend class SkFontPriv; + friend class SkGlyphRunListPainterCPU; + friend class SkStrikeSpec; + friend class SkRemoteGlyphCacheTest; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkFontArguments.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkFontArguments.h new file mode 100644 index 0000000000..5ab8d2e182 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkFontArguments.h @@ -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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkFontMetrics.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkFontMetrics.h new file mode 100644 index 0000000000..0686246ad1 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkFontMetrics.h @@ -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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkFontMgr.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkFontMgr.h new file mode 100644 index 0000000000..48f49f6845 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkFontMgr.h @@ -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 + +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 createTypeface(int index) = 0; + virtual sk_sp matchStyle(const SkFontStyle& pattern) = 0; + + static sk_sp CreateEmpty(); + +protected: + sk_sp matchStyleCSS3(const SkFontStyle& pattern); +}; + +class SK_API SkFontMgr : public SkRefCnt { +public: + int countFamilies() const; + void getFamilyName(int index, SkString* familyName) const; + sk_sp 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 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 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 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 makeFromData(sk_sp, 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 makeFromStream(std::unique_ptr, int ttcIndex = 0) const; + + /* Experimental, API subject to change. */ + sk_sp makeFromStream(std::unique_ptr, 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 makeFromFile(const char path[], int ttcIndex = 0) const; + + sk_sp legacyMakeTypeface(const char familyName[], SkFontStyle style) const; + + /* Returns an empty font manager without any typeface dependencies */ + static sk_sp RefEmpty(); + +protected: + virtual int onCountFamilies() const = 0; + virtual void onGetFamilyName(int index, SkString* familyName) const = 0; + virtual sk_sp onCreateStyleSet(int index)const = 0; + + /** May return NULL if the name is not found. */ + virtual sk_sp onMatchFamily(const char familyName[]) const = 0; + + virtual sk_sp onMatchFamilyStyle(const char familyName[], + const SkFontStyle&) const = 0; + virtual sk_sp onMatchFamilyStyleCharacter(const char familyName[], + const SkFontStyle&, + const char* bcp47[], int bcp47Count, + SkUnichar character) const = 0; + + virtual sk_sp onMakeFromData(sk_sp, int ttcIndex) const = 0; + virtual sk_sp onMakeFromStreamIndex(std::unique_ptr, + int ttcIndex) const = 0; + virtual sk_sp onMakeFromStreamArgs(std::unique_ptr, + const SkFontArguments&) const = 0; + virtual sk_sp onMakeFromFile(const char path[], int ttcIndex) const = 0; + + virtual sk_sp onLegacyMakeTypeface(const char familyName[], SkFontStyle) const = 0; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkFontParameters.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkFontParameters.h new file mode 100644 index 0000000000..ae4f1d68b6 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkFontParameters.h @@ -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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkFontStyle.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkFontStyle.h new file mode 100644 index 0000000000..be46b53bb2 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkFontStyle.h @@ -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 + +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(weight, kInvisible_Weight, kExtraBlack_Weight)) + + (SkTPin(width, kUltraCondensed_Width, kUltraExpanded_Width) << 16) + + (SkTPin(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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkFontTypes.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkFontTypes.h new file mode 100644 index 0000000000..76f5dde67f --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkFontTypes.h @@ -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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkGraphics.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkGraphics.h new file mode 100644 index 0000000000..58fd16b734 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkGraphics.h @@ -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 +#include +#include + +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 + (*ImageGeneratorFromEncodedDataFactory)(sk_sp); + + /** + * 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 (*)(const uint8_t* svg, size_t length); + static OpenTypeSVGDecoderFactory SetOpenTypeSVGDecoderFactory(OpenTypeSVGDecoderFactory); + static OpenTypeSVGDecoderFactory GetOpenTypeSVGDecoderFactory(); +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkImage.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkImage.h new file mode 100644 index 0000000000..600f167971 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkImage.h @@ -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 +#include +#include +#include + +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 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 RasterFromCompressedTextureData(sk_sp 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 DeferredFromEncodedData(sk_sp encoded, + std::optional 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 DeferredFromGenerator(std::unique_ptr 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 DeferredFromPicture(sk_sp picture, + const SkISize& dimensions, + const SkMatrix* matrix, + const SkPaint* paint, + BitDepth bitDepth, + sk_sp colorSpace, + SkSurfaceProps props); +SK_API sk_sp DeferredFromPicture(sk_sp picture, + const SkISize& dimensions, + const SkMatrix* matrix, + const SkPaint* paint, + BitDepth bitDepth, + sk_sp 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 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 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 RasterFromData(const SkImageInfo& info, + sk_sp 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 MakeWithFilter(sk_sp 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 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 makeShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions&, + const SkMatrix* localMatrix = nullptr) const; + sk_sp makeShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions& sampling, + const SkMatrix& lm) const; + /** Defaults to clamp in both X and Y. */ + sk_sp makeShader(const SkSamplingOptions& sampling, const SkMatrix& lm) const; + sk_sp 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 makeRawShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions&, + const SkMatrix* localMatrix = nullptr) const; + sk_sp makeRawShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions& sampling, + const SkMatrix& lm) const; + /** Defaults to clamp in both X and Y. */ + sk_sp makeRawShader(const SkSamplingOptions& sampling, const SkMatrix& lm) const; + sk_sp 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); + + 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 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 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 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 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 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 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 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 makeRasterImage(GrDirectContext*, + CachingHint cachingHint = kDisallow_CachingHint) const; + +#if !defined(SK_IMAGE_READ_PIXELS_DISABLE_LEGACY_API) + sk_sp 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 makeColorSpace(GrDirectContext* direct, + sk_sp 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 makeColorSpace(skgpu::graphite::Recorder*, + sk_sp 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 makeColorTypeAndColorSpace(GrDirectContext* direct, + SkColorType targetColorType, + sk_sp 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 makeColorTypeAndColorSpace(skgpu::graphite::Recorder*, + SkColorType targetColorType, + sk_sp 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 reinterpretColorSpace(sk_sp 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 withMipmaps(sk_sp) const; + + using INHERITED = SkRefCnt; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkImageFilter.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkImageFilter.h new file mode 100644 index 0000000000..7352cf71f7 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkImageFilter.h @@ -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 + +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 makeWithLocalMatrix(const SkMatrix& matrix) const; + + static sk_sp Deserialize(const void* data, size_t size, + const SkDeserialProcs* procs = nullptr) { + return sk_sp(static_cast( + SkFlattenable::Deserialize(kSkImageFilter_Type, data, size, procs).release())); + } + +protected: + + sk_sp refMe() const { + return sk_ref_sp(const_cast(this)); + } + +private: + friend class SkImageFilter_Base; + + using INHERITED = SkFlattenable; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkImageGenerator.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkImageGenerator.h new file mode 100644 index 0000000000..4210cdb601 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkImageGenerator.h @@ -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 +#include + +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 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 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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkImageInfo.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkImageInfo.h new file mode 100644 index 0000000000..4d08e429fc --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkImageInfo.h @@ -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 +#include +#include + +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 cs); + + SkColorInfo(const SkColorInfo&); + SkColorInfo(SkColorInfo&&); + + SkColorInfo& operator=(const SkColorInfo&); + SkColorInfo& operator=(SkColorInfo&&); + + SkColorSpace* colorSpace() const; + sk_sp 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 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 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 cs); + static SkImageInfo Make(SkISize dimensions, SkColorType ct, SkAlphaType at); + static SkImageInfo Make(SkISize dimensions, SkColorType ct, SkAlphaType at, + sk_sp 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 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 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 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 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 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(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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkM44.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkM44.h new file mode 100644 index 0000000000..d8c77ea07a --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkM44.h @@ -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 + +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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkMallocPixelRef.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkMallocPixelRef.h new file mode 100644 index 0000000000..5f37348583 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkMallocPixelRef.h @@ -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 + +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 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 MakeWithData(const SkImageInfo&, size_t rowBytes, sk_sp data); +} // namespace SkMallocPixelRef +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkMaskFilter.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkMaskFilter.h new file mode 100644 index 0000000000..9d03e98c0c --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkMaskFilter.h @@ -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 + +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 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 Deserialize(const void* data, size_t size, + const SkDeserialProcs* procs = nullptr); + +private: + static void RegisterFlattenables(); + friend class SkFlattenable; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkMatrix.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkMatrix.h new file mode 100644 index 0000000000..10ee699db1 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkMatrix.h @@ -0,0 +1,1997 @@ +/* + * 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 SkMatrix_DEFINED +#define SkMatrix_DEFINED + +#include "include/core/SkPoint.h" +#include "include/core/SkRect.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkFloatingPoint.h" +#include "include/private/base/SkMacros.h" +#include "include/private/base/SkTo.h" + +#include +#include + +struct SkPoint3; +struct SkRSXform; +struct SkSize; + +// Remove when clients are updated to live without this +#define SK_SUPPORT_LEGACY_MATRIX_RECTTORECT + +/** + * When we transform points through a matrix containing perspective (the bottom row is something + * other than 0,0,1), the bruteforce math can produce confusing results (since we might divide + * by 0, or a negative w value). By default, methods that map rects and paths will apply + * perspective clipping, but this can be changed by specifying kYes to those methods. + */ +enum class SkApplyPerspectiveClip { + kNo, //!< Don't pre-clip the geometry before applying the (perspective) matrix + kYes, //!< Do pre-clip the geometry before applying the (perspective) matrix +}; + +/** \class SkMatrix + SkMatrix holds a 3x3 matrix for transforming coordinates. This allows mapping + SkPoint and vectors with translation, scaling, skewing, rotation, and + perspective. + + SkMatrix elements are in row major order. + SkMatrix constexpr default constructs to identity. + + SkMatrix includes a hidden variable that classifies the type of matrix to + improve performance. SkMatrix is not thread safe unless getType() is called first. + + example: https://fiddle.skia.org/c/@Matrix_063 +*/ +SK_BEGIN_REQUIRE_DENSE +class SK_API SkMatrix { +public: + + /** Creates an identity SkMatrix: + + | 1 0 0 | + | 0 1 0 | + | 0 0 1 | + */ + constexpr SkMatrix() : SkMatrix(1,0,0, 0,1,0, 0,0,1, kIdentity_Mask | kRectStaysRect_Mask) {} + + /** Sets SkMatrix to scale by (sx, sy). Returned matrix is: + + | sx 0 0 | + | 0 sy 0 | + | 0 0 1 | + + @param sx horizontal scale factor + @param sy vertical scale factor + @return SkMatrix with scale + */ + [[nodiscard]] static SkMatrix Scale(SkScalar sx, SkScalar sy) { + SkMatrix m; + m.setScale(sx, sy); + return m; + } + + /** Sets SkMatrix to translate by (dx, dy). Returned matrix is: + + | 1 0 dx | + | 0 1 dy | + | 0 0 1 | + + @param dx horizontal translation + @param dy vertical translation + @return SkMatrix with translation + */ + [[nodiscard]] static SkMatrix Translate(SkScalar dx, SkScalar dy) { + SkMatrix m; + m.setTranslate(dx, dy); + return m; + } + [[nodiscard]] static SkMatrix Translate(SkVector t) { return Translate(t.x(), t.y()); } + [[nodiscard]] static SkMatrix Translate(SkIVector t) { return Translate(t.x(), t.y()); } + + /** Sets SkMatrix to rotate by |deg| about a pivot point at (0, 0). + + @param deg rotation angle in degrees (positive rotates clockwise) + @return SkMatrix with rotation + */ + [[nodiscard]] static SkMatrix RotateDeg(SkScalar deg) { + SkMatrix m; + m.setRotate(deg); + return m; + } + [[nodiscard]] static SkMatrix RotateDeg(SkScalar deg, SkPoint pt) { + SkMatrix m; + m.setRotate(deg, pt.x(), pt.y()); + return m; + } + [[nodiscard]] static SkMatrix RotateRad(SkScalar rad) { + return RotateDeg(SkRadiansToDegrees(rad)); + } + + /** Sets SkMatrix to skew by (kx, ky) about pivot point (0, 0). + + @param kx horizontal skew factor + @param ky vertical skew factor + @return SkMatrix with skew + */ + [[nodiscard]] static SkMatrix Skew(SkScalar kx, SkScalar ky) { + SkMatrix m; + m.setSkew(kx, ky); + return m; + } + + /** \enum SkMatrix::ScaleToFit + ScaleToFit describes how SkMatrix is constructed to map one SkRect to another. + ScaleToFit may allow SkMatrix to have unequal horizontal and vertical scaling, + or may restrict SkMatrix to square scaling. If restricted, ScaleToFit specifies + how SkMatrix maps to the side or center of the destination SkRect. + */ + enum ScaleToFit { + kFill_ScaleToFit, //!< scales in x and y to fill destination SkRect + kStart_ScaleToFit, //!< scales and aligns to left and top + kCenter_ScaleToFit, //!< scales and aligns to center + kEnd_ScaleToFit, //!< scales and aligns to right and bottom + }; + + /** Returns SkMatrix set to scale and translate src to dst. ScaleToFit selects + whether mapping completely fills dst or preserves the aspect ratio, and how to + align src within dst. Returns the identity SkMatrix if src is empty. If dst is + empty, returns SkMatrix set to: + + | 0 0 0 | + | 0 0 0 | + | 0 0 1 | + + @param src SkRect to map from + @param dst SkRect to map to + @param mode How to handle the mapping + @return SkMatrix mapping src to dst + */ + [[nodiscard]] static SkMatrix RectToRect(const SkRect& src, const SkRect& dst, + ScaleToFit mode = kFill_ScaleToFit) { + return MakeRectToRect(src, dst, mode); + } + + /** Sets SkMatrix to: + + | scaleX skewX transX | + | skewY scaleY transY | + | pers0 pers1 pers2 | + + @param scaleX horizontal scale factor + @param skewX horizontal skew factor + @param transX horizontal translation + @param skewY vertical skew factor + @param scaleY vertical scale factor + @param transY vertical translation + @param pers0 input x-axis perspective factor + @param pers1 input y-axis perspective factor + @param pers2 perspective scale factor + @return SkMatrix constructed from parameters + */ + [[nodiscard]] static SkMatrix MakeAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, + SkScalar skewY, SkScalar scaleY, SkScalar transY, + SkScalar pers0, SkScalar pers1, SkScalar pers2) { + SkMatrix m; + m.setAll(scaleX, skewX, transX, skewY, scaleY, transY, pers0, pers1, pers2); + return m; + } + + /** \enum SkMatrix::TypeMask + Enum of bit fields for mask returned by getType(). + Used to identify the complexity of SkMatrix, to optimize performance. + */ + enum TypeMask { + kIdentity_Mask = 0, //!< identity SkMatrix; all bits clear + kTranslate_Mask = 0x01, //!< translation SkMatrix + kScale_Mask = 0x02, //!< scale SkMatrix + kAffine_Mask = 0x04, //!< skew or rotate SkMatrix + kPerspective_Mask = 0x08, //!< perspective SkMatrix + }; + + /** Returns a bit field describing the transformations the matrix may + perform. The bit field is computed conservatively, so it may include + false positives. For example, when kPerspective_Mask is set, all + other bits are set. + + @return kIdentity_Mask, or combinations of: kTranslate_Mask, kScale_Mask, + kAffine_Mask, kPerspective_Mask + */ + TypeMask getType() const { + if (fTypeMask & kUnknown_Mask) { + fTypeMask = this->computeTypeMask(); + } + // only return the public masks + return (TypeMask)(fTypeMask & 0xF); + } + + /** Returns true if SkMatrix is identity. Identity matrix is: + + | 1 0 0 | + | 0 1 0 | + | 0 0 1 | + + @return true if SkMatrix has no effect + */ + bool isIdentity() const { + return this->getType() == 0; + } + + /** Returns true if SkMatrix at most scales and translates. SkMatrix may be identity, + contain only scale elements, only translate elements, or both. SkMatrix form is: + + | scale-x 0 translate-x | + | 0 scale-y translate-y | + | 0 0 1 | + + @return true if SkMatrix is identity; or scales, translates, or both + */ + bool isScaleTranslate() const { + return !(this->getType() & ~(kScale_Mask | kTranslate_Mask)); + } + + /** Returns true if SkMatrix is identity, or translates. SkMatrix form is: + + | 1 0 translate-x | + | 0 1 translate-y | + | 0 0 1 | + + @return true if SkMatrix is identity, or translates + */ + bool isTranslate() const { return !(this->getType() & ~(kTranslate_Mask)); } + + /** Returns true SkMatrix maps SkRect to another SkRect. If true, SkMatrix is identity, + or scales, or rotates a multiple of 90 degrees, or mirrors on axes. In all + cases, SkMatrix may also have translation. SkMatrix form is either: + + | scale-x 0 translate-x | + | 0 scale-y translate-y | + | 0 0 1 | + + or + + | 0 rotate-x translate-x | + | rotate-y 0 translate-y | + | 0 0 1 | + + for non-zero values of scale-x, scale-y, rotate-x, and rotate-y. + + Also called preservesAxisAlignment(); use the one that provides better inline + documentation. + + @return true if SkMatrix maps one SkRect into another + */ + bool rectStaysRect() const { + if (fTypeMask & kUnknown_Mask) { + fTypeMask = this->computeTypeMask(); + } + return (fTypeMask & kRectStaysRect_Mask) != 0; + } + + /** Returns true SkMatrix maps SkRect to another SkRect. If true, SkMatrix is identity, + or scales, or rotates a multiple of 90 degrees, or mirrors on axes. In all + cases, SkMatrix may also have translation. SkMatrix form is either: + + | scale-x 0 translate-x | + | 0 scale-y translate-y | + | 0 0 1 | + + or + + | 0 rotate-x translate-x | + | rotate-y 0 translate-y | + | 0 0 1 | + + for non-zero values of scale-x, scale-y, rotate-x, and rotate-y. + + Also called rectStaysRect(); use the one that provides better inline + documentation. + + @return true if SkMatrix maps one SkRect into another + */ + bool preservesAxisAlignment() const { return this->rectStaysRect(); } + + /** Returns true if the matrix contains perspective elements. SkMatrix form is: + + | -- -- -- | + | -- -- -- | + | perspective-x perspective-y perspective-scale | + + where perspective-x or perspective-y is non-zero, or perspective-scale is + not one. All other elements may have any value. + + @return true if SkMatrix is in most general form + */ + bool hasPerspective() const { + return SkToBool(this->getPerspectiveTypeMaskOnly() & + kPerspective_Mask); + } + + /** Returns true if SkMatrix contains only translation, rotation, reflection, and + uniform scale. + Returns false if SkMatrix contains different scales, skewing, perspective, or + degenerate forms that collapse to a line or point. + + Describes that the SkMatrix makes rendering with and without the matrix are + visually alike; a transformed circle remains a circle. Mathematically, this is + referred to as similarity of a Euclidean space, or a similarity transformation. + + Preserves right angles, keeping the arms of the angle equal lengths. + + @param tol to be deprecated + @return true if SkMatrix only rotates, uniformly scales, translates + + example: https://fiddle.skia.org/c/@Matrix_isSimilarity + */ + bool isSimilarity(SkScalar tol = SK_ScalarNearlyZero) const; + + /** Returns true if SkMatrix contains only translation, rotation, reflection, and + scale. Scale may differ along rotated axes. + Returns false if SkMatrix skewing, perspective, or degenerate forms that collapse + to a line or point. + + Preserves right angles, but not requiring that the arms of the angle + retain equal lengths. + + @param tol to be deprecated + @return true if SkMatrix only rotates, scales, translates + + example: https://fiddle.skia.org/c/@Matrix_preservesRightAngles + */ + bool preservesRightAngles(SkScalar tol = SK_ScalarNearlyZero) const; + + /** SkMatrix organizes its values in row-major order. These members correspond to + each value in SkMatrix. + */ + static constexpr int kMScaleX = 0; //!< horizontal scale factor + static constexpr int kMSkewX = 1; //!< horizontal skew factor + static constexpr int kMTransX = 2; //!< horizontal translation + static constexpr int kMSkewY = 3; //!< vertical skew factor + static constexpr int kMScaleY = 4; //!< vertical scale factor + static constexpr int kMTransY = 5; //!< vertical translation + static constexpr int kMPersp0 = 6; //!< input x perspective factor + static constexpr int kMPersp1 = 7; //!< input y perspective factor + static constexpr int kMPersp2 = 8; //!< perspective bias + + /** Affine arrays are in column-major order to match the matrix used by + PDF and XPS. + */ + static constexpr int kAScaleX = 0; //!< horizontal scale factor + static constexpr int kASkewY = 1; //!< vertical skew factor + static constexpr int kASkewX = 2; //!< horizontal skew factor + static constexpr int kAScaleY = 3; //!< vertical scale factor + static constexpr int kATransX = 4; //!< horizontal translation + static constexpr int kATransY = 5; //!< vertical translation + + /** Returns one matrix value. Asserts if index is out of range and SK_DEBUG is + defined. + + @param index one of: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY, + kMPersp0, kMPersp1, kMPersp2 + @return value corresponding to index + */ + SkScalar operator[](int index) const { + SkASSERT((unsigned)index < 9); + return fMat[index]; + } + + /** Returns one matrix value. Asserts if index is out of range and SK_DEBUG is + defined. + + @param index one of: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY, + kMPersp0, kMPersp1, kMPersp2 + @return value corresponding to index + */ + SkScalar get(int index) const { + SkASSERT((unsigned)index < 9); + return fMat[index]; + } + + /** Returns one matrix value from a particular row/column. Asserts if index is out + of range and SK_DEBUG is defined. + + @param r matrix row to fetch + @param c matrix column to fetch + @return value at the given matrix position + */ + SkScalar rc(int r, int c) const { + SkASSERT(r >= 0 && r <= 2); + SkASSERT(c >= 0 && c <= 2); + return fMat[r*3 + c]; + } + + /** Returns scale factor multiplied by x-axis input, contributing to x-axis output. + With mapPoints(), scales SkPoint along the x-axis. + + @return horizontal scale factor + */ + SkScalar getScaleX() const { return fMat[kMScaleX]; } + + /** Returns scale factor multiplied by y-axis input, contributing to y-axis output. + With mapPoints(), scales SkPoint along the y-axis. + + @return vertical scale factor + */ + SkScalar getScaleY() const { return fMat[kMScaleY]; } + + /** Returns scale factor multiplied by x-axis input, contributing to y-axis output. + With mapPoints(), skews SkPoint along the y-axis. + Skewing both axes can rotate SkPoint. + + @return vertical skew factor + */ + SkScalar getSkewY() const { return fMat[kMSkewY]; } + + /** Returns scale factor multiplied by y-axis input, contributing to x-axis output. + With mapPoints(), skews SkPoint along the x-axis. + Skewing both axes can rotate SkPoint. + + @return horizontal scale factor + */ + SkScalar getSkewX() const { return fMat[kMSkewX]; } + + /** Returns translation contributing to x-axis output. + With mapPoints(), moves SkPoint along the x-axis. + + @return horizontal translation factor + */ + SkScalar getTranslateX() const { return fMat[kMTransX]; } + + /** Returns translation contributing to y-axis output. + With mapPoints(), moves SkPoint along the y-axis. + + @return vertical translation factor + */ + SkScalar getTranslateY() const { return fMat[kMTransY]; } + + /** Returns factor scaling input x-axis relative to input y-axis. + + @return input x-axis perspective factor + */ + SkScalar getPerspX() const { return fMat[kMPersp0]; } + + /** Returns factor scaling input y-axis relative to input x-axis. + + @return input y-axis perspective factor + */ + SkScalar getPerspY() const { return fMat[kMPersp1]; } + + /** Returns writable SkMatrix value. Asserts if index is out of range and SK_DEBUG is + defined. Clears internal cache anticipating that caller will change SkMatrix value. + + Next call to read SkMatrix state may recompute cache; subsequent writes to SkMatrix + value must be followed by dirtyMatrixTypeCache(). + + @param index one of: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY, + kMPersp0, kMPersp1, kMPersp2 + @return writable value corresponding to index + */ + SkScalar& operator[](int index) { + SkASSERT((unsigned)index < 9); + this->setTypeMask(kUnknown_Mask); + return fMat[index]; + } + + /** Sets SkMatrix value. Asserts if index is out of range and SK_DEBUG is + defined. Safer than operator[]; internal cache is always maintained. + + @param index one of: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY, + kMPersp0, kMPersp1, kMPersp2 + @param value scalar to store in SkMatrix + */ + SkMatrix& set(int index, SkScalar value) { + SkASSERT((unsigned)index < 9); + fMat[index] = value; + this->setTypeMask(kUnknown_Mask); + return *this; + } + + /** Sets horizontal scale factor. + + @param v horizontal scale factor to store + */ + SkMatrix& setScaleX(SkScalar v) { return this->set(kMScaleX, v); } + + /** Sets vertical scale factor. + + @param v vertical scale factor to store + */ + SkMatrix& setScaleY(SkScalar v) { return this->set(kMScaleY, v); } + + /** Sets vertical skew factor. + + @param v vertical skew factor to store + */ + SkMatrix& setSkewY(SkScalar v) { return this->set(kMSkewY, v); } + + /** Sets horizontal skew factor. + + @param v horizontal skew factor to store + */ + SkMatrix& setSkewX(SkScalar v) { return this->set(kMSkewX, v); } + + /** Sets horizontal translation. + + @param v horizontal translation to store + */ + SkMatrix& setTranslateX(SkScalar v) { return this->set(kMTransX, v); } + + /** Sets vertical translation. + + @param v vertical translation to store + */ + SkMatrix& setTranslateY(SkScalar v) { return this->set(kMTransY, v); } + + /** Sets input x-axis perspective factor, which causes mapXY() to vary input x-axis values + inversely proportional to input y-axis values. + + @param v perspective factor + */ + SkMatrix& setPerspX(SkScalar v) { return this->set(kMPersp0, v); } + + /** Sets input y-axis perspective factor, which causes mapXY() to vary input y-axis values + inversely proportional to input x-axis values. + + @param v perspective factor + */ + SkMatrix& setPerspY(SkScalar v) { return this->set(kMPersp1, v); } + + /** Sets all values from parameters. Sets matrix to: + + | scaleX skewX transX | + | skewY scaleY transY | + | persp0 persp1 persp2 | + + @param scaleX horizontal scale factor to store + @param skewX horizontal skew factor to store + @param transX horizontal translation to store + @param skewY vertical skew factor to store + @param scaleY vertical scale factor to store + @param transY vertical translation to store + @param persp0 input x-axis values perspective factor to store + @param persp1 input y-axis values perspective factor to store + @param persp2 perspective scale factor to store + */ + SkMatrix& setAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, + SkScalar skewY, SkScalar scaleY, SkScalar transY, + SkScalar persp0, SkScalar persp1, SkScalar persp2) { + fMat[kMScaleX] = scaleX; + fMat[kMSkewX] = skewX; + fMat[kMTransX] = transX; + fMat[kMSkewY] = skewY; + fMat[kMScaleY] = scaleY; + fMat[kMTransY] = transY; + fMat[kMPersp0] = persp0; + fMat[kMPersp1] = persp1; + fMat[kMPersp2] = persp2; + this->setTypeMask(kUnknown_Mask); + return *this; + } + + /** Copies nine scalar values contained by SkMatrix into buffer, in member value + ascending order: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY, + kMPersp0, kMPersp1, kMPersp2. + + @param buffer storage for nine scalar values + */ + void get9(SkScalar buffer[9]) const { + memcpy(buffer, fMat, 9 * sizeof(SkScalar)); + } + + /** Sets SkMatrix to nine scalar values in buffer, in member value ascending order: + kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY, kMPersp0, kMPersp1, + kMPersp2. + + Sets matrix to: + + | buffer[0] buffer[1] buffer[2] | + | buffer[3] buffer[4] buffer[5] | + | buffer[6] buffer[7] buffer[8] | + + In the future, set9 followed by get9 may not return the same values. Since SkMatrix + maps non-homogeneous coordinates, scaling all nine values produces an equivalent + transformation, possibly improving precision. + + @param buffer nine scalar values + */ + SkMatrix& set9(const SkScalar buffer[9]); + + /** Sets SkMatrix to identity; which has no effect on mapped SkPoint. Sets SkMatrix to: + + | 1 0 0 | + | 0 1 0 | + | 0 0 1 | + + Also called setIdentity(); use the one that provides better inline + documentation. + */ + SkMatrix& reset(); + + /** Sets SkMatrix to identity; which has no effect on mapped SkPoint. Sets SkMatrix to: + + | 1 0 0 | + | 0 1 0 | + | 0 0 1 | + + Also called reset(); use the one that provides better inline + documentation. + */ + SkMatrix& setIdentity() { return this->reset(); } + + /** Sets SkMatrix to translate by (dx, dy). + + @param dx horizontal translation + @param dy vertical translation + */ + SkMatrix& setTranslate(SkScalar dx, SkScalar dy); + + /** Sets SkMatrix to translate by (v.fX, v.fY). + + @param v vector containing horizontal and vertical translation + */ + SkMatrix& setTranslate(const SkVector& v) { return this->setTranslate(v.fX, v.fY); } + + /** Sets SkMatrix to scale by sx and sy, about a pivot point at (px, py). + The pivot point is unchanged when mapped with SkMatrix. + + @param sx horizontal scale factor + @param sy vertical scale factor + @param px pivot on x-axis + @param py pivot on y-axis + */ + SkMatrix& setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py); + + /** Sets SkMatrix to scale by sx and sy about at pivot point at (0, 0). + + @param sx horizontal scale factor + @param sy vertical scale factor + */ + SkMatrix& setScale(SkScalar sx, SkScalar sy); + + /** Sets SkMatrix to rotate by degrees about a pivot point at (px, py). + The pivot point is unchanged when mapped with SkMatrix. + + Positive degrees rotates clockwise. + + @param degrees angle of axes relative to upright axes + @param px pivot on x-axis + @param py pivot on y-axis + */ + SkMatrix& setRotate(SkScalar degrees, SkScalar px, SkScalar py); + + /** Sets SkMatrix to rotate by degrees about a pivot point at (0, 0). + Positive degrees rotates clockwise. + + @param degrees angle of axes relative to upright axes + */ + SkMatrix& setRotate(SkScalar degrees); + + /** Sets SkMatrix to rotate by sinValue and cosValue, about a pivot point at (px, py). + The pivot point is unchanged when mapped with SkMatrix. + + Vector (sinValue, cosValue) describes the angle of rotation relative to (0, 1). + Vector length specifies scale. + + @param sinValue rotation vector x-axis component + @param cosValue rotation vector y-axis component + @param px pivot on x-axis + @param py pivot on y-axis + */ + SkMatrix& setSinCos(SkScalar sinValue, SkScalar cosValue, + SkScalar px, SkScalar py); + + /** Sets SkMatrix to rotate by sinValue and cosValue, about a pivot point at (0, 0). + + Vector (sinValue, cosValue) describes the angle of rotation relative to (0, 1). + Vector length specifies scale. + + @param sinValue rotation vector x-axis component + @param cosValue rotation vector y-axis component + */ + SkMatrix& setSinCos(SkScalar sinValue, SkScalar cosValue); + + /** Sets SkMatrix to rotate, scale, and translate using a compressed matrix form. + + Vector (rsxForm.fSSin, rsxForm.fSCos) describes the angle of rotation relative + to (0, 1). Vector length specifies scale. Mapped point is rotated and scaled + by vector, then translated by (rsxForm.fTx, rsxForm.fTy). + + @param rsxForm compressed SkRSXform matrix + @return reference to SkMatrix + + example: https://fiddle.skia.org/c/@Matrix_setRSXform + */ + SkMatrix& setRSXform(const SkRSXform& rsxForm); + + /** Sets SkMatrix to skew by kx and ky, about a pivot point at (px, py). + The pivot point is unchanged when mapped with SkMatrix. + + @param kx horizontal skew factor + @param ky vertical skew factor + @param px pivot on x-axis + @param py pivot on y-axis + */ + SkMatrix& setSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py); + + /** Sets SkMatrix to skew by kx and ky, about a pivot point at (0, 0). + + @param kx horizontal skew factor + @param ky vertical skew factor + */ + SkMatrix& setSkew(SkScalar kx, SkScalar ky); + + /** Sets SkMatrix to SkMatrix a multiplied by SkMatrix b. Either a or b may be this. + + Given: + + | A B C | | J K L | + a = | D E F |, b = | M N O | + | G H I | | P Q R | + + sets SkMatrix to: + + | A B C | | J K L | | AJ+BM+CP AK+BN+CQ AL+BO+CR | + a * b = | D E F | * | M N O | = | DJ+EM+FP DK+EN+FQ DL+EO+FR | + | G H I | | P Q R | | GJ+HM+IP GK+HN+IQ GL+HO+IR | + + @param a SkMatrix on left side of multiply expression + @param b SkMatrix on right side of multiply expression + */ + SkMatrix& setConcat(const SkMatrix& a, const SkMatrix& b); + + /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from translation (dx, dy). + This can be thought of as moving the point to be mapped before applying SkMatrix. + + Given: + + | A B C | | 1 0 dx | + Matrix = | D E F |, T(dx, dy) = | 0 1 dy | + | G H I | | 0 0 1 | + + sets SkMatrix to: + + | A B C | | 1 0 dx | | A B A*dx+B*dy+C | + Matrix * T(dx, dy) = | D E F | | 0 1 dy | = | D E D*dx+E*dy+F | + | G H I | | 0 0 1 | | G H G*dx+H*dy+I | + + @param dx x-axis translation before applying SkMatrix + @param dy y-axis translation before applying SkMatrix + */ + SkMatrix& preTranslate(SkScalar dx, SkScalar dy); + + /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from scaling by (sx, sy) + about pivot point (px, py). + This can be thought of as scaling about a pivot point before applying SkMatrix. + + Given: + + | A B C | | sx 0 dx | + Matrix = | D E F |, S(sx, sy, px, py) = | 0 sy dy | + | G H I | | 0 0 1 | + + where + + dx = px - sx * px + dy = py - sy * py + + sets SkMatrix to: + + | A B C | | sx 0 dx | | A*sx B*sy A*dx+B*dy+C | + Matrix * S(sx, sy, px, py) = | D E F | | 0 sy dy | = | D*sx E*sy D*dx+E*dy+F | + | G H I | | 0 0 1 | | G*sx H*sy G*dx+H*dy+I | + + @param sx horizontal scale factor + @param sy vertical scale factor + @param px pivot on x-axis + @param py pivot on y-axis + */ + SkMatrix& preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py); + + /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from scaling by (sx, sy) + about pivot point (0, 0). + This can be thought of as scaling about the origin before applying SkMatrix. + + Given: + + | A B C | | sx 0 0 | + Matrix = | D E F |, S(sx, sy) = | 0 sy 0 | + | G H I | | 0 0 1 | + + sets SkMatrix to: + + | A B C | | sx 0 0 | | A*sx B*sy C | + Matrix * S(sx, sy) = | D E F | | 0 sy 0 | = | D*sx E*sy F | + | G H I | | 0 0 1 | | G*sx H*sy I | + + @param sx horizontal scale factor + @param sy vertical scale factor + */ + SkMatrix& preScale(SkScalar sx, SkScalar sy); + + /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from rotating by degrees + about pivot point (px, py). + This can be thought of as rotating about a pivot point before applying SkMatrix. + + Positive degrees rotates clockwise. + + Given: + + | A B C | | c -s dx | + Matrix = | D E F |, R(degrees, px, py) = | s c dy | + | G H I | | 0 0 1 | + + where + + c = cos(degrees) + s = sin(degrees) + dx = s * py + (1 - c) * px + dy = -s * px + (1 - c) * py + + sets SkMatrix to: + + | A B C | | c -s dx | | Ac+Bs -As+Bc A*dx+B*dy+C | + Matrix * R(degrees, px, py) = | D E F | | s c dy | = | Dc+Es -Ds+Ec D*dx+E*dy+F | + | G H I | | 0 0 1 | | Gc+Hs -Gs+Hc G*dx+H*dy+I | + + @param degrees angle of axes relative to upright axes + @param px pivot on x-axis + @param py pivot on y-axis + */ + SkMatrix& preRotate(SkScalar degrees, SkScalar px, SkScalar py); + + /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from rotating by degrees + about pivot point (0, 0). + This can be thought of as rotating about the origin before applying SkMatrix. + + Positive degrees rotates clockwise. + + Given: + + | A B C | | c -s 0 | + Matrix = | D E F |, R(degrees, px, py) = | s c 0 | + | G H I | | 0 0 1 | + + where + + c = cos(degrees) + s = sin(degrees) + + sets SkMatrix to: + + | A B C | | c -s 0 | | Ac+Bs -As+Bc C | + Matrix * R(degrees, px, py) = | D E F | | s c 0 | = | Dc+Es -Ds+Ec F | + | G H I | | 0 0 1 | | Gc+Hs -Gs+Hc I | + + @param degrees angle of axes relative to upright axes + */ + SkMatrix& preRotate(SkScalar degrees); + + /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from skewing by (kx, ky) + about pivot point (px, py). + This can be thought of as skewing about a pivot point before applying SkMatrix. + + Given: + + | A B C | | 1 kx dx | + Matrix = | D E F |, K(kx, ky, px, py) = | ky 1 dy | + | G H I | | 0 0 1 | + + where + + dx = -kx * py + dy = -ky * px + + sets SkMatrix to: + + | A B C | | 1 kx dx | | A+B*ky A*kx+B A*dx+B*dy+C | + Matrix * K(kx, ky, px, py) = | D E F | | ky 1 dy | = | D+E*ky D*kx+E D*dx+E*dy+F | + | G H I | | 0 0 1 | | G+H*ky G*kx+H G*dx+H*dy+I | + + @param kx horizontal skew factor + @param ky vertical skew factor + @param px pivot on x-axis + @param py pivot on y-axis + */ + SkMatrix& preSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py); + + /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from skewing by (kx, ky) + about pivot point (0, 0). + This can be thought of as skewing about the origin before applying SkMatrix. + + Given: + + | A B C | | 1 kx 0 | + Matrix = | D E F |, K(kx, ky) = | ky 1 0 | + | G H I | | 0 0 1 | + + sets SkMatrix to: + + | A B C | | 1 kx 0 | | A+B*ky A*kx+B C | + Matrix * K(kx, ky) = | D E F | | ky 1 0 | = | D+E*ky D*kx+E F | + | G H I | | 0 0 1 | | G+H*ky G*kx+H I | + + @param kx horizontal skew factor + @param ky vertical skew factor + */ + SkMatrix& preSkew(SkScalar kx, SkScalar ky); + + /** Sets SkMatrix to SkMatrix multiplied by SkMatrix other. + This can be thought of mapping by other before applying SkMatrix. + + Given: + + | A B C | | J K L | + Matrix = | D E F |, other = | M N O | + | G H I | | P Q R | + + sets SkMatrix to: + + | A B C | | J K L | | AJ+BM+CP AK+BN+CQ AL+BO+CR | + Matrix * other = | D E F | * | M N O | = | DJ+EM+FP DK+EN+FQ DL+EO+FR | + | G H I | | P Q R | | GJ+HM+IP GK+HN+IQ GL+HO+IR | + + @param other SkMatrix on right side of multiply expression + */ + SkMatrix& preConcat(const SkMatrix& other); + + /** Sets SkMatrix to SkMatrix constructed from translation (dx, dy) multiplied by SkMatrix. + This can be thought of as moving the point to be mapped after applying SkMatrix. + + Given: + + | J K L | | 1 0 dx | + Matrix = | M N O |, T(dx, dy) = | 0 1 dy | + | P Q R | | 0 0 1 | + + sets SkMatrix to: + + | 1 0 dx | | J K L | | J+dx*P K+dx*Q L+dx*R | + T(dx, dy) * Matrix = | 0 1 dy | | M N O | = | M+dy*P N+dy*Q O+dy*R | + | 0 0 1 | | P Q R | | P Q R | + + @param dx x-axis translation after applying SkMatrix + @param dy y-axis translation after applying SkMatrix + */ + SkMatrix& postTranslate(SkScalar dx, SkScalar dy); + + /** Sets SkMatrix to SkMatrix constructed from scaling by (sx, sy) about pivot point + (px, py), multiplied by SkMatrix. + This can be thought of as scaling about a pivot point after applying SkMatrix. + + Given: + + | J K L | | sx 0 dx | + Matrix = | M N O |, S(sx, sy, px, py) = | 0 sy dy | + | P Q R | | 0 0 1 | + + where + + dx = px - sx * px + dy = py - sy * py + + sets SkMatrix to: + + | sx 0 dx | | J K L | | sx*J+dx*P sx*K+dx*Q sx*L+dx+R | + S(sx, sy, px, py) * Matrix = | 0 sy dy | | M N O | = | sy*M+dy*P sy*N+dy*Q sy*O+dy*R | + | 0 0 1 | | P Q R | | P Q R | + + @param sx horizontal scale factor + @param sy vertical scale factor + @param px pivot on x-axis + @param py pivot on y-axis + */ + SkMatrix& postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py); + + /** Sets SkMatrix to SkMatrix constructed from scaling by (sx, sy) about pivot point + (0, 0), multiplied by SkMatrix. + This can be thought of as scaling about the origin after applying SkMatrix. + + Given: + + | J K L | | sx 0 0 | + Matrix = | M N O |, S(sx, sy) = | 0 sy 0 | + | P Q R | | 0 0 1 | + + sets SkMatrix to: + + | sx 0 0 | | J K L | | sx*J sx*K sx*L | + S(sx, sy) * Matrix = | 0 sy 0 | | M N O | = | sy*M sy*N sy*O | + | 0 0 1 | | P Q R | | P Q R | + + @param sx horizontal scale factor + @param sy vertical scale factor + */ + SkMatrix& postScale(SkScalar sx, SkScalar sy); + + /** Sets SkMatrix to SkMatrix constructed from rotating by degrees about pivot point + (px, py), multiplied by SkMatrix. + This can be thought of as rotating about a pivot point after applying SkMatrix. + + Positive degrees rotates clockwise. + + Given: + + | J K L | | c -s dx | + Matrix = | M N O |, R(degrees, px, py) = | s c dy | + | P Q R | | 0 0 1 | + + where + + c = cos(degrees) + s = sin(degrees) + dx = s * py + (1 - c) * px + dy = -s * px + (1 - c) * py + + sets SkMatrix to: + + |c -s dx| |J K L| |cJ-sM+dx*P cK-sN+dx*Q cL-sO+dx+R| + R(degrees, px, py) * Matrix = |s c dy| |M N O| = |sJ+cM+dy*P sK+cN+dy*Q sL+cO+dy*R| + |0 0 1| |P Q R| | P Q R| + + @param degrees angle of axes relative to upright axes + @param px pivot on x-axis + @param py pivot on y-axis + */ + SkMatrix& postRotate(SkScalar degrees, SkScalar px, SkScalar py); + + /** Sets SkMatrix to SkMatrix constructed from rotating by degrees about pivot point + (0, 0), multiplied by SkMatrix. + This can be thought of as rotating about the origin after applying SkMatrix. + + Positive degrees rotates clockwise. + + Given: + + | J K L | | c -s 0 | + Matrix = | M N O |, R(degrees, px, py) = | s c 0 | + | P Q R | | 0 0 1 | + + where + + c = cos(degrees) + s = sin(degrees) + + sets SkMatrix to: + + | c -s dx | | J K L | | cJ-sM cK-sN cL-sO | + R(degrees, px, py) * Matrix = | s c dy | | M N O | = | sJ+cM sK+cN sL+cO | + | 0 0 1 | | P Q R | | P Q R | + + @param degrees angle of axes relative to upright axes + */ + SkMatrix& postRotate(SkScalar degrees); + + /** Sets SkMatrix to SkMatrix constructed from skewing by (kx, ky) about pivot point + (px, py), multiplied by SkMatrix. + This can be thought of as skewing about a pivot point after applying SkMatrix. + + Given: + + | J K L | | 1 kx dx | + Matrix = | M N O |, K(kx, ky, px, py) = | ky 1 dy | + | P Q R | | 0 0 1 | + + where + + dx = -kx * py + dy = -ky * px + + sets SkMatrix to: + + | 1 kx dx| |J K L| |J+kx*M+dx*P K+kx*N+dx*Q L+kx*O+dx+R| + K(kx, ky, px, py) * Matrix = |ky 1 dy| |M N O| = |ky*J+M+dy*P ky*K+N+dy*Q ky*L+O+dy*R| + | 0 0 1| |P Q R| | P Q R| + + @param kx horizontal skew factor + @param ky vertical skew factor + @param px pivot on x-axis + @param py pivot on y-axis + */ + SkMatrix& postSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py); + + /** Sets SkMatrix to SkMatrix constructed from skewing by (kx, ky) about pivot point + (0, 0), multiplied by SkMatrix. + This can be thought of as skewing about the origin after applying SkMatrix. + + Given: + + | J K L | | 1 kx 0 | + Matrix = | M N O |, K(kx, ky) = | ky 1 0 | + | P Q R | | 0 0 1 | + + sets SkMatrix to: + + | 1 kx 0 | | J K L | | J+kx*M K+kx*N L+kx*O | + K(kx, ky) * Matrix = | ky 1 0 | | M N O | = | ky*J+M ky*K+N ky*L+O | + | 0 0 1 | | P Q R | | P Q R | + + @param kx horizontal skew factor + @param ky vertical skew factor + */ + SkMatrix& postSkew(SkScalar kx, SkScalar ky); + + /** Sets SkMatrix to SkMatrix other multiplied by SkMatrix. + This can be thought of mapping by other after applying SkMatrix. + + Given: + + | J K L | | A B C | + Matrix = | M N O |, other = | D E F | + | P Q R | | G H I | + + sets SkMatrix to: + + | A B C | | J K L | | AJ+BM+CP AK+BN+CQ AL+BO+CR | + other * Matrix = | D E F | * | M N O | = | DJ+EM+FP DK+EN+FQ DL+EO+FR | + | G H I | | P Q R | | GJ+HM+IP GK+HN+IQ GL+HO+IR | + + @param other SkMatrix on left side of multiply expression + */ + SkMatrix& postConcat(const SkMatrix& other); + +#ifndef SK_SUPPORT_LEGACY_MATRIX_RECTTORECT +private: +#endif + /** Sets SkMatrix to scale and translate src SkRect to dst SkRect. stf selects whether + mapping completely fills dst or preserves the aspect ratio, and how to align + src within dst. Returns false if src is empty, and sets SkMatrix to identity. + Returns true if dst is empty, and sets SkMatrix to: + + | 0 0 0 | + | 0 0 0 | + | 0 0 1 | + + @param src SkRect to map from + @param dst SkRect to map to + @return true if SkMatrix can represent SkRect mapping + + example: https://fiddle.skia.org/c/@Matrix_setRectToRect + */ + bool setRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf); + + /** Returns SkMatrix set to scale and translate src SkRect to dst SkRect. stf selects + whether mapping completely fills dst or preserves the aspect ratio, and how to + align src within dst. Returns the identity SkMatrix if src is empty. If dst is + empty, returns SkMatrix set to: + + | 0 0 0 | + | 0 0 0 | + | 0 0 1 | + + @param src SkRect to map from + @param dst SkRect to map to + @return SkMatrix mapping src to dst + */ + static SkMatrix MakeRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf) { + SkMatrix m; + m.setRectToRect(src, dst, stf); + return m; + } +#ifndef SK_SUPPORT_LEGACY_MATRIX_RECTTORECT +public: +#endif + + /** Sets SkMatrix to map src to dst. count must be zero or greater, and four or less. + + If count is zero, sets SkMatrix to identity and returns true. + If count is one, sets SkMatrix to translate and returns true. + If count is two or more, sets SkMatrix to map SkPoint if possible; returns false + if SkMatrix cannot be constructed. If count is four, SkMatrix may include + perspective. + + @param src SkPoint to map from + @param dst SkPoint to map to + @param count number of SkPoint in src and dst + @return true if SkMatrix was constructed successfully + + example: https://fiddle.skia.org/c/@Matrix_setPolyToPoly + */ + bool setPolyToPoly(const SkPoint src[], const SkPoint dst[], int count); + + /** Sets inverse to reciprocal matrix, returning true if SkMatrix can be inverted. + Geometrically, if SkMatrix maps from source to destination, inverse SkMatrix + maps from destination to source. If SkMatrix can not be inverted, inverse is + unchanged. + + @param inverse storage for inverted SkMatrix; may be nullptr + @return true if SkMatrix can be inverted + */ + [[nodiscard]] bool invert(SkMatrix* inverse) const { + // Allow the trivial case to be inlined. + if (this->isIdentity()) { + if (inverse) { + inverse->reset(); + } + return true; + } + return this->invertNonIdentity(inverse); + } + + /** Fills affine with identity values in column major order. + Sets affine to: + + | 1 0 0 | + | 0 1 0 | + + Affine 3 by 2 matrices in column major order are used by OpenGL and XPS. + + @param affine storage for 3 by 2 affine matrix + + example: https://fiddle.skia.org/c/@Matrix_SetAffineIdentity + */ + static void SetAffineIdentity(SkScalar affine[6]); + + /** Fills affine in column major order. Sets affine to: + + | scale-x skew-x translate-x | + | skew-y scale-y translate-y | + + If SkMatrix contains perspective, returns false and leaves affine unchanged. + + @param affine storage for 3 by 2 affine matrix; may be nullptr + @return true if SkMatrix does not contain perspective + */ + [[nodiscard]] bool asAffine(SkScalar affine[6]) const; + + /** Sets SkMatrix to affine values, passed in column major order. Given affine, + column, then row, as: + + | scale-x skew-x translate-x | + | skew-y scale-y translate-y | + + SkMatrix is set, row, then column, to: + + | scale-x skew-x translate-x | + | skew-y scale-y translate-y | + | 0 0 1 | + + @param affine 3 by 2 affine matrix + */ + SkMatrix& setAffine(const SkScalar affine[6]); + + /** + * A matrix is categorized as 'perspective' if the bottom row is not [0, 0, 1]. + * However, for most uses (e.g. mapPoints) a bottom row of [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, X], + * it will be changed to [0, 0, 1] by scaling the rest of the matrix by 1/X. + * + * | A B C | | A/X B/X C/X | + * | D E F | -> | D/X E/X F/X | for X != 0 + * | 0 0 X | | 0 0 1 | + */ + void normalizePerspective() { + if (fMat[8] != 1) { + this->doNormalizePerspective(); + } + } + + /** Maps src SkPoint array of length count to dst SkPoint array of equal or greater + length. SkPoint are mapped by multiplying each SkPoint by SkMatrix. Given: + + | A B C | | x | + Matrix = | D E F |, pt = | y | + | G H I | | 1 | + + where + + for (i = 0; i < count; ++i) { + x = src[i].fX + y = src[i].fY + } + + each dst SkPoint is computed as: + + |A B C| |x| Ax+By+C Dx+Ey+F + Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , ------- + |G H I| |1| Gx+Hy+I Gx+Hy+I + + src and dst may point to the same storage. + + @param dst storage for mapped SkPoint + @param src SkPoint to transform + @param count number of SkPoint to transform + + example: https://fiddle.skia.org/c/@Matrix_mapPoints + */ + void mapPoints(SkPoint dst[], const SkPoint src[], int count) const; + + /** Maps pts SkPoint array of length count in place. SkPoint are mapped by multiplying + each SkPoint by SkMatrix. Given: + + | A B C | | x | + Matrix = | D E F |, pt = | y | + | G H I | | 1 | + + where + + for (i = 0; i < count; ++i) { + x = pts[i].fX + y = pts[i].fY + } + + each resulting pts SkPoint is computed as: + + |A B C| |x| Ax+By+C Dx+Ey+F + Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , ------- + |G H I| |1| Gx+Hy+I Gx+Hy+I + + @param pts storage for mapped SkPoint + @param count number of SkPoint to transform + */ + void mapPoints(SkPoint pts[], int count) const { + this->mapPoints(pts, pts, count); + } + + /** Maps src SkPoint3 array of length count to dst SkPoint3 array, which must of length count or + greater. SkPoint3 array is mapped by multiplying each SkPoint3 by SkMatrix. Given: + + | A B C | | x | + Matrix = | D E F |, src = | y | + | G H I | | z | + + each resulting dst SkPoint is computed as: + + |A B C| |x| + Matrix * src = |D E F| |y| = |Ax+By+Cz Dx+Ey+Fz Gx+Hy+Iz| + |G H I| |z| + + @param dst storage for mapped SkPoint3 array + @param src SkPoint3 array to transform + @param count items in SkPoint3 array to transform + + example: https://fiddle.skia.org/c/@Matrix_mapHomogeneousPoints + */ + void mapHomogeneousPoints(SkPoint3 dst[], const SkPoint3 src[], int count) const; + + /** + * Returns homogeneous points, starting with 2D src points (with implied w = 1). + */ + void mapHomogeneousPoints(SkPoint3 dst[], const SkPoint src[], int count) const; + + /** Returns SkPoint pt multiplied by SkMatrix. Given: + + | A B C | | x | + Matrix = | D E F |, pt = | y | + | G H I | | 1 | + + result is computed as: + + |A B C| |x| Ax+By+C Dx+Ey+F + Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , ------- + |G H I| |1| Gx+Hy+I Gx+Hy+I + + @param p SkPoint to map + @return mapped SkPoint + */ + SkPoint mapPoint(SkPoint pt) const { + SkPoint result; + this->mapXY(pt.x(), pt.y(), &result); + return result; + } + + /** Maps SkPoint (x, y) to result. SkPoint is mapped by multiplying by SkMatrix. Given: + + | A B C | | x | + Matrix = | D E F |, pt = | y | + | G H I | | 1 | + + result is computed as: + + |A B C| |x| Ax+By+C Dx+Ey+F + Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , ------- + |G H I| |1| Gx+Hy+I Gx+Hy+I + + @param x x-axis value of SkPoint to map + @param y y-axis value of SkPoint to map + @param result storage for mapped SkPoint + + example: https://fiddle.skia.org/c/@Matrix_mapXY + */ + void mapXY(SkScalar x, SkScalar y, SkPoint* result) const; + + /** Returns SkPoint (x, y) multiplied by SkMatrix. Given: + + | A B C | | x | + Matrix = | D E F |, pt = | y | + | G H I | | 1 | + + result is computed as: + + |A B C| |x| Ax+By+C Dx+Ey+F + Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , ------- + |G H I| |1| Gx+Hy+I Gx+Hy+I + + @param x x-axis value of SkPoint to map + @param y y-axis value of SkPoint to map + @return mapped SkPoint + */ + SkPoint mapXY(SkScalar x, SkScalar y) const { + SkPoint result; + this->mapXY(x,y, &result); + return result; + } + + + /** Returns (0, 0) multiplied by SkMatrix. Given: + + | A B C | | 0 | + Matrix = | D E F |, pt = | 0 | + | G H I | | 1 | + + result is computed as: + + |A B C| |0| C F + Matrix * pt = |D E F| |0| = |C F I| = - , - + |G H I| |1| I I + + @return mapped (0, 0) + */ + SkPoint mapOrigin() const { + SkScalar x = this->getTranslateX(), + y = this->getTranslateY(); + if (this->hasPerspective()) { + SkScalar w = fMat[kMPersp2]; + if (w) { w = 1 / w; } + x *= w; + y *= w; + } + return {x, y}; + } + + /** Maps src vector array of length count to vector SkPoint array of equal or greater + length. Vectors are mapped by multiplying each vector by SkMatrix, treating + SkMatrix translation as zero. Given: + + | A B 0 | | x | + Matrix = | D E 0 |, src = | y | + | G H I | | 1 | + + where + + for (i = 0; i < count; ++i) { + x = src[i].fX + y = src[i].fY + } + + each dst vector is computed as: + + |A B 0| |x| Ax+By Dx+Ey + Matrix * src = |D E 0| |y| = |Ax+By Dx+Ey Gx+Hy+I| = ------- , ------- + |G H I| |1| Gx+Hy+I Gx+Hy+I + + src and dst may point to the same storage. + + @param dst storage for mapped vectors + @param src vectors to transform + @param count number of vectors to transform + + example: https://fiddle.skia.org/c/@Matrix_mapVectors + */ + void mapVectors(SkVector dst[], const SkVector src[], int count) const; + + /** Maps vecs vector array of length count in place, multiplying each vector by + SkMatrix, treating SkMatrix translation as zero. Given: + + | A B 0 | | x | + Matrix = | D E 0 |, vec = | y | + | G H I | | 1 | + + where + + for (i = 0; i < count; ++i) { + x = vecs[i].fX + y = vecs[i].fY + } + + each result vector is computed as: + + |A B 0| |x| Ax+By Dx+Ey + Matrix * vec = |D E 0| |y| = |Ax+By Dx+Ey Gx+Hy+I| = ------- , ------- + |G H I| |1| Gx+Hy+I Gx+Hy+I + + @param vecs vectors to transform, and storage for mapped vectors + @param count number of vectors to transform + */ + void mapVectors(SkVector vecs[], int count) const { + this->mapVectors(vecs, vecs, count); + } + + /** Maps vector (dx, dy) to result. Vector is mapped by multiplying by SkMatrix, + treating SkMatrix translation as zero. Given: + + | A B 0 | | dx | + Matrix = | D E 0 |, vec = | dy | + | G H I | | 1 | + + each result vector is computed as: + + |A B 0| |dx| A*dx+B*dy D*dx+E*dy + Matrix * vec = |D E 0| |dy| = |A*dx+B*dy D*dx+E*dy G*dx+H*dy+I| = ----------- , ----------- + |G H I| | 1| G*dx+H*dy+I G*dx+*dHy+I + + @param dx x-axis value of vector to map + @param dy y-axis value of vector to map + @param result storage for mapped vector + */ + void mapVector(SkScalar dx, SkScalar dy, SkVector* result) const { + SkVector vec = { dx, dy }; + this->mapVectors(result, &vec, 1); + } + + /** Returns vector (dx, dy) multiplied by SkMatrix, treating SkMatrix translation as zero. + Given: + + | A B 0 | | dx | + Matrix = | D E 0 |, vec = | dy | + | G H I | | 1 | + + each result vector is computed as: + + |A B 0| |dx| A*dx+B*dy D*dx+E*dy + Matrix * vec = |D E 0| |dy| = |A*dx+B*dy D*dx+E*dy G*dx+H*dy+I| = ----------- , ----------- + |G H I| | 1| G*dx+H*dy+I G*dx+*dHy+I + + @param dx x-axis value of vector to map + @param dy y-axis value of vector to map + @return mapped vector + */ + SkVector mapVector(SkScalar dx, SkScalar dy) const { + SkVector vec = { dx, dy }; + this->mapVectors(&vec, &vec, 1); + return vec; + } + + /** Sets dst to bounds of src corners mapped by SkMatrix. + Returns true if mapped corners are dst corners. + + Returned value is the same as calling rectStaysRect(). + + @param dst storage for bounds of mapped SkPoint + @param src SkRect to map + @param pc whether to apply perspective clipping + @return true if dst is equivalent to mapped src + + example: https://fiddle.skia.org/c/@Matrix_mapRect + */ + bool mapRect(SkRect* dst, const SkRect& src, + SkApplyPerspectiveClip pc = SkApplyPerspectiveClip::kYes) const; + + /** Sets rect to bounds of rect corners mapped by SkMatrix. + Returns true if mapped corners are computed rect corners. + + Returned value is the same as calling rectStaysRect(). + + @param rect rectangle to map, and storage for bounds of mapped corners + @param pc whether to apply perspective clipping + @return true if result is equivalent to mapped rect + */ + bool mapRect(SkRect* rect, SkApplyPerspectiveClip pc = SkApplyPerspectiveClip::kYes) const { + return this->mapRect(rect, *rect, pc); + } + + /** Returns bounds of src corners mapped by SkMatrix. + + @param src rectangle to map + @return mapped bounds + */ + SkRect mapRect(const SkRect& src, + SkApplyPerspectiveClip pc = SkApplyPerspectiveClip::kYes) const { + SkRect dst; + (void)this->mapRect(&dst, src, pc); + return dst; + } + + /** Maps four corners of rect to dst. SkPoint are mapped by multiplying each + rect corner by SkMatrix. rect corner is processed in this order: + (rect.fLeft, rect.fTop), (rect.fRight, rect.fTop), (rect.fRight, rect.fBottom), + (rect.fLeft, rect.fBottom). + + rect may be empty: rect.fLeft may be greater than or equal to rect.fRight; + rect.fTop may be greater than or equal to rect.fBottom. + + Given: + + | A B C | | x | + Matrix = | D E F |, pt = | y | + | G H I | | 1 | + + where pt is initialized from each of (rect.fLeft, rect.fTop), + (rect.fRight, rect.fTop), (rect.fRight, rect.fBottom), (rect.fLeft, rect.fBottom), + each dst SkPoint is computed as: + + |A B C| |x| Ax+By+C Dx+Ey+F + Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , ------- + |G H I| |1| Gx+Hy+I Gx+Hy+I + + @param dst storage for mapped corner SkPoint + @param rect SkRect to map + + Note: this does not perform perspective clipping (as that might result in more than + 4 points, so results are suspect if the matrix contains perspective. + */ + void mapRectToQuad(SkPoint dst[4], const SkRect& rect) const { + // This could potentially be faster if we only transformed each x and y of the rect once. + rect.toQuad(dst); + this->mapPoints(dst, 4); + } + + /** Sets dst to bounds of src corners mapped by SkMatrix. If matrix contains + elements other than scale or translate: asserts if SK_DEBUG is defined; + otherwise, results are undefined. + + @param dst storage for bounds of mapped SkPoint + @param src SkRect to map + + example: https://fiddle.skia.org/c/@Matrix_mapRectScaleTranslate + */ + void mapRectScaleTranslate(SkRect* dst, const SkRect& src) const; + + /** Returns geometric mean radius of ellipse formed by constructing circle of + size radius, and mapping constructed circle with SkMatrix. The result squared is + equal to the major axis length times the minor axis length. + Result is not meaningful if SkMatrix contains perspective elements. + + @param radius circle size to map + @return average mapped radius + + example: https://fiddle.skia.org/c/@Matrix_mapRadius + */ + SkScalar mapRadius(SkScalar radius) const; + + /** Compares a and b; returns true if a and b are numerically equal. Returns true + even if sign of zero values are different. Returns false if either SkMatrix + contains NaN, even if the other SkMatrix also contains NaN. + + @param a SkMatrix to compare + @param b SkMatrix to compare + @return true if SkMatrix a and SkMatrix b are numerically equal + */ + friend SK_API bool operator==(const SkMatrix& a, const SkMatrix& b); + + /** Compares a and b; returns true if a and b are not numerically equal. Returns false + even if sign of zero values are different. Returns true if either SkMatrix + contains NaN, even if the other SkMatrix also contains NaN. + + @param a SkMatrix to compare + @param b SkMatrix to compare + @return true if SkMatrix a and SkMatrix b are numerically not equal + */ + friend SK_API bool operator!=(const SkMatrix& a, const SkMatrix& b) { + return !(a == b); + } + + /** Writes text representation of SkMatrix to standard output. Floating point values + are written with limited precision; it may not be possible to reconstruct + original SkMatrix from output. + + example: https://fiddle.skia.org/c/@Matrix_dump + */ + void dump() const; + + /** Returns the minimum scaling factor of SkMatrix by decomposing the scaling and + skewing elements. + Returns -1 if scale factor overflows or SkMatrix contains perspective. + + @return minimum scale factor + + example: https://fiddle.skia.org/c/@Matrix_getMinScale + */ + SkScalar getMinScale() const; + + /** Returns the maximum scaling factor of SkMatrix by decomposing the scaling and + skewing elements. + Returns -1 if scale factor overflows or SkMatrix contains perspective. + + @return maximum scale factor + + example: https://fiddle.skia.org/c/@Matrix_getMaxScale + */ + SkScalar getMaxScale() const; + + /** Sets scaleFactors[0] to the minimum scaling factor, and scaleFactors[1] to the + maximum scaling factor. Scaling factors are computed by decomposing + the SkMatrix scaling and skewing elements. + + Returns true if scaleFactors are found; otherwise, returns false and sets + scaleFactors to undefined values. + + @param scaleFactors storage for minimum and maximum scale factors + @return true if scale factors were computed correctly + */ + [[nodiscard]] bool getMinMaxScales(SkScalar scaleFactors[2]) const; + + /** Decomposes SkMatrix into scale components and whatever remains. Returns false if + SkMatrix could not be decomposed. + + Sets scale to portion of SkMatrix that scale axes. Sets remaining to SkMatrix + with scaling factored out. remaining may be passed as nullptr + to determine if SkMatrix can be decomposed without computing remainder. + + Returns true if scale components are found. scale and remaining are + unchanged if SkMatrix contains perspective; scale factors are not finite, or + are nearly zero. + + On success: Matrix = Remaining * scale. + + @param scale axes scaling factors; may be nullptr + @param remaining SkMatrix without scaling; may be nullptr + @return true if scale can be computed + + example: https://fiddle.skia.org/c/@Matrix_decomposeScale + */ + bool decomposeScale(SkSize* scale, SkMatrix* remaining = nullptr) const; + + /** Returns reference to const identity SkMatrix. Returned SkMatrix is set to: + + | 1 0 0 | + | 0 1 0 | + | 0 0 1 | + + @return const identity SkMatrix + + example: https://fiddle.skia.org/c/@Matrix_I + */ + static const SkMatrix& I(); + + /** Returns reference to a const SkMatrix with invalid values. Returned SkMatrix is set + to: + + | SK_ScalarMax SK_ScalarMax SK_ScalarMax | + | SK_ScalarMax SK_ScalarMax SK_ScalarMax | + | SK_ScalarMax SK_ScalarMax SK_ScalarMax | + + @return const invalid SkMatrix + + example: https://fiddle.skia.org/c/@Matrix_InvalidMatrix + */ + static const SkMatrix& InvalidMatrix(); + + /** Returns SkMatrix a multiplied by SkMatrix b. + + Given: + + | A B C | | J K L | + a = | D E F |, b = | M N O | + | G H I | | P Q R | + + sets SkMatrix to: + + | A B C | | J K L | | AJ+BM+CP AK+BN+CQ AL+BO+CR | + a * b = | D E F | * | M N O | = | DJ+EM+FP DK+EN+FQ DL+EO+FR | + | G H I | | P Q R | | GJ+HM+IP GK+HN+IQ GL+HO+IR | + + @param a SkMatrix on left side of multiply expression + @param b SkMatrix on right side of multiply expression + @return SkMatrix computed from a times b + */ + static SkMatrix Concat(const SkMatrix& a, const SkMatrix& b) { + SkMatrix result; + result.setConcat(a, b); + return result; + } + + friend SkMatrix operator*(const SkMatrix& a, const SkMatrix& b) { + return Concat(a, b); + } + + /** Sets internal cache to unknown state. Use to force update after repeated + modifications to SkMatrix element reference returned by operator[](int index). + */ + void dirtyMatrixTypeCache() { + this->setTypeMask(kUnknown_Mask); + } + + /** Initializes SkMatrix with scale and translate elements. + + | sx 0 tx | + | 0 sy ty | + | 0 0 1 | + + @param sx horizontal scale factor to store + @param sy vertical scale factor to store + @param tx horizontal translation to store + @param ty vertical translation to store + */ + void setScaleTranslate(SkScalar sx, SkScalar sy, SkScalar tx, SkScalar ty) { + fMat[kMScaleX] = sx; + fMat[kMSkewX] = 0; + fMat[kMTransX] = tx; + + fMat[kMSkewY] = 0; + fMat[kMScaleY] = sy; + fMat[kMTransY] = ty; + + fMat[kMPersp0] = 0; + fMat[kMPersp1] = 0; + fMat[kMPersp2] = 1; + + int mask = 0; + if (sx != 1 || sy != 1) { + mask |= kScale_Mask; + } + if (tx != 0.0f || ty != 0.0f) { + mask |= kTranslate_Mask; + } + if (sx != 0 && sy != 0) { + mask |= kRectStaysRect_Mask; + } + this->setTypeMask(mask); + } + + /** 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, 9); } + +private: + /** Set if the matrix will map a rectangle to another rectangle. This + can be true if the matrix is scale-only, or rotates a multiple of + 90 degrees. + + This bit will be set on identity matrices + */ + static constexpr int kRectStaysRect_Mask = 0x10; + + /** Set if the perspective bit is valid even though the rest of + the matrix is Unknown. + */ + static constexpr int kOnlyPerspectiveValid_Mask = 0x40; + + static constexpr int kUnknown_Mask = 0x80; + + static constexpr int kORableMasks = kTranslate_Mask | + kScale_Mask | + kAffine_Mask | + kPerspective_Mask; + + static constexpr int kAllMasks = kTranslate_Mask | + kScale_Mask | + kAffine_Mask | + kPerspective_Mask | + kRectStaysRect_Mask; + + SkScalar fMat[9]; + mutable int32_t fTypeMask; + + constexpr SkMatrix(SkScalar sx, SkScalar kx, SkScalar tx, + SkScalar ky, SkScalar sy, SkScalar ty, + SkScalar p0, SkScalar p1, SkScalar p2, int typeMask) + : fMat{sx, kx, tx, + ky, sy, ty, + p0, p1, p2} + , fTypeMask(typeMask) {} + + static void ComputeInv(SkScalar dst[9], const SkScalar src[9], double invDet, bool isPersp); + + uint8_t computeTypeMask() const; + uint8_t computePerspectiveTypeMask() const; + + void setTypeMask(int mask) { + // allow kUnknown or a valid mask + SkASSERT(kUnknown_Mask == mask || (mask & kAllMasks) == mask || + ((kUnknown_Mask | kOnlyPerspectiveValid_Mask) & mask) + == (kUnknown_Mask | kOnlyPerspectiveValid_Mask)); + fTypeMask = mask; + } + + void orTypeMask(int mask) { + SkASSERT((mask & kORableMasks) == mask); + fTypeMask |= mask; + } + + void clearTypeMask(int mask) { + // only allow a valid mask + SkASSERT((mask & kAllMasks) == mask); + fTypeMask &= ~mask; + } + + TypeMask getPerspectiveTypeMaskOnly() const { + if ((fTypeMask & kUnknown_Mask) && + !(fTypeMask & kOnlyPerspectiveValid_Mask)) { + fTypeMask = this->computePerspectiveTypeMask(); + } + return (TypeMask)(fTypeMask & 0xF); + } + + /** Returns true if we already know that the matrix is identity; + false otherwise. + */ + bool isTriviallyIdentity() const { + if (fTypeMask & kUnknown_Mask) { + return false; + } + return ((fTypeMask & 0xF) == 0); + } + + inline void updateTranslateMask() { + if ((fMat[kMTransX] != 0) | (fMat[kMTransY] != 0)) { + fTypeMask |= kTranslate_Mask; + } else { + fTypeMask &= ~kTranslate_Mask; + } + } + + typedef void (*MapXYProc)(const SkMatrix& mat, SkScalar x, SkScalar y, + SkPoint* result); + + static MapXYProc GetMapXYProc(TypeMask mask) { + SkASSERT((mask & ~kAllMasks) == 0); + return gMapXYProcs[mask & kAllMasks]; + } + + MapXYProc getMapXYProc() const { + return GetMapXYProc(this->getType()); + } + + typedef void (*MapPtsProc)(const SkMatrix& mat, SkPoint dst[], + const SkPoint src[], int count); + + static MapPtsProc GetMapPtsProc(TypeMask mask) { + SkASSERT((mask & ~kAllMasks) == 0); + return gMapPtsProcs[mask & kAllMasks]; + } + + MapPtsProc getMapPtsProc() const { + return GetMapPtsProc(this->getType()); + } + + [[nodiscard]] bool invertNonIdentity(SkMatrix* inverse) const; + + static bool Poly2Proc(const SkPoint[], SkMatrix*); + static bool Poly3Proc(const SkPoint[], SkMatrix*); + static bool Poly4Proc(const SkPoint[], SkMatrix*); + + static void Identity_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); + static void Trans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); + static void Scale_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); + static void ScaleTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); + static void Rot_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); + static void RotTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); + static void Persp_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*); + + static const MapXYProc gMapXYProcs[]; + + static void Identity_pts(const SkMatrix&, SkPoint[], const SkPoint[], int); + static void Trans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); + static void Scale_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); + static void ScaleTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], + int count); + static void Persp_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); + + static void Affine_vpts(const SkMatrix&, SkPoint dst[], const SkPoint[], int); + + static const MapPtsProc gMapPtsProcs[]; + + // return the number of bytes written, whether or not buffer is null + size_t writeToMemory(void* buffer) const; + /** + * Reads data from the buffer parameter + * + * @param buffer Memory to read from + * @param length Amount of memory available in the buffer + * @return number of bytes read (must be a multiple of 4) or + * 0 if there was not enough memory available + */ + size_t readFromMemory(const void* buffer, size_t length); + + // legacy method -- still needed? why not just postScale(1/divx, ...)? + bool postIDiv(int divx, int divy); + void doNormalizePerspective(); + + friend class SkPerspIter; + friend class SkMatrixPriv; + friend class SerializationTest; +}; +SK_END_REQUIRE_DENSE + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkMesh.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkMesh.h new file mode 100644 index 0000000000..6eccc937fd --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkMesh.h @@ -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 +#include +#include +#include +#include +#include + +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 { +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 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 attributes, + size_t vertexStride, + SkSpan varyings, + const SkString& vs, + const SkString& fs); + static Result Make(SkSpan attributes, + size_t vertexStride, + SkSpan varyings, + const SkString& vs, + const SkString& fs, + sk_sp cs); + static Result Make(SkSpan attributes, + size_t vertexStride, + SkSpan varyings, + const SkString& vs, + const SkString& fs, + sk_sp cs, + SkAlphaType at); + + SkSpan 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 uniforms() const { return SkSpan(fUniforms); } + + /** Provides basic info about individual children: names, indices and runtime effect type. */ + SkSpan 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 attributes, + size_t stride, + SkSpan varyings, + const SkString& vs, + const SkString& fs, + sk_sp cs, + SkAlphaType at); + + SkMeshSpecification(SkSpan, + size_t, + SkSpan, + int passthroughLocalCoordsVaryingIndex, + uint32_t deadVaryingMask, + std::vector uniforms, + std::vector children, + std::unique_ptr, + std::unique_ptr, + ColorType, + sk_sp, + SkAlphaType); + + SkMeshSpecification(const SkMeshSpecification&) = delete; + SkMeshSpecification(SkMeshSpecification&&) = delete; + + SkMeshSpecification& operator=(const SkMeshSpecification&) = delete; + SkMeshSpecification& operator=(SkMeshSpecification&&) = delete; + + const std::vector fAttributes; + const std::vector fVaryings; + const std::vector fUniforms; + const std::vector fChildren; + const std::unique_ptr fVS; + const std::unique_ptr fFS; + const size_t fStride; + uint32_t fHash; + const int fPassthroughLocalCoordsVaryingIndex; + const uint32_t fDeadVaryingMask; + const ColorType fColorType; + const sk_sp 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, + Mode, + sk_sp, + size_t vertexCount, + size_t vertexOffset, + sk_sp uniforms, + SkSpan 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, + Mode, + sk_sp, + size_t vertexCount, + size_t vertexOffset, + sk_sp, + size_t indexCount, + size_t indexOffset, + sk_sp uniforms, + SkSpan children, + const SkRect& bounds); + + sk_sp refSpec() const { return fSpec; } + SkMeshSpecification* spec() const { return fSpec.get(); } + + Mode mode() const { return fMode; } + + sk_sp refVertexBuffer() const { return fVB; } + VertexBuffer* vertexBuffer() const { return fVB.get(); } + + size_t vertexOffset() const { return fVOffset; } + size_t vertexCount() const { return fVCount; } + + sk_sp refIndexBuffer() const { return fIB; } + IndexBuffer* indexBuffer() const { return fIB.get(); } + + size_t indexOffset() const { return fIOffset; } + size_t indexCount() const { return fICount; } + + sk_sp refUniforms() const { return fUniforms; } + const SkData* uniforms() const { return fUniforms.get(); } + + SkSpan children() const { return SkSpan(fChildren); } + + SkRect bounds() const { return fBounds; } + + bool isValid() const; + +private: + std::tuple validate() const; + + sk_sp fSpec; + + sk_sp fVB; + sk_sp fIB; + + sk_sp 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 MakeIndexBuffer(const void* data, size_t size); + +/** + * Makes a copy of an index buffer. The copy will be CPU-backed. + */ +SK_API sk_sp CopyIndexBuffer(const sk_sp&); + +/** + * 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 MakeVertexBuffer(const void*, size_t size); + +/** + * Makes a copy of a vertex buffer. The copy will be CPU-backed. + */ +SK_API sk_sp CopyVertexBuffer(const sk_sp&); +} // namespace SkMeshes + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkMilestone.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkMilestone.h new file mode 100644 index 0000000000..05671302e5 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkMilestone.h @@ -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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkOpenTypeSVGDecoder.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkOpenTypeSVGDecoder.h new file mode 100644 index 0000000000..5a2e48a9df --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkOpenTypeSVGDecoder.h @@ -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 + +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 palette) = 0; + virtual ~SkOpenTypeSVGDecoder() = default; +}; + +#endif // SkOpenTypeSVGDecoder_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkOverdrawCanvas.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkOverdrawCanvas.h new file mode 100644 index 0000000000..5dea52ae69 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkOverdrawCanvas.h @@ -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 + +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 { +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; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPaint.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPaint.h new file mode 100644 index 0000000000..300f0ea088 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPaint.h @@ -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 +#include +#include + +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(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(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(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 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 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 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 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 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 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 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 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 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 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 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 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 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 fPathEffect; + sk_sp fShader; + sk_sp fMaskFilter; + sk_sp fColorFilter; + sk_sp fImageFilter; + sk_sp 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::value); + static_assert(::sk_is_trivially_relocatable::value); + static_assert(::sk_is_trivially_relocatable::value); + static_assert(::sk_is_trivially_relocatable::value); + static_assert(::sk_is_trivially_relocatable::value); + static_assert(::sk_is_trivially_relocatable::value); + static_assert(::sk_is_trivially_relocatable::value); + static_assert(::sk_is_trivially_relocatable::value); + + friend class SkPaintPriv; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPath.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPath.h new file mode 100644 index 0000000000..00324e989e --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPath.h @@ -0,0 +1,1943 @@ +/* + * 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 SkPath_DEFINED +#define SkPath_DEFINED + +#include "include/core/SkMatrix.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/base/SkDebug.h" +#include "include/private/base/SkTo.h" +#include "include/private/base/SkTypeTraits.h" + +#include +#include +#include +#include +#include +#include + +struct SkArc; +class SkData; +class SkPathRef; +class SkRRect; +class SkWStream; +enum class SkPathConvexity; +enum class SkPathFirstDirection; +struct SkPathVerbAnalysis; + +// WIP -- define this locally, and fix call-sites to use SkPathBuilder (skbug.com/9000) +//#define SK_HIDE_PATH_EDIT_METHODS + +/** \class SkPath + SkPath contain geometry. SkPath may be empty, or contain one or more verbs that + outline a figure. SkPath always starts with a move verb to a Cartesian coordinate, + and may be followed by additional verbs that add lines or curves. + Adding a close verb makes the geometry into a continuous loop, a closed contour. + SkPath may contain any number of contours, each beginning with a move verb. + + SkPath contours may contain only a move verb, or may also contain lines, + quadratic beziers, conics, and cubic beziers. SkPath contours may be open or + closed. + + When used to draw a filled area, SkPath describes whether the fill is inside or + outside the geometry. SkPath also describes the winding rule used to fill + overlapping contours. + + Internally, SkPath lazily computes metrics likes bounds and convexity. Call + SkPath::updateBoundsCache to make SkPath thread safe. +*/ +class SK_API SkPath { +public: + /** + * Create a new path with the specified segments. + * + * The points and weights arrays are read in order, based on the sequence of verbs. + * + * Move 1 point + * Line 1 point + * Quad 2 points + * Conic 2 points and 1 weight + * Cubic 3 points + * Close 0 points + * + * If an illegal sequence of verbs is encountered, or the specified number of points + * or weights is not sufficient given the verbs, an empty Path is returned. + * + * A legal sequence of verbs consists of any number of Contours. A contour always begins + * with a Move verb, followed by 0 or more segments: Line, Quad, Conic, Cubic, followed + * by an optional Close. + */ + static SkPath Make(const SkPoint[], int pointCount, + const uint8_t[], int verbCount, + const SkScalar[], int conicWeightCount, + SkPathFillType, bool isVolatile = false); + + static SkPath Rect(const SkRect&, SkPathDirection = SkPathDirection::kCW, + unsigned startIndex = 0); + static SkPath Oval(const SkRect&, SkPathDirection = SkPathDirection::kCW); + static SkPath Oval(const SkRect&, SkPathDirection, unsigned startIndex); + static SkPath Circle(SkScalar center_x, SkScalar center_y, SkScalar radius, + SkPathDirection dir = SkPathDirection::kCW); + static SkPath RRect(const SkRRect&, SkPathDirection dir = SkPathDirection::kCW); + static SkPath RRect(const SkRRect&, SkPathDirection, unsigned startIndex); + static SkPath RRect(const SkRect& bounds, SkScalar rx, SkScalar ry, + SkPathDirection dir = SkPathDirection::kCW); + + static SkPath Polygon(const SkPoint pts[], int count, bool isClosed, + SkPathFillType = SkPathFillType::kWinding, + bool isVolatile = false); + + static SkPath Polygon(const std::initializer_list& list, bool isClosed, + SkPathFillType fillType = SkPathFillType::kWinding, + bool isVolatile = false) { + return Polygon(list.begin(), SkToInt(list.size()), isClosed, fillType, isVolatile); + } + + static SkPath Line(const SkPoint a, const SkPoint b) { + return Polygon({a, b}, false); + } + + /** Constructs an empty SkPath. By default, SkPath has no verbs, no SkPoint, and no weights. + FillType is set to kWinding. + + @return empty SkPath + + example: https://fiddle.skia.org/c/@Path_empty_constructor + */ + SkPath(); + + /** Constructs a copy of an existing path. + Copy constructor makes two paths identical by value. Internally, path and + the returned result share pointer values. The underlying verb array, SkPoint array + and weights are copied when modified. + + Creating a SkPath copy is very efficient and never allocates memory. + SkPath are always copied by value from the interface; the underlying shared + pointers are not exposed. + + @param path SkPath to copy by value + @return copy of SkPath + + example: https://fiddle.skia.org/c/@Path_copy_const_SkPath + */ + SkPath(const SkPath& path); + + /** Releases ownership of any shared data and deletes data if SkPath is sole owner. + + example: https://fiddle.skia.org/c/@Path_destructor + */ + ~SkPath(); + + /** Returns a copy of this path in the current state. */ + SkPath snapshot() const { + return *this; + } + + /** Returns a copy of this path in the current state, and resets the path to empty. */ + SkPath detach() { + SkPath result = *this; + this->reset(); + return result; + } + + /** Constructs a copy of an existing path. + SkPath assignment makes two paths identical by value. Internally, assignment + shares pointer values. The underlying verb array, SkPoint array and weights + are copied when modified. + + Copying SkPath by assignment is very efficient and never allocates memory. + SkPath are always copied by value from the interface; the underlying shared + pointers are not exposed. + + @param path verb array, SkPoint array, weights, and SkPath::FillType to copy + @return SkPath copied by value + + example: https://fiddle.skia.org/c/@Path_copy_operator + */ + SkPath& operator=(const SkPath& path); + + /** Compares a and b; returns true if SkPath::FillType, verb array, SkPoint array, and weights + are equivalent. + + @param a SkPath to compare + @param b SkPath to compare + @return true if SkPath pair are equivalent + */ + friend SK_API bool operator==(const SkPath& a, const SkPath& b); + + /** Compares a and b; returns true if SkPath::FillType, verb array, SkPoint array, and weights + are not equivalent. + + @param a SkPath to compare + @param b SkPath to compare + @return true if SkPath pair are not equivalent + */ + friend bool operator!=(const SkPath& a, const SkPath& b) { + return !(a == b); + } + + /** Returns true if SkPath contain equal verbs and equal weights. + If SkPath contain one or more conics, the weights must match. + + conicTo() may add different verbs depending on conic weight, so it is not + trivial to interpolate a pair of SkPath containing conics with different + conic weight values. + + @param compare SkPath to compare + @return true if SkPath verb array and weights are equivalent + + example: https://fiddle.skia.org/c/@Path_isInterpolatable + */ + bool isInterpolatable(const SkPath& compare) const; + + /** Interpolates between SkPath with SkPoint array of equal size. + Copy verb array and weights to out, and set out SkPoint array to a weighted + average of this SkPoint array and ending SkPoint array, using the formula: + (Path Point * weight) + ending Point * (1 - weight). + + weight is most useful when between zero (ending SkPoint array) and + one (this Point_Array); will work with values outside of this + range. + + interpolate() returns false and leaves out unchanged if SkPoint array is not + the same size as ending SkPoint array. Call isInterpolatable() to check SkPath + compatibility prior to calling interpolate(). + + @param ending SkPoint array averaged with this SkPoint array + @param weight contribution of this SkPoint array, and + one minus contribution of ending SkPoint array + @param out SkPath replaced by interpolated averages + @return true if SkPath contain same number of SkPoint + + example: https://fiddle.skia.org/c/@Path_interpolate + */ + bool interpolate(const SkPath& ending, SkScalar weight, SkPath* out) const; + + /** Returns SkPathFillType, the rule used to fill SkPath. + + @return current SkPathFillType setting + */ + SkPathFillType getFillType() const { return (SkPathFillType)fFillType; } + + /** Sets FillType, the rule used to fill SkPath. While there is no check + that ft is legal, values outside of FillType are not supported. + */ + void setFillType(SkPathFillType ft) { + fFillType = SkToU8(ft); + } + + /** Returns if FillType describes area outside SkPath geometry. The inverse fill area + extends indefinitely. + + @return true if FillType is kInverseWinding or kInverseEvenOdd + */ + bool isInverseFillType() const { return SkPathFillType_IsInverse(this->getFillType()); } + + /** Replaces FillType with its inverse. The inverse of FillType describes the area + unmodified by the original FillType. + */ + void toggleInverseFillType() { + fFillType ^= 2; + } + + /** Returns true if the path is convex. If necessary, it will first compute the convexity. + */ + bool isConvex() const; + + /** Returns true if this path is recognized as an oval or circle. + + bounds receives bounds of oval. + + bounds is unmodified if oval is not found. + + @param bounds storage for bounding SkRect of oval; may be nullptr + @return true if SkPath is recognized as an oval or circle + + example: https://fiddle.skia.org/c/@Path_isOval + */ + bool isOval(SkRect* bounds) const; + + /** Returns true if path is representable as SkRRect. + Returns false if path is representable as oval, circle, or SkRect. + + rrect receives bounds of SkRRect. + + rrect is unmodified if SkRRect is not found. + + @param rrect storage for bounding SkRect of SkRRect; may be nullptr + @return true if SkPath contains only SkRRect + + example: https://fiddle.skia.org/c/@Path_isRRect + */ + bool isRRect(SkRRect* rrect) const; + + /** Returns true if path is representable as an oval arc. In other words, could this + path be drawn using SkCanvas::drawArc. + + arc receives parameters of arc + + @param arc storage for arc; may be nullptr + @return true if SkPath contains only a single arc from an oval + */ + bool isArc(SkArc* arc) const; + + /** Sets SkPath to its initial state. + Removes verb array, SkPoint array, and weights, and sets FillType to kWinding. + Internal storage associated with SkPath is released. + + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_reset + */ + SkPath& reset(); + + /** Sets SkPath to its initial state, preserving internal storage. + Removes verb array, SkPoint array, and weights, and sets FillType to kWinding. + Internal storage associated with SkPath is retained. + + Use rewind() instead of reset() if SkPath storage will be reused and performance + is critical. + + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_rewind + */ + SkPath& rewind(); + + /** Returns if SkPath is empty. + Empty SkPath may have FillType but has no SkPoint, SkPath::Verb, or conic weight. + SkPath() constructs empty SkPath; reset() and rewind() make SkPath empty. + + @return true if the path contains no SkPath::Verb array + */ + bool isEmpty() const; + + /** Returns if contour is closed. + Contour is closed if SkPath SkPath::Verb array was last modified by close(). When stroked, + closed contour draws SkPaint::Join instead of SkPaint::Cap at first and last SkPoint. + + @return true if the last contour ends with a kClose_Verb + + example: https://fiddle.skia.org/c/@Path_isLastContourClosed + */ + bool isLastContourClosed() const; + + /** Returns true for finite SkPoint array values between negative SK_ScalarMax and + positive SK_ScalarMax. Returns false for any SkPoint array value of + SK_ScalarInfinity, SK_ScalarNegativeInfinity, or SK_ScalarNaN. + + @return true if all SkPoint values are finite + */ + bool isFinite() const; + + /** Returns true if the path is volatile; it will not be altered or discarded + by the caller after it is drawn. SkPath by default have volatile set false, allowing + SkSurface to attach a cache of data which speeds repeated drawing. If true, SkSurface + may not speed repeated drawing. + + @return true if caller will alter SkPath after drawing + */ + bool isVolatile() const { + return SkToBool(fIsVolatile); + } + + /** Specifies whether SkPath is volatile; whether it will be altered or discarded + by the caller after it is drawn. SkPath by default have volatile set false, allowing + Skia to attach a cache of data which speeds repeated drawing. + + Mark temporary paths, discarded or modified after use, as volatile + to inform Skia that the path need not be cached. + + Mark animating SkPath volatile to improve performance. + Mark unchanging SkPath non-volatile to improve repeated rendering. + + raster surface SkPath draws are affected by volatile for some shadows. + GPU surface SkPath draws are affected by volatile for some shadows and concave geometries. + + @param isVolatile true if caller will alter SkPath after drawing + @return reference to SkPath + */ + SkPath& setIsVolatile(bool isVolatile) { + fIsVolatile = isVolatile; + return *this; + } + + /** Tests if line between SkPoint pair is degenerate. + Line with no length or that moves a very short distance is degenerate; it is + treated as a point. + + exact changes the equality test. If true, returns true only if p1 equals p2. + If false, returns true if p1 equals or nearly equals p2. + + @param p1 line start point + @param p2 line end point + @param exact if false, allow nearly equals + @return true if line is degenerate; its length is effectively zero + + example: https://fiddle.skia.org/c/@Path_IsLineDegenerate + */ + static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2, bool exact); + + /** Tests if quad is degenerate. + Quad with no length or that moves a very short distance is degenerate; it is + treated as a point. + + @param p1 quad start point + @param p2 quad control point + @param p3 quad end point + @param exact if true, returns true only if p1, p2, and p3 are equal; + if false, returns true if p1, p2, and p3 are equal or nearly equal + @return true if quad is degenerate; its length is effectively zero + */ + static bool IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2, + const SkPoint& p3, bool exact); + + /** Tests if cubic is degenerate. + Cubic with no length or that moves a very short distance is degenerate; it is + treated as a point. + + @param p1 cubic start point + @param p2 cubic control point 1 + @param p3 cubic control point 2 + @param p4 cubic end point + @param exact if true, returns true only if p1, p2, p3, and p4 are equal; + if false, returns true if p1, p2, p3, and p4 are equal or nearly equal + @return true if cubic is degenerate; its length is effectively zero + */ + static bool IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2, + const SkPoint& p3, const SkPoint& p4, bool exact); + + /** Returns true if SkPath contains only one line; + SkPath::Verb array has two entries: kMove_Verb, kLine_Verb. + If SkPath contains one line and line is not nullptr, line is set to + line start point and line end point. + Returns false if SkPath is not one line; line is unaltered. + + @param line storage for line. May be nullptr + @return true if SkPath contains exactly one line + + example: https://fiddle.skia.org/c/@Path_isLine + */ + bool isLine(SkPoint line[2]) const; + + /** Returns the number of points in SkPath. + SkPoint count is initially zero. + + @return SkPath SkPoint array length + + example: https://fiddle.skia.org/c/@Path_countPoints + */ + int countPoints() const; + + /** Returns SkPoint at index in SkPoint array. Valid range for index is + 0 to countPoints() - 1. + Returns (0, 0) if index is out of range. + + @param index SkPoint array element selector + @return SkPoint array value or (0, 0) + + example: https://fiddle.skia.org/c/@Path_getPoint + */ + SkPoint getPoint(int index) const; + + /** Returns number of points in SkPath. Up to max points are copied. + points may be nullptr; then, max must be zero. + If max is greater than number of points, excess points storage is unaltered. + + @param points storage for SkPath SkPoint array. May be nullptr + @param max maximum to copy; must be greater than or equal to zero + @return SkPath SkPoint array length + + example: https://fiddle.skia.org/c/@Path_getPoints + */ + int getPoints(SkPoint points[], int max) const; + + /** Returns the number of verbs: kMove_Verb, kLine_Verb, kQuad_Verb, kConic_Verb, + kCubic_Verb, and kClose_Verb; added to SkPath. + + @return length of verb array + + example: https://fiddle.skia.org/c/@Path_countVerbs + */ + int countVerbs() const; + + /** Returns the number of verbs in the path. Up to max verbs are copied. The + verbs are copied as one byte per verb. + + @param verbs storage for verbs, may be nullptr + @param max maximum number to copy into verbs + @return the actual number of verbs in the path + + example: https://fiddle.skia.org/c/@Path_getVerbs + */ + int getVerbs(uint8_t verbs[], int max) const; + + /** Returns the approximate byte size of the SkPath in memory. + + @return approximate size + */ + size_t approximateBytesUsed() const; + + /** Exchanges the verb array, SkPoint array, weights, and SkPath::FillType with other. + Cached state is also exchanged. swap() internally exchanges pointers, so + it is lightweight and does not allocate memory. + + swap() usage has largely been replaced by operator=(const SkPath& path). + SkPath do not copy their content on assignment until they are written to, + making assignment as efficient as swap(). + + @param other SkPath exchanged by value + + example: https://fiddle.skia.org/c/@Path_swap + */ + void swap(SkPath& other); + + /** Returns minimum and maximum axes values of SkPoint array. + Returns (0, 0, 0, 0) if SkPath contains no points. Returned bounds width and height may + be larger or smaller than area affected when SkPath is drawn. + + SkRect returned includes all SkPoint added to SkPath, including SkPoint associated with + kMove_Verb that define empty contours. + + @return bounds of all SkPoint in SkPoint array + */ + const SkRect& getBounds() const; + + /** Updates internal bounds so that subsequent calls to getBounds() are instantaneous. + Unaltered copies of SkPath may also access cached bounds through getBounds(). + + For now, identical to calling getBounds() and ignoring the returned value. + + Call to prepare SkPath subsequently drawn from multiple threads, + to avoid a race condition where each draw separately computes the bounds. + */ + void updateBoundsCache() const { + // for now, just calling getBounds() is sufficient + this->getBounds(); + } + + /** Returns minimum and maximum axes values of the lines and curves in SkPath. + Returns (0, 0, 0, 0) if SkPath contains no points. + Returned bounds width and height may be larger or smaller than area affected + when SkPath is drawn. + + Includes SkPoint associated with kMove_Verb that define empty + contours. + + Behaves identically to getBounds() when SkPath contains + only lines. If SkPath contains curves, computed bounds includes + the maximum extent of the quad, conic, or cubic; is slower than getBounds(); + and unlike getBounds(), does not cache the result. + + @return tight bounds of curves in SkPath + + example: https://fiddle.skia.org/c/@Path_computeTightBounds + */ + SkRect computeTightBounds() const; + + /** Returns true if rect is contained by SkPath. + May return false when rect is contained by SkPath. + + For now, only returns true if SkPath has one contour and is convex. + rect may share points and edges with SkPath and be contained. + Returns true if rect is empty, that is, it has zero width or height; and + the SkPoint or line described by rect is contained by SkPath. + + @param rect SkRect, line, or SkPoint checked for containment + @return true if rect is contained + + example: https://fiddle.skia.org/c/@Path_conservativelyContainsRect + */ + bool conservativelyContainsRect(const SkRect& rect) const; + + /** Grows SkPath verb array, SkPoint array, and conics to contain additional space. + May improve performance and use less memory by + reducing the number and size of allocations when creating SkPath. + + @param extraPtCount number of additional SkPoint to allocate + @param extraVerbCount number of additional verbs + @param extraConicCount number of additional conics + + example: https://fiddle.skia.org/c/@Path_incReserve + */ + void incReserve(int extraPtCount, int extraVerbCount = 0, int extraConicCount = 0); + +#ifdef SK_HIDE_PATH_EDIT_METHODS +private: +#endif + + /** Adds beginning of contour at SkPoint (x, y). + + @param x x-axis value of contour start + @param y y-axis value of contour start + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_moveTo + */ + SkPath& moveTo(SkScalar x, SkScalar y); + + /** Adds beginning of contour at SkPoint p. + + @param p contour start + @return reference to SkPath + */ + SkPath& moveTo(const SkPoint& p) { + return this->moveTo(p.fX, p.fY); + } + + /** Adds beginning of contour relative to last point. + If SkPath is empty, starts contour at (dx, dy). + Otherwise, start contour at last point offset by (dx, dy). + Function name stands for "relative move to". + + @param dx offset from last point to contour start on x-axis + @param dy offset from last point to contour start on y-axis + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_rMoveTo + */ + SkPath& rMoveTo(SkScalar dx, SkScalar dy); + + /** Adds line from last point to (x, y). If SkPath is empty, or last SkPath::Verb is + kClose_Verb, last point is set to (0, 0) before adding line. + + lineTo() appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed. + lineTo() then appends kLine_Verb to verb array and (x, y) to SkPoint array. + + @param x end of added line on x-axis + @param y end of added line on y-axis + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_lineTo + */ + SkPath& lineTo(SkScalar x, SkScalar y); + + /** Adds line from last point to SkPoint p. If SkPath is empty, or last SkPath::Verb is + kClose_Verb, last point is set to (0, 0) before adding line. + + lineTo() first appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed. + lineTo() then appends kLine_Verb to verb array and SkPoint p to SkPoint array. + + @param p end SkPoint of added line + @return reference to SkPath + */ + SkPath& lineTo(const SkPoint& p) { + return this->lineTo(p.fX, p.fY); + } + + /** Adds line from last point to vector (dx, dy). If SkPath is empty, or last SkPath::Verb is + kClose_Verb, last point is set to (0, 0) before adding line. + + Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed; + then appends kLine_Verb to verb array and line end to SkPoint array. + Line end is last point plus vector (dx, dy). + Function name stands for "relative line to". + + @param dx offset from last point to line end on x-axis + @param dy offset from last point to line end on y-axis + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_rLineTo + example: https://fiddle.skia.org/c/@Quad_a + example: https://fiddle.skia.org/c/@Quad_b + */ + SkPath& rLineTo(SkScalar dx, SkScalar dy); + + /** Adds quad from last point towards (x1, y1), to (x2, y2). + If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0) + before adding quad. + + Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed; + then appends kQuad_Verb to verb array; and (x1, y1), (x2, y2) + to SkPoint array. + + @param x1 control SkPoint of quad on x-axis + @param y1 control SkPoint of quad on y-axis + @param x2 end SkPoint of quad on x-axis + @param y2 end SkPoint of quad on y-axis + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_quadTo + */ + SkPath& quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2); + + /** Adds quad from last point towards SkPoint p1, to SkPoint p2. + If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0) + before adding quad. + + Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed; + then appends kQuad_Verb to verb array; and SkPoint p1, p2 + to SkPoint array. + + @param p1 control SkPoint of added quad + @param p2 end SkPoint of added quad + @return reference to SkPath + */ + SkPath& quadTo(const SkPoint& p1, const SkPoint& p2) { + return this->quadTo(p1.fX, p1.fY, p2.fX, p2.fY); + } + + /** Adds quad from last point towards vector (dx1, dy1), to vector (dx2, dy2). + If SkPath is empty, or last SkPath::Verb + is kClose_Verb, last point is set to (0, 0) before adding quad. + + Appends kMove_Verb to verb array and (0, 0) to SkPoint array, + if needed; then appends kQuad_Verb to verb array; and appends quad + control and quad end to SkPoint array. + Quad control is last point plus vector (dx1, dy1). + Quad end is last point plus vector (dx2, dy2). + Function name stands for "relative quad to". + + @param dx1 offset from last point to quad control on x-axis + @param dy1 offset from last point to quad control on y-axis + @param dx2 offset from last point to quad end on x-axis + @param dy2 offset from last point to quad end on y-axis + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Conic_Weight_a + example: https://fiddle.skia.org/c/@Conic_Weight_b + example: https://fiddle.skia.org/c/@Conic_Weight_c + example: https://fiddle.skia.org/c/@Path_rQuadTo + */ + SkPath& rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2); + + /** Adds conic from last point towards (x1, y1), to (x2, y2), weighted by w. + If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0) + before adding conic. + + Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed. + + If w is finite and not one, appends kConic_Verb to verb array; + and (x1, y1), (x2, y2) to SkPoint array; and w to conic weights. + + If w is one, appends kQuad_Verb to verb array, and + (x1, y1), (x2, y2) to SkPoint array. + + If w is not finite, appends kLine_Verb twice to verb array, and + (x1, y1), (x2, y2) to SkPoint array. + + @param x1 control SkPoint of conic on x-axis + @param y1 control SkPoint of conic on y-axis + @param x2 end SkPoint of conic on x-axis + @param y2 end SkPoint of conic on y-axis + @param w weight of added conic + @return reference to SkPath + */ + SkPath& conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, + SkScalar w); + + /** Adds conic from last point towards SkPoint p1, to SkPoint p2, weighted by w. + If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0) + before adding conic. + + Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed. + + If w is finite and not one, appends kConic_Verb to verb array; + and SkPoint p1, p2 to SkPoint array; and w to conic weights. + + If w is one, appends kQuad_Verb to verb array, and SkPoint p1, p2 + to SkPoint array. + + If w is not finite, appends kLine_Verb twice to verb array, and + SkPoint p1, p2 to SkPoint array. + + @param p1 control SkPoint of added conic + @param p2 end SkPoint of added conic + @param w weight of added conic + @return reference to SkPath + */ + SkPath& conicTo(const SkPoint& p1, const SkPoint& p2, SkScalar w) { + return this->conicTo(p1.fX, p1.fY, p2.fX, p2.fY, w); + } + + /** Adds conic from last point towards vector (dx1, dy1), to vector (dx2, dy2), + weighted by w. If SkPath is empty, or last SkPath::Verb + is kClose_Verb, last point is set to (0, 0) before adding conic. + + Appends kMove_Verb to verb array and (0, 0) to SkPoint array, + if needed. + + If w is finite and not one, next appends kConic_Verb to verb array, + and w is recorded as conic weight; otherwise, if w is one, appends + kQuad_Verb to verb array; or if w is not finite, appends kLine_Verb + twice to verb array. + + In all cases appends SkPoint control and end to SkPoint array. + control is last point plus vector (dx1, dy1). + end is last point plus vector (dx2, dy2). + + Function name stands for "relative conic to". + + @param dx1 offset from last point to conic control on x-axis + @param dy1 offset from last point to conic control on y-axis + @param dx2 offset from last point to conic end on x-axis + @param dy2 offset from last point to conic end on y-axis + @param w weight of added conic + @return reference to SkPath + */ + SkPath& rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2, + SkScalar w); + + /** Adds cubic from last point towards (x1, y1), then towards (x2, y2), ending at + (x3, y3). If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to + (0, 0) before adding cubic. + + Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed; + then appends kCubic_Verb to verb array; and (x1, y1), (x2, y2), (x3, y3) + to SkPoint array. + + @param x1 first control SkPoint of cubic on x-axis + @param y1 first control SkPoint of cubic on y-axis + @param x2 second control SkPoint of cubic on x-axis + @param y2 second control SkPoint of cubic on y-axis + @param x3 end SkPoint of cubic on x-axis + @param y3 end SkPoint of cubic on y-axis + @return reference to SkPath + */ + SkPath& cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, + SkScalar x3, SkScalar y3); + + /** Adds cubic from last point towards SkPoint p1, then towards SkPoint p2, ending at + SkPoint p3. If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to + (0, 0) before adding cubic. + + Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed; + then appends kCubic_Verb to verb array; and SkPoint p1, p2, p3 + to SkPoint array. + + @param p1 first control SkPoint of cubic + @param p2 second control SkPoint of cubic + @param p3 end SkPoint of cubic + @return reference to SkPath + */ + SkPath& cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3) { + return this->cubicTo(p1.fX, p1.fY, p2.fX, p2.fY, p3.fX, p3.fY); + } + + /** Adds cubic from last point towards vector (dx1, dy1), then towards + vector (dx2, dy2), to vector (dx3, dy3). + If SkPath is empty, or last SkPath::Verb + is kClose_Verb, last point is set to (0, 0) before adding cubic. + + Appends kMove_Verb to verb array and (0, 0) to SkPoint array, + if needed; then appends kCubic_Verb to verb array; and appends cubic + control and cubic end to SkPoint array. + Cubic control is last point plus vector (dx1, dy1). + Cubic end is last point plus vector (dx2, dy2). + Function name stands for "relative cubic to". + + @param dx1 offset from last point to first cubic control on x-axis + @param dy1 offset from last point to first cubic control on y-axis + @param dx2 offset from last point to second cubic control on x-axis + @param dy2 offset from last point to second cubic control on y-axis + @param dx3 offset from last point to cubic end on x-axis + @param dy3 offset from last point to cubic end on y-axis + @return reference to SkPath + */ + SkPath& rCubicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2, + SkScalar dx3, SkScalar dy3); + + /** Appends arc to SkPath. 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 SkPath last SkPoint to initial arc SkPoint if forceMoveTo + is false and SkPath 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 startAngle starting angle of arc in degrees + @param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360 + @param forceMoveTo true to start a new contour with arc + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_arcTo + */ + SkPath& arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, 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 (x1, y1), and tangent from (x1, y1) to (x2, y2). Arc + is part of circle sized to radius, positioned so it touches both tangent lines. + + If last Path Point does not start Arc, arcTo appends connecting Line to Path. + The length of Vector from (x1, y1) to (x2, y2) 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 Path Point to (x1, y1). + + arcTo appends at most one Line and one conic. + arcTo implements the functionality of PostScript arct and HTML Canvas arcTo. + + @param x1 x-axis value common to pair of tangents + @param y1 y-axis value common to pair of tangents + @param x2 x-axis value end of second tangent + @param y2 y-axis value end of second tangent + @param radius distance from arc to circle center + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_arcTo_2_a + example: https://fiddle.skia.org/c/@Path_arcTo_2_b + example: https://fiddle.skia.org/c/@Path_arcTo_2_c + */ + SkPath& arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius); + + /** 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 + */ + SkPath& arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius) { + return this->arcTo(p1.fX, p1.fY, p2.fX, p2.fY, radius); + } + + /** \enum SkPath::ArcSize + Four oval parts with radii (rx, ry) start at last SkPath SkPoint and ends at (x, y). + ArcSize and Direction select one of the four oval parts. + */ + 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 conics weighted to + describe part of oval with radii (rx, ry) rotated by xAxisRotate degrees. Arc + curves from last SkPath SkPoint to (x, y), 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 (x, y) if + either radii are zero, or if last SkPath SkPoint equals (x, y). arcTo() scales radii + (rx, ry) to fit last SkPath SkPoint and (x, y) if both are greater than zero but + too small. + + 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 rx radius on x-axis before x-axis rotation + @param ry radius on y-axis 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 x end of arc + @param y end of arc + @return reference to SkPath + */ + SkPath& arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc, + SkPathDirection sweep, SkScalar x, SkScalar y); + + /** 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 + */ + SkPath& arcTo(const SkPoint r, SkScalar xAxisRotate, ArcSize largeArc, SkPathDirection sweep, + const SkPoint xy) { + return this->arcTo(r.fX, r.fY, xAxisRotate, largeArc, sweep, xy.fX, xy.fY); + } + + /** Appends arc to SkPath, relative to last SkPath SkPoint. Arc is implemented by one or + more conic, weighted to describe part of oval with radii (rx, ry) rotated by + xAxisRotate degrees. Arc curves from last SkPath SkPoint to relative end SkPoint: + (dx, dy), choosing one of four possible routes: clockwise or + counterclockwise, and smaller or larger. If SkPath is empty, the start arc SkPoint + is (0, 0). + + Arc sweep is always less than 360 degrees. arcTo() appends line to end SkPoint + if either radii are zero, or if last SkPath SkPoint equals end SkPoint. + arcTo() scales radii (rx, ry) to fit last SkPath SkPoint and end SkPoint 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 rx radius before x-axis rotation + @param ry radius 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 dx x-axis offset end of arc from last SkPath SkPoint + @param dy y-axis offset end of arc from last SkPath SkPoint + @return reference to SkPath + */ + SkPath& rArcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc, + SkPathDirection sweep, SkScalar dx, SkScalar dy); + + /** Appends kClose_Verb to SkPath. A closed contour connects the first and last SkPoint + with line, forming a continuous loop. Open and closed contour draw the same + with SkPaint::kFill_Style. With SkPaint::kStroke_Style, open contour draws + SkPaint::Cap at contour start and end; closed contour draws + SkPaint::Join at contour start and end. + + close() has no effect if SkPath is empty or last SkPath SkPath::Verb is kClose_Verb. + + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_close + */ + SkPath& close(); + +#ifdef SK_HIDE_PATH_EDIT_METHODS +public: +#endif + + /** Approximates conic with quad array. Conic is constructed from start SkPoint p0, + control SkPoint p1, end SkPoint p2, and weight w. + Quad array is stored in pts; this storage is supplied by caller. + Maximum quad count is 2 to the pow2. + Every third point in array shares last SkPoint of previous quad and first SkPoint of + next quad. Maximum pts storage size is given by: + (1 + 2 * (1 << pow2)) * sizeof(SkPoint). + + Returns quad count used the approximation, which may be smaller + than the number requested. + + conic weight determines the amount of influence conic control point has on the curve. + w less than one represents an elliptical section. w greater than one represents + a hyperbolic section. w equal to one represents a parabolic section. + + Two quad curves are sufficient to approximate an elliptical conic with a sweep + of up to 90 degrees; in this case, set pow2 to one. + + @param p0 conic start SkPoint + @param p1 conic control SkPoint + @param p2 conic end SkPoint + @param w conic weight + @param pts storage for quad array + @param pow2 quad count, as power of two, normally 0 to 5 (1 to 32 quad curves) + @return number of quad curves written to pts + */ + static int ConvertConicToQuads(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2, + SkScalar w, SkPoint pts[], int pow2); + + /** Returns true if SkPath is equivalent to SkRect when filled. + If false: rect, isClosed, and direction are unchanged. + If true: rect, isClosed, and direction are written to if not nullptr. + + rect may be smaller than the SkPath bounds. SkPath bounds may include kMove_Verb points + that do not alter the area drawn by the returned rect. + + @param rect storage for bounds of SkRect; may be nullptr + @param isClosed storage set to true if SkPath is closed; may be nullptr + @param direction storage set to SkRect direction; may be nullptr + @return true if SkPath contains SkRect + + example: https://fiddle.skia.org/c/@Path_isRect + */ + bool isRect(SkRect* rect, bool* isClosed = nullptr, SkPathDirection* direction = nullptr) const; + +#ifdef SK_HIDE_PATH_EDIT_METHODS +private: +#endif + + /** Adds a new contour to the path, defined by the rect, and wound in the + specified direction. The verbs added to the path will be: + + kMove, kLine, kLine, kLine, kClose + + start specifies which corner to begin the contour: + 0: upper-left corner + 1: upper-right corner + 2: lower-right corner + 3: lower-left corner + + This start point also acts as the implied beginning of the subsequent, + contour, if it does not have an explicit moveTo(). e.g. + + path.addRect(...) + // if we don't say moveTo() here, we will use the rect's start point + path.lineTo(...) + + @param rect SkRect to add as a closed contour + @param dir SkPath::Direction to orient the new contour + @param start initial corner of SkRect to add + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_addRect_2 + */ + SkPath& addRect(const SkRect& rect, SkPathDirection dir, unsigned start); + + SkPath& addRect(const SkRect& rect, SkPathDirection dir = SkPathDirection::kCW) { + return this->addRect(rect, dir, 0); + } + + SkPath& addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom, + SkPathDirection dir = SkPathDirection::kCW) { + return this->addRect({left, top, right, bottom}, dir, 0); + } + + /** Adds oval to path, appending kMove_Verb, four kConic_Verb, and kClose_Verb. + Oval is upright ellipse bounded by SkRect oval with radii equal to half oval width + and half oval height. Oval begins at (oval.fRight, oval.centerY()) and continues + clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction. + + @param oval bounds of ellipse added + @param dir SkPath::Direction to wind ellipse + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_addOval + */ + SkPath& addOval(const SkRect& oval, SkPathDirection dir = SkPathDirection::kCW); + + /** Adds oval to SkPath, appending kMove_Verb, four kConic_Verb, and kClose_Verb. + Oval is upright ellipse bounded by SkRect oval with radii equal to half oval width + and half oval height. Oval begins at start and continues + clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction. + + @param oval bounds of ellipse added + @param dir SkPath::Direction to wind ellipse + @param start index of initial point of ellipse + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_addOval_2 + */ + SkPath& addOval(const SkRect& oval, SkPathDirection dir, unsigned start); + + /** Experimental, subject to change or removal. + + Adds an "open" oval to SkPath. This follows canvas2D semantics: The oval is not + a separate contour. If the path was empty, then kMove_Verb is appended. Otherwise, + kLine_Verb is appended. Four kConic_Verbs are appended. kClose_Verb is not appended. + */ + SkPath& addOpenOval(const SkRect& oval, SkPathDirection dir, unsigned start); + + /** Adds circle centered at (x, y) of size radius to SkPath, appending kMove_Verb, + four kConic_Verb, and kClose_Verb. Circle begins at: (x + radius, y), continuing + clockwise if dir is kCW_Direction, and counterclockwise if dir is kCCW_Direction. + + Has no effect if radius is zero or negative. + + @param x center of circle + @param y center of circle + @param radius distance from center to edge + @param dir SkPath::Direction to wind circle + @return reference to SkPath + */ + SkPath& addCircle(SkScalar x, SkScalar y, SkScalar radius, + SkPathDirection dir = SkPathDirection::kCW); + + /** Appends arc to SkPath, 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 startAngle starting angle of arc in degrees + @param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360 + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_addArc + */ + SkPath& addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle); + + /** Appends SkRRect to SkPath, creating a new closed contour. SkRRect has bounds + equal to rect; each corner is 90 degrees of an ellipse with radii (rx, ry). If + dir is kCW_Direction, SkRRect starts at top-left of the lower-left corner and + winds clockwise. If dir is kCCW_Direction, SkRRect starts at the bottom-left + of the upper-left corner and winds counterclockwise. + + If either rx or ry is too large, rx and ry are scaled uniformly until the + corners fit. If rx or ry is less than or equal to zero, addRoundRect() appends + SkRect rect to SkPath. + + After appending, SkPath may be empty, or may contain: SkRect, oval, or SkRRect. + + @param rect bounds of SkRRect + @param rx x-axis radius of rounded corners on the SkRRect + @param ry y-axis radius of rounded corners on the SkRRect + @param dir SkPath::Direction to wind SkRRect + @return reference to SkPath + */ + SkPath& addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, + SkPathDirection dir = SkPathDirection::kCW); + + /** Appends SkRRect to SkPath, creating a new closed contour. SkRRect has bounds + equal to rect; each corner is 90 degrees of an ellipse with radii from the + array. + + @param rect bounds of SkRRect + @param radii array of 8 SkScalar values, a radius pair for each corner + @param dir SkPath::Direction to wind SkRRect + @return reference to SkPath + */ + SkPath& addRoundRect(const SkRect& rect, const SkScalar radii[], + SkPathDirection dir = SkPathDirection::kCW); + + /** Adds rrect to SkPath, creating a new closed contour. If + dir is kCW_Direction, rrect starts at top-left of the lower-left corner and + winds clockwise. If dir is kCCW_Direction, rrect starts at the bottom-left + of the upper-left corner and winds counterclockwise. + + After appending, SkPath may be empty, or may contain: SkRect, oval, or SkRRect. + + @param rrect bounds and radii of rounded rectangle + @param dir SkPath::Direction to wind SkRRect + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_addRRect + */ + SkPath& addRRect(const SkRRect& rrect, SkPathDirection dir = SkPathDirection::kCW); + + /** Adds rrect to SkPath, creating a new closed contour. If dir is kCW_Direction, rrect + winds clockwise; if dir is kCCW_Direction, rrect winds counterclockwise. + start determines the first point of rrect to add. + + @param rrect bounds and radii of rounded rectangle + @param dir SkPath::Direction to wind SkRRect + @param start index of initial point of SkRRect + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_addRRect_2 + */ + SkPath& addRRect(const SkRRect& rrect, SkPathDirection dir, unsigned start); + + /** Adds contour created from line array, adding (count - 1) line segments. + Contour added starts at pts[0], then adds a line for every additional SkPoint + in pts array. If close is true, appends kClose_Verb to SkPath, connecting + pts[count - 1] and pts[0]. + + If count is zero, append kMove_Verb to path. + Has no effect if count is less than one. + + @param pts array of line sharing end and start SkPoint + @param count length of SkPoint array + @param close true to add line connecting contour end and start + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_addPoly + */ + SkPath& addPoly(const SkPoint pts[], int count, bool close); + + /** Adds contour created from list. Contour added starts at list[0], then adds a line + for every additional SkPoint in list. If close is true, appends kClose_Verb to SkPath, + connecting last and first SkPoint in list. + + If list is empty, append kMove_Verb to path. + + @param list array of SkPoint + @param close true to add line connecting contour end and start + @return reference to SkPath + */ + SkPath& addPoly(const std::initializer_list& list, bool close) { + return this->addPoly(list.begin(), SkToInt(list.size()), close); + } + +#ifdef SK_HIDE_PATH_EDIT_METHODS +public: +#endif + + /** \enum SkPath::AddPathMode + AddPathMode chooses how addPath() appends. Adding one SkPath to another can extend + the last contour or start a new contour. + */ + enum AddPathMode { + /** Contours are appended to the destination path as new contours. + */ + kAppend_AddPathMode, + /** Extends the last contour of the destination path with the first countour + of the source path, connecting them with a line. If the last contour is + closed, a new empty contour starting at its start point is extended instead. + If the destination path is empty, the result is the source path. + The last path of the result is closed only if the last path of the source is. + */ + kExtend_AddPathMode, + }; + + /** Appends src to SkPath, offset by (dx, dy). + + If mode is kAppend_AddPathMode, src verb array, SkPoint array, and conic weights are + added unaltered. If mode is kExtend_AddPathMode, add line before appending + verbs, SkPoint, and conic weights. + + @param src SkPath verbs, SkPoint, and conic weights to add + @param dx offset added to src SkPoint array x-axis coordinates + @param dy offset added to src SkPoint array y-axis coordinates + @param mode kAppend_AddPathMode or kExtend_AddPathMode + @return reference to SkPath + */ + SkPath& addPath(const SkPath& src, SkScalar dx, SkScalar dy, + AddPathMode mode = kAppend_AddPathMode); + + /** Appends src to SkPath. + + If mode is kAppend_AddPathMode, src verb array, SkPoint array, and conic weights are + added unaltered. If mode is kExtend_AddPathMode, add line before appending + verbs, SkPoint, and conic weights. + + @param src SkPath verbs, SkPoint, and conic weights to add + @param mode kAppend_AddPathMode or kExtend_AddPathMode + @return reference to SkPath + */ + SkPath& addPath(const SkPath& src, AddPathMode mode = kAppend_AddPathMode) { + SkMatrix m; + m.reset(); + return this->addPath(src, m, mode); + } + + /** Appends src to SkPath, transformed by matrix. Transformed curves may have different + verbs, SkPoint, and conic weights. + + If mode is kAppend_AddPathMode, src verb array, SkPoint array, and conic weights are + added unaltered. If mode is kExtend_AddPathMode, add line before appending + verbs, SkPoint, and conic weights. + + @param src SkPath verbs, SkPoint, and conic weights to add + @param matrix transform applied to src + @param mode kAppend_AddPathMode or kExtend_AddPathMode + @return reference to SkPath + */ + SkPath& addPath(const SkPath& src, const SkMatrix& matrix, + AddPathMode mode = kAppend_AddPathMode); + + /** Appends src to SkPath, from back to front. + Reversed src always appends a new contour to SkPath. + + @param src SkPath verbs, SkPoint, and conic weights to add + @return reference to SkPath + + example: https://fiddle.skia.org/c/@Path_reverseAddPath + */ + SkPath& reverseAddPath(const SkPath& src); + + /** Offsets SkPoint array by (dx, dy). Offset SkPath replaces dst. + If dst is nullptr, SkPath is replaced by offset data. + + @param dx offset added to SkPoint array x-axis coordinates + @param dy offset added to SkPoint array y-axis coordinates + @param dst overwritten, translated copy of SkPath; may be nullptr + + example: https://fiddle.skia.org/c/@Path_offset + */ + void offset(SkScalar dx, SkScalar dy, SkPath* dst) const; + + /** Offsets SkPoint array by (dx, dy). SkPath is replaced by offset data. + + @param dx offset added to SkPoint array x-axis coordinates + @param dy offset added to SkPoint array y-axis coordinates + */ + SkPath& offset(SkScalar dx, SkScalar dy) { + this->offset(dx, dy, this); + return *this; + } + + /** Transforms verb array, SkPoint array, and weight by matrix. + transform may change verbs and increase their number. + Transformed SkPath replaces dst; if dst is nullptr, original data + is replaced. + + @param matrix SkMatrix to apply to SkPath + @param dst overwritten, transformed copy of SkPath; may be nullptr + @param pc whether to apply perspective clipping + + example: https://fiddle.skia.org/c/@Path_transform + */ + void transform(const SkMatrix& matrix, SkPath* dst, + SkApplyPerspectiveClip pc = SkApplyPerspectiveClip::kYes) const; + + /** Transforms verb array, SkPoint array, and weight by matrix. + transform may change verbs and increase their number. + SkPath is replaced by transformed data. + + @param matrix SkMatrix to apply to SkPath + @param pc whether to apply perspective clipping + */ + SkPath& transform(const SkMatrix& matrix, + SkApplyPerspectiveClip pc = SkApplyPerspectiveClip::kYes) { + this->transform(matrix, this, pc); + return *this; + } + + SkPath makeTransform(const SkMatrix& m, + SkApplyPerspectiveClip pc = SkApplyPerspectiveClip::kYes) const { + SkPath dst; + this->transform(m, &dst, pc); + return dst; + } + + SkPath makeScale(SkScalar sx, SkScalar sy) { + return this->makeTransform(SkMatrix::Scale(sx, sy), SkApplyPerspectiveClip::kNo); + } + + /** Returns last point on SkPath in lastPt. Returns false if SkPoint array is empty, + storing (0, 0) if lastPt is not nullptr. + + @param lastPt storage for final SkPoint in SkPoint array; may be nullptr + @return true if SkPoint array contains one or more SkPoint + + example: https://fiddle.skia.org/c/@Path_getLastPt + */ + bool getLastPt(SkPoint* lastPt) const; + + /** Sets last point to (x, y). If SkPoint array is empty, append kMove_Verb to + verb array and append (x, y) to SkPoint array. + + @param x set x-axis value of last point + @param y set y-axis value of last point + + example: https://fiddle.skia.org/c/@Path_setLastPt + */ + void setLastPt(SkScalar x, SkScalar y); + + /** Sets the last point on the path. If SkPoint array is empty, append kMove_Verb to + verb array and append p to SkPoint array. + + @param p set value of last point + */ + void setLastPt(const SkPoint& p) { + this->setLastPt(p.fX, p.fY); + } + + /** \enum SkPath::SegmentMask + SegmentMask constants correspond to each drawing Verb type in SkPath; for + instance, if SkPath only contains lines, only the kLine_SegmentMask bit is set. + */ + enum SegmentMask { + kLine_SegmentMask = kLine_SkPathSegmentMask, + kQuad_SegmentMask = kQuad_SkPathSegmentMask, + kConic_SegmentMask = kConic_SkPathSegmentMask, + kCubic_SegmentMask = kCubic_SkPathSegmentMask, + }; + + /** Returns a mask, where each set bit corresponds to a SegmentMask constant + if SkPath contains one or more verbs of that type. + Returns zero if SkPath contains no lines, or curves: quads, conics, or cubics. + + getSegmentMasks() returns a cached result; it is very fast. + + @return SegmentMask bits or zero + */ + uint32_t getSegmentMasks() const; + + /** \enum SkPath::Verb + Verb instructs SkPath how to interpret one or more SkPoint and optional conic weight; + manage contour, and terminate SkPath. + */ + enum Verb { + kMove_Verb = static_cast(SkPathVerb::kMove), + kLine_Verb = static_cast(SkPathVerb::kLine), + kQuad_Verb = static_cast(SkPathVerb::kQuad), + kConic_Verb = static_cast(SkPathVerb::kConic), + kCubic_Verb = static_cast(SkPathVerb::kCubic), + kClose_Verb = static_cast(SkPathVerb::kClose), + kDone_Verb = kClose_Verb + 1 + }; + + /** \class SkPath::Iter + Iterates through verb array, and associated SkPoint array and conic weight. + Provides options to treat open contours as closed, and to ignore + degenerate data. + */ + class SK_API Iter { + public: + + /** Initializes SkPath::Iter with an empty SkPath. next() on SkPath::Iter returns + kDone_Verb. + Call setPath to initialize SkPath::Iter at a later time. + + @return SkPath::Iter of empty SkPath + + example: https://fiddle.skia.org/c/@Path_Iter_Iter + */ + Iter(); + + /** Sets SkPath::Iter to return elements of verb array, SkPoint array, and conic weight in + path. If forceClose is true, SkPath::Iter will add kLine_Verb and kClose_Verb after each + open contour. path is not altered. + + @param path SkPath to iterate + @param forceClose true if open contours generate kClose_Verb + @return SkPath::Iter of path + + example: https://fiddle.skia.org/c/@Path_Iter_const_SkPath + */ + Iter(const SkPath& path, bool forceClose); + + /** Sets SkPath::Iter to return elements of verb array, SkPoint array, and conic weight in + path. If forceClose is true, SkPath::Iter will add kLine_Verb and kClose_Verb after each + open contour. path is not altered. + + @param path SkPath to iterate + @param forceClose true if open contours generate kClose_Verb + + example: https://fiddle.skia.org/c/@Path_Iter_setPath + */ + void setPath(const SkPath& path, bool forceClose); + + /** Returns next SkPath::Verb in verb array, and advances SkPath::Iter. + When verb array is exhausted, returns kDone_Verb. + + Zero to four SkPoint are stored in pts, depending on the returned SkPath::Verb. + + @param pts storage for SkPoint data describing returned SkPath::Verb + @return next SkPath::Verb from verb array + + example: https://fiddle.skia.org/c/@Path_RawIter_next + */ + Verb next(SkPoint pts[4]); + + /** Returns conic weight if next() returned kConic_Verb. + + If next() has not been called, or next() did not return kConic_Verb, + result is undefined. + + @return conic weight for conic SkPoint returned by next() + */ + SkScalar conicWeight() const { return *fConicWeights; } + + /** Returns true if last kLine_Verb returned by next() was generated + by kClose_Verb. When true, the end point returned by next() is + also the start point of contour. + + If next() has not been called, or next() did not return kLine_Verb, + result is undefined. + + @return true if last kLine_Verb was generated by kClose_Verb + */ + bool isCloseLine() const { return SkToBool(fCloseLine); } + + /** Returns true if subsequent calls to next() return kClose_Verb before returning + kMove_Verb. if true, contour SkPath::Iter is processing may end with kClose_Verb, or + SkPath::Iter may have been initialized with force close set to true. + + @return true if contour is closed + + example: https://fiddle.skia.org/c/@Path_Iter_isClosedContour + */ + bool isClosedContour() const; + + private: + const SkPoint* fPts; + const uint8_t* fVerbs; + const uint8_t* fVerbStop; + const SkScalar* fConicWeights; + SkPoint fMoveTo; + SkPoint fLastPt; + bool fForceClose; + bool fNeedClose; + bool fCloseLine; + + Verb autoClose(SkPoint pts[2]); + }; + +private: + /** \class SkPath::RangeIter + Iterates through a raw range of path verbs, points, and conics. All values are returned + unaltered. + + NOTE: This class will be moved into SkPathPriv once RangeIter is removed. + */ + class RangeIter { + public: + RangeIter() = default; + RangeIter(const uint8_t* verbs, const SkPoint* points, const SkScalar* weights) + : fVerb(verbs), fPoints(points), fWeights(weights) { + SkDEBUGCODE(fInitialPoints = fPoints;) + } + bool operator!=(const RangeIter& that) const { + return fVerb != that.fVerb; + } + bool operator==(const RangeIter& that) const { + return fVerb == that.fVerb; + } + RangeIter& operator++() { + auto verb = static_cast(*fVerb++); + fPoints += pts_advance_after_verb(verb); + if (verb == SkPathVerb::kConic) { + ++fWeights; + } + return *this; + } + RangeIter operator++(int) { + RangeIter copy = *this; + this->operator++(); + return copy; + } + SkPathVerb peekVerb() const { + return static_cast(*fVerb); + } + std::tuple operator*() const { + SkPathVerb verb = this->peekVerb(); + // We provide the starting point for beziers by peeking backwards from the current + // point, which works fine as long as there is always a kMove before any geometry. + // (SkPath::injectMoveToIfNeeded should have guaranteed this to be the case.) + int backset = pts_backset_for_verb(verb); + SkASSERT(fPoints + backset >= fInitialPoints); + return {verb, fPoints + backset, fWeights}; + } + private: + constexpr static int pts_advance_after_verb(SkPathVerb verb) { + switch (verb) { + case SkPathVerb::kMove: return 1; + case SkPathVerb::kLine: return 1; + case SkPathVerb::kQuad: return 2; + case SkPathVerb::kConic: return 2; + case SkPathVerb::kCubic: return 3; + case SkPathVerb::kClose: return 0; + } + SkUNREACHABLE; + } + constexpr static int pts_backset_for_verb(SkPathVerb verb) { + switch (verb) { + case SkPathVerb::kMove: return 0; + case SkPathVerb::kLine: return -1; + case SkPathVerb::kQuad: return -1; + case SkPathVerb::kConic: return -1; + case SkPathVerb::kCubic: return -1; + case SkPathVerb::kClose: return -1; + } + SkUNREACHABLE; + } + const uint8_t* fVerb = nullptr; + const SkPoint* fPoints = nullptr; + const SkScalar* fWeights = nullptr; + SkDEBUGCODE(const SkPoint* fInitialPoints = nullptr;) + }; +public: + + /** \class SkPath::RawIter + Use Iter instead. This class will soon be removed and RangeIter will be made private. + */ + class SK_API RawIter { + public: + + /** Initializes RawIter with an empty SkPath. next() on RawIter returns kDone_Verb. + Call setPath to initialize SkPath::Iter at a later time. + + @return RawIter of empty SkPath + */ + RawIter() {} + + /** Sets RawIter to return elements of verb array, SkPoint array, and conic weight in path. + + @param path SkPath to iterate + @return RawIter of path + */ + RawIter(const SkPath& path) { + setPath(path); + } + + /** Sets SkPath::Iter to return elements of verb array, SkPoint array, and conic weight in + path. + + @param path SkPath to iterate + */ + void setPath(const SkPath&); + + /** Returns next SkPath::Verb in verb array, and advances RawIter. + When verb array is exhausted, returns kDone_Verb. + Zero to four SkPoint are stored in pts, depending on the returned SkPath::Verb. + + @param pts storage for SkPoint data describing returned SkPath::Verb + @return next SkPath::Verb from verb array + */ + Verb next(SkPoint[4]); + + /** Returns next SkPath::Verb, but does not advance RawIter. + + @return next SkPath::Verb from verb array + */ + Verb peek() const { + return (fIter != fEnd) ? static_cast(std::get<0>(*fIter)) : kDone_Verb; + } + + /** Returns conic weight if next() returned kConic_Verb. + + If next() has not been called, or next() did not return kConic_Verb, + result is undefined. + + @return conic weight for conic SkPoint returned by next() + */ + SkScalar conicWeight() const { + return fConicWeight; + } + + private: + RangeIter fIter; + RangeIter fEnd; + SkScalar fConicWeight = 0; + friend class SkPath; + + }; + + /** Returns true if the point (x, y) is contained by SkPath, taking into + account FillType. + + @param x x-axis value of containment test + @param y y-axis value of containment test + @return true if SkPoint is in SkPath + + example: https://fiddle.skia.org/c/@Path_contains + */ + bool contains(SkScalar x, SkScalar y) const; + + /** Writes text representation of SkPath to stream. If stream is nullptr, writes to + standard output. Set dumpAsHex true to generate exact binary representations + of floating point numbers used in SkPoint array and conic weights. + + @param stream writable SkWStream receiving SkPath text representation; may be nullptr + @param dumpAsHex true if SkScalar values are written as hexadecimal + + example: https://fiddle.skia.org/c/@Path_dump + */ + void dump(SkWStream* stream, bool dumpAsHex) const; + + void dump() const { this->dump(nullptr, false); } + void dumpHex() const { this->dump(nullptr, true); } + + // Like dump(), but outputs for the SkPath::Make() factory + void dumpArrays(SkWStream* stream, bool dumpAsHex) const; + void dumpArrays() const { this->dumpArrays(nullptr, false); } + + /** Writes SkPath to buffer, returning the number of bytes written. + Pass nullptr to obtain the storage size. + + Writes SkPath::FillType, verb array, SkPoint array, conic weight, and + additionally writes computed information like SkPath::Convexity and bounds. + + Use only be used in concert with readFromMemory(); + the format used for SkPath in memory is not guaranteed. + + @param buffer storage for SkPath; may be nullptr + @return size of storage required for SkPath; always a multiple of 4 + + example: https://fiddle.skia.org/c/@Path_writeToMemory + */ + size_t writeToMemory(void* buffer) const; + + /** Writes SkPath to buffer, returning the buffer written to, wrapped in SkData. + + serialize() writes SkPath::FillType, verb array, SkPoint array, conic weight, and + additionally writes computed information like SkPath::Convexity and bounds. + + serialize() should only be used in concert with readFromMemory(). + The format used for SkPath in memory is not guaranteed. + + @return SkPath data wrapped in SkData buffer + + example: https://fiddle.skia.org/c/@Path_serialize + */ + sk_sp serialize() const; + + /** Initializes SkPath from buffer of size length. Returns zero if the buffer is + data is inconsistent, or the length is too small. + + Reads SkPath::FillType, verb array, SkPoint array, conic weight, and + additionally reads computed information like SkPath::Convexity and bounds. + + Used only in concert with writeToMemory(); + the format used for SkPath in memory is not guaranteed. + + @param buffer storage for SkPath + @param length buffer size in bytes; must be multiple of 4 + @return number of bytes read, or zero on failure + + example: https://fiddle.skia.org/c/@Path_readFromMemory + */ + size_t readFromMemory(const void* buffer, size_t length); + + /** (See Skia bug 1762.) + Returns a non-zero, globally unique value. A different value is returned + if verb array, SkPoint array, or conic weight changes. + + Setting SkPath::FillType does not change generation identifier. + + Each time the path is modified, a different generation identifier will be returned. + SkPath::FillType does affect generation identifier on Android framework. + + @return non-zero, globally unique value + + example: https://fiddle.skia.org/c/@Path_getGenerationID + */ + uint32_t getGenerationID() const; + + /** Returns if SkPath data is consistent. Corrupt SkPath data is detected if + internal values are out of range or internal storage does not match + array dimensions. + + @return true if SkPath data is consistent + */ + bool isValid() const; + + using sk_is_trivially_relocatable = std::true_type; + +private: + SkPath(sk_sp, SkPathFillType, bool isVolatile, SkPathConvexity, + SkPathFirstDirection firstDirection); + + sk_sp fPathRef; + int fLastMoveToIndex; + mutable std::atomic fConvexity; // SkPathConvexity + mutable std::atomic fFirstDirection; // SkPathFirstDirection + uint8_t fFillType : 2; + uint8_t fIsVolatile : 1; + + static_assert(::sk_is_trivially_relocatable::value); + + /** Resets all fields other than fPathRef to their initial 'empty' values. + * Assumes the caller has already emptied fPathRef. + */ + void resetFields(); + + /** Sets all fields other than fPathRef to the values in 'that'. + * Assumes the caller has already set fPathRef. + * Doesn't change fGenerationID or fSourcePath on Android. + */ + void copyFields(const SkPath& that); + + size_t writeToMemoryAsRRect(void* buffer) const; + size_t readAsRRect(const void*, size_t); + size_t readFromMemory_EQ4Or5(const void*, size_t); + + friend class Iter; + friend class SkPathPriv; + friend class SkPathStroker; + + /* Append, in reverse order, the first contour of path, ignoring path's + last point. If no moveTo() call has been made for this contour, the + first point is automatically set to (0,0). + */ + SkPath& reversePathTo(const SkPath&); + + // called before we add points for lineTo, quadTo, cubicTo, checking to see + // if we need to inject a leading moveTo first + // + // SkPath path; path.lineTo(...); <--- need a leading moveTo(0, 0) + // SkPath path; ... path.close(); path.lineTo(...) <-- need a moveTo(previous moveTo) + // + inline void injectMoveToIfNeeded(); + + inline bool hasOnlyMoveTos() const; + + SkPathConvexity computeConvexity() const; + + bool isValidImpl() const; + /** Asserts if SkPath data is inconsistent. + Debugging check intended for internal use only. + */ +#ifdef SK_DEBUG + void validate() const; + void validateRef() const; +#endif + + // called by stroker to see if all points (in the last contour) are equal and worthy of a cap + bool isZeroLengthSincePoint(int startPtIndex) const; + + /** Returns if the path can return a bound at no cost (true) or will have to + perform some computation (false). + */ + bool hasComputedBounds() const; + + // 'rect' needs to be sorted + void setBounds(const SkRect& rect); + + void setPt(int index, SkScalar x, SkScalar y); + + SkPath& dirtyAfterEdit(); + + // Bottlenecks for working with fConvexity and fFirstDirection. + // Notice the setters are const... these are mutable atomic fields. + void setConvexity(SkPathConvexity) const; + + void setFirstDirection(SkPathFirstDirection) const; + SkPathFirstDirection getFirstDirection() const; + + /** Returns the comvexity type, computing if needed. Never returns kUnknown. + @return path's convexity type (convex or concave) + */ + SkPathConvexity getConvexity() const; + + SkPathConvexity getConvexityOrUnknown() const; + + // Compares the cached value with a freshly computed one (computeConvexity()) + bool isConvexityAccurate() const; + + /** Stores a convexity type for this path. This is what will be returned if + * getConvexityOrUnknown() is called. If you pass kUnknown, then if getContexityType() + * is called, the real convexity will be computed. + * + * example: https://fiddle.skia.org/c/@Path_setConvexity + */ + void setConvexity(SkPathConvexity convexity); + + /** Shrinks SkPath verb array and SkPoint array storage to discard unused capacity. + * May reduce the heap overhead for SkPath known to be fully constructed. + * + * NOTE: This may relocate the underlying buffers, and thus any Iterators referencing + * this path should be discarded after calling shrinkToFit(). + */ + void shrinkToFit(); + + // Creates a new Path after the supplied arguments have been validated by + // sk_path_analyze_verbs(). + static SkPath MakeInternal(const SkPathVerbAnalysis& analsis, + const SkPoint points[], + const uint8_t verbs[], + int verbCount, + const SkScalar conics[], + SkPathFillType fillType, + bool isVolatile); + + friend class SkAutoPathBoundsUpdate; + friend class SkAutoDisableOvalCheck; + friend class SkAutoDisableDirectionCheck; + friend class SkPathBuilder; + friend class SkPathEdgeIter; + friend class SkPathWriter; + friend class SkOpBuilder; + friend class SkBench_AddPathTest; // perf test reversePathTo + friend class PathTest_Private; // unit test reversePathTo + friend class ForceIsRRect_Private; // unit test isRRect + friend class FuzzPath; // for legacy access to validateRef +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPathBuilder.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPathBuilder.h new file mode 100644 index 0000000000..247c08624c --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPathBuilder.h @@ -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 + +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& 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& 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) const; + + SkPathBuilder& privateReverseAddPath(const SkPath&); + + friend class SkPathPriv; +}; + +#endif + diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPathEffect.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPathEffect.h new file mode 100644 index 0000000000..0ebe39f293 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPathEffect.h @@ -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 +#include + +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 MakeSum(sk_sp first, sk_sp 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 MakeCompose(sk_sp outer, sk_sp 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 Deserialize(const void* data, size_t size, + const SkDeserialProcs* procs = nullptr); + +private: + SkPathEffect() = default; + friend class SkPathEffectBase; + + using INHERITED = SkFlattenable; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPathMeasure.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPathMeasure.h new file mode 100644 index 0000000000..2c2c36007a --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPathMeasure.h @@ -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 fContour; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPathTypes.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPathTypes.h new file mode 100644 index 0000000000..963a6bda00 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPathTypes.h @@ -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(ft) & 1) != 0; +} + +static inline bool SkPathFillType_IsInverse(SkPathFillType ft) { + return (static_cast(ft) & 2) != 0; +} + +static inline SkPathFillType SkPathFillType_ConvertToNonInverse(SkPathFillType ft) { + return static_cast(static_cast(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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPathUtils.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPathUtils.h new file mode 100644 index 0000000000..6285da7996 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPathUtils.h @@ -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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPicture.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPicture.h new file mode 100644 index 0000000000..f4ab3ed29d --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPicture.h @@ -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 +#include +#include + +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 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 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 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 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 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 makeShader(SkTileMode tmx, SkTileMode tmy, SkFilterMode mode, + const SkMatrix* localMatrix, const SkRect* tileRect) const; + + sk_sp 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 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 Forwardport(const struct SkPictInfo&, + const class SkPictureData*, + class SkReadBuffer* buffer); + + struct SkPictInfo createHeader() const; + class SkPictureData* backport() const; + + uint32_t fUniqueID; + mutable std::atomic fAddedToCache{false}; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPictureRecorder.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPictureRecorder.h new file mode 100644 index 0000000000..573a643f73 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPictureRecorder.h @@ -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 + +#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 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 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 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 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 fBBH; + std::unique_ptr fRecorder; + sk_sp fRecord; + + SkPictureRecorder(SkPictureRecorder&&) = delete; + SkPictureRecorder& operator=(SkPictureRecorder&&) = delete; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPixelRef.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPixelRef.h new file mode 100644 index 0000000000..12779890f8 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPixelRef.h @@ -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 +#include +#include + +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 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 fTaggedGenID; + + SkIDChangeListener::List fGenIDChangeListeners; + + // Set true by caches when they cache content that's derived from the current pixels. + std::atomic 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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPixmap.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPixmap.h new file mode 100644 index 0000000000..e3379cbcf9 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPixmap.h @@ -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 +#include + +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 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 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(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(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(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(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(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(this->addr64(x, y)); + } + + /** Returns writable base pixel address. + + @return writable generic base pointer to pixels + */ + void* writable_addr() const { return const_cast(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(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(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(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(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(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(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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPoint.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPoint.h new file mode 100644 index 0000000000..4c7e0943cd --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPoint.h @@ -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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPoint3.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPoint3.h new file mode 100644 index 0000000000..abf8dfd9c9 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkPoint3.h @@ -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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkRRect.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkRRect.h new file mode 100644 index 0000000000..b6dc32c5b7 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkRRect.h @@ -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 +#include + +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(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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkRSXform.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkRSXform.h new file mode 100644 index 0000000000..de6bafd358 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkRSXform.h @@ -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 + diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkRasterHandleAllocator.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkRasterHandleAllocator.h new file mode 100644 index 0000000000..6fe121a6de --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkRasterHandleAllocator.h @@ -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 canvas = SkRasterHandleAllocator::MakeCanvas( + * SkImageInfo::Make(...), + * std::make_unique(...), + * 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 MakeCanvas(std::unique_ptr, + 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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkRect.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkRect.h new file mode 100644 index 0000000000..65c053a5e1 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkRect.h @@ -0,0 +1,1374 @@ +/* + * 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 SkRect_DEFINED +#define SkRect_DEFINED + +#include "include/core/SkPoint.h" +#include "include/core/SkSize.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkFloatingPoint.h" +#include "include/private/base/SkSafe32.h" +#include "include/private/base/SkTFitsIn.h" + +#include +#include +#include +#include + +struct SkRect; + +/** \struct SkIRect + SkIRect holds four 32-bit integer coordinates describing the upper and + lower bounds of a rectangle. SkIRect may be created from outer bounds or + from position, width, and height. SkIRect describes an area; if its right + is less than or equal to its left, or if its bottom is less than or equal to + its top, it is considered empty. +*/ +struct SK_API SkIRect { + int32_t fLeft = 0; //!< smaller x-axis bounds + int32_t fTop = 0; //!< smaller y-axis bounds + int32_t fRight = 0; //!< larger x-axis bounds + int32_t fBottom = 0; //!< larger y-axis bounds + + /** Returns constructed SkIRect set to (0, 0, 0, 0). + Many other rectangles are empty; if left is equal to or greater than right, + or if top is equal to or greater than bottom. Setting all members to zero + is a convenience, but does not designate a special empty rectangle. + + @return bounds (0, 0, 0, 0) + */ + [[nodiscard]] static constexpr SkIRect MakeEmpty() { + return SkIRect{0, 0, 0, 0}; + } + + /** Returns constructed SkIRect set to (0, 0, w, h). Does not validate input; w or h + may be negative. + + @param w width of constructed SkIRect + @param h height of constructed SkIRect + @return bounds (0, 0, w, h) + */ + [[nodiscard]] static constexpr SkIRect MakeWH(int32_t w, int32_t h) { + return SkIRect{0, 0, w, h}; + } + + /** Returns constructed SkIRect set to (0, 0, size.width(), size.height()). + Does not validate input; size.width() or size.height() may be negative. + + @param size values for SkIRect width and height + @return bounds (0, 0, size.width(), size.height()) + */ + [[nodiscard]] static constexpr SkIRect MakeSize(const SkISize& size) { + return SkIRect{0, 0, size.fWidth, size.fHeight}; + } + + /** Returns constructed SkIRect set to (pt.x(), pt.y(), pt.x() + size.width(), + pt.y() + size.height()). Does not validate input; size.width() or size.height() may be + negative. + + @param pt values for SkIRect fLeft and fTop + @param size values for SkIRect width and height + @return bounds at pt with width and height of size + */ + [[nodiscard]] static constexpr SkIRect MakePtSize(SkIPoint pt, SkISize size) { + return MakeXYWH(pt.x(), pt.y(), size.width(), size.height()); + } + + /** Returns constructed SkIRect set to (l, t, r, b). Does not sort input; SkIRect may + result in fLeft greater than fRight, or fTop greater than fBottom. + + @param l integer stored in fLeft + @param t integer stored in fTop + @param r integer stored in fRight + @param b integer stored in fBottom + @return bounds (l, t, r, b) + */ + [[nodiscard]] static constexpr SkIRect MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b) { + return SkIRect{l, t, r, b}; + } + + /** Returns constructed SkIRect set to: (x, y, x + w, y + h). + Does not validate input; w or h may be negative. + + @param x stored in fLeft + @param y stored in fTop + @param w added to x and stored in fRight + @param h added to y and stored in fBottom + @return bounds at (x, y) with width w and height h + */ + [[nodiscard]] static constexpr SkIRect MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h) { + return { x, y, Sk32_sat_add(x, w), Sk32_sat_add(y, h) }; + } + + /** Returns left edge of SkIRect, if sorted. + Call sort() to reverse fLeft and fRight if needed. + + @return fLeft + */ + constexpr int32_t left() const { return fLeft; } + + /** Returns top edge of SkIRect, if sorted. Call isEmpty() to see if SkIRect may be invalid, + and sort() to reverse fTop and fBottom if needed. + + @return fTop + */ + constexpr int32_t top() const { return fTop; } + + /** Returns right edge of SkIRect, if sorted. + Call sort() to reverse fLeft and fRight if needed. + + @return fRight + */ + constexpr int32_t right() const { return fRight; } + + /** Returns bottom edge of SkIRect, if sorted. Call isEmpty() to see if SkIRect may be invalid, + and sort() to reverse fTop and fBottom if needed. + + @return fBottom + */ + constexpr int32_t bottom() const { return fBottom; } + + /** Returns left edge of SkIRect, if sorted. Call isEmpty() to see if SkIRect may be invalid, + and sort() to reverse fLeft and fRight if needed. + + @return fLeft + */ + constexpr int32_t x() const { return fLeft; } + + /** Returns top edge of SkIRect, if sorted. Call isEmpty() to see if SkIRect may be invalid, + and sort() to reverse fTop and fBottom if needed. + + @return fTop + */ + constexpr int32_t y() const { return fTop; } + + // Experimental + constexpr SkIPoint topLeft() const { return {fLeft, fTop}; } + + /** Returns span on the x-axis. This does not check if SkIRect is sorted, or if + result fits in 32-bit signed integer; result may be negative. + + @return fRight minus fLeft + */ + constexpr int32_t width() const { return Sk32_can_overflow_sub(fRight, fLeft); } + + /** Returns span on the y-axis. This does not check if SkIRect is sorted, or if + result fits in 32-bit signed integer; result may be negative. + + @return fBottom minus fTop + */ + constexpr int32_t height() const { return Sk32_can_overflow_sub(fBottom, fTop); } + + /** Returns spans on the x-axis and y-axis. This does not check if SkIRect is sorted, + or if result fits in 32-bit signed integer; result may be negative. + + @return SkISize (width, height) + */ + constexpr SkISize size() const { return SkISize::Make(this->width(), this->height()); } + + /** Returns span on the x-axis. This does not check if SkIRect is sorted, so the + result may be negative. This is safer than calling width() since width() might + overflow in its calculation. + + @return fRight minus fLeft cast to int64_t + */ + constexpr int64_t width64() const { return (int64_t)fRight - (int64_t)fLeft; } + + /** Returns span on the y-axis. This does not check if SkIRect is sorted, so the + result may be negative. This is safer than calling height() since height() might + overflow in its calculation. + + @return fBottom minus fTop cast to int64_t + */ + constexpr int64_t height64() const { return (int64_t)fBottom - (int64_t)fTop; } + + /** Returns true if fLeft is equal to or greater than fRight, or if fTop is equal + to or greater than fBottom. Call sort() to reverse rectangles with negative + width64() or height64(). + + @return true if width64() or height64() are zero or negative + */ + bool isEmpty64() const { return fRight <= fLeft || fBottom <= fTop; } + + /** Returns true if width() or height() are zero or negative. + + @return true if width() or height() are zero or negative + */ + bool isEmpty() const { + int64_t w = this->width64(); + int64_t h = this->height64(); + if (w <= 0 || h <= 0) { + return true; + } + // Return true if either exceeds int32_t + return !SkTFitsIn(w | h); + } + + /** Returns true if all members in a: fLeft, fTop, fRight, and fBottom; are + identical to corresponding members in b. + + @param a SkIRect to compare + @param b SkIRect to compare + @return true if members are equal + */ + friend bool operator==(const SkIRect& a, const SkIRect& b) { + return a.fLeft == b.fLeft && a.fTop == b.fTop && + a.fRight == b.fRight && a.fBottom == b.fBottom; + } + + /** Returns true if any member in a: fLeft, fTop, fRight, and fBottom; is not + identical to the corresponding member in b. + + @param a SkIRect to compare + @param b SkIRect to compare + @return true if members are not equal + */ + friend bool operator!=(const SkIRect& a, const SkIRect& b) { + return a.fLeft != b.fLeft || a.fTop != b.fTop || + a.fRight != b.fRight || a.fBottom != b.fBottom; + } + + /** Sets SkIRect to (0, 0, 0, 0). + + Many other rectangles are empty; if left is equal to or greater than right, + or if top is equal to or greater than bottom. Setting all members to zero + is a convenience, but does not designate a special empty rectangle. + */ + void setEmpty() { memset(this, 0, sizeof(*this)); } + + /** Sets SkIRect to (left, top, right, bottom). + left and right are not sorted; left is not necessarily less than right. + top and bottom are not sorted; top is not necessarily less than bottom. + + @param left stored in fLeft + @param top stored in fTop + @param right stored in fRight + @param bottom stored in fBottom + */ + void setLTRB(int32_t left, int32_t top, int32_t right, int32_t bottom) { + fLeft = left; + fTop = top; + fRight = right; + fBottom = bottom; + } + + /** Sets SkIRect to: (x, y, x + width, y + height). + Does not validate input; width or height may be negative. + + @param x stored in fLeft + @param y stored in fTop + @param width added to x and stored in fRight + @param height added to y and stored in fBottom + */ + void setXYWH(int32_t x, int32_t y, int32_t width, int32_t height) { + fLeft = x; + fTop = y; + fRight = Sk32_sat_add(x, width); + fBottom = Sk32_sat_add(y, height); + } + + void setWH(int32_t width, int32_t height) { + fLeft = 0; + fTop = 0; + fRight = width; + fBottom = height; + } + + void setSize(SkISize size) { + fLeft = 0; + fTop = 0; + fRight = size.width(); + fBottom = size.height(); + } + + /** Returns SkIRect offset by (dx, dy). + + If dx is negative, SkIRect returned is moved to the left. + If dx is positive, SkIRect returned is moved to the right. + If dy is negative, SkIRect returned is moved upward. + If dy is positive, SkIRect returned is moved downward. + + @param dx offset added to fLeft and fRight + @param dy offset added to fTop and fBottom + @return SkIRect offset by dx and dy, with original width and height + */ + constexpr SkIRect makeOffset(int32_t dx, int32_t dy) const { + return { + Sk32_sat_add(fLeft, dx), Sk32_sat_add(fTop, dy), + Sk32_sat_add(fRight, dx), Sk32_sat_add(fBottom, dy), + }; + } + + /** Returns SkIRect offset by (offset.x(), offset.y()). + + If offset.x() is negative, SkIRect returned is moved to the left. + If offset.x() is positive, SkIRect returned is moved to the right. + If offset.y() is negative, SkIRect returned is moved upward. + If offset.y() is positive, SkIRect returned is moved downward. + + @param offset translation vector + @return SkIRect translated by offset, with original width and height + */ + constexpr SkIRect makeOffset(SkIVector offset) const { + return this->makeOffset(offset.x(), offset.y()); + } + + /** Returns SkIRect, inset by (dx, dy). + + If dx is negative, SkIRect returned is wider. + If dx is positive, SkIRect returned is narrower. + If dy is negative, SkIRect returned is taller. + If dy is positive, SkIRect returned is shorter. + + @param dx offset added to fLeft and subtracted from fRight + @param dy offset added to fTop and subtracted from fBottom + @return SkIRect inset symmetrically left and right, top and bottom + */ + SkIRect makeInset(int32_t dx, int32_t dy) const { + return { + Sk32_sat_add(fLeft, dx), Sk32_sat_add(fTop, dy), + Sk32_sat_sub(fRight, dx), Sk32_sat_sub(fBottom, dy), + }; + } + + /** Returns SkIRect, outset by (dx, dy). + + If dx is negative, SkIRect returned is narrower. + If dx is positive, SkIRect returned is wider. + If dy is negative, SkIRect returned is shorter. + If dy is positive, SkIRect returned is taller. + + @param dx offset subtracted to fLeft and added from fRight + @param dy offset subtracted to fTop and added from fBottom + @return SkIRect outset symmetrically left and right, top and bottom + */ + SkIRect makeOutset(int32_t dx, int32_t dy) const { + return { + Sk32_sat_sub(fLeft, dx), Sk32_sat_sub(fTop, dy), + Sk32_sat_add(fRight, dx), Sk32_sat_add(fBottom, dy), + }; + } + + /** Offsets SkIRect by adding dx to fLeft, fRight; and by adding dy to fTop, fBottom. + + If dx is negative, moves SkIRect returned to the left. + If dx is positive, moves SkIRect returned to the right. + If dy is negative, moves SkIRect returned upward. + If dy is positive, moves SkIRect returned downward. + + @param dx offset added to fLeft and fRight + @param dy offset added to fTop and fBottom + */ + void offset(int32_t dx, int32_t dy) { + fLeft = Sk32_sat_add(fLeft, dx); + fTop = Sk32_sat_add(fTop, dy); + fRight = Sk32_sat_add(fRight, dx); + fBottom = Sk32_sat_add(fBottom, dy); + } + + /** Offsets SkIRect by adding delta.fX to fLeft, fRight; and by adding delta.fY to + fTop, fBottom. + + If delta.fX is negative, moves SkIRect returned to the left. + If delta.fX is positive, moves SkIRect returned to the right. + If delta.fY is negative, moves SkIRect returned upward. + If delta.fY is positive, moves SkIRect returned downward. + + @param delta offset added to SkIRect + */ + void offset(const SkIPoint& delta) { + this->offset(delta.fX, delta.fY); + } + + /** Offsets SkIRect so that fLeft equals newX, and fTop equals newY. width and height + are unchanged. + + @param newX stored in fLeft, preserving width() + @param newY stored in fTop, preserving height() + */ + void offsetTo(int32_t newX, int32_t newY) { + fRight = Sk64_pin_to_s32((int64_t)fRight + newX - fLeft); + fBottom = Sk64_pin_to_s32((int64_t)fBottom + newY - fTop); + fLeft = newX; + fTop = newY; + } + + /** Insets SkIRect by (dx,dy). + + If dx is positive, makes SkIRect narrower. + If dx is negative, makes SkIRect wider. + If dy is positive, makes SkIRect shorter. + If dy is negative, makes SkIRect taller. + + @param dx offset added to fLeft and subtracted from fRight + @param dy offset added to fTop and subtracted from fBottom + */ + void inset(int32_t dx, int32_t dy) { + fLeft = Sk32_sat_add(fLeft, dx); + fTop = Sk32_sat_add(fTop, dy); + fRight = Sk32_sat_sub(fRight, dx); + fBottom = Sk32_sat_sub(fBottom, dy); + } + + /** Outsets SkIRect by (dx, dy). + + If dx is positive, makes SkIRect wider. + If dx is negative, makes SkIRect narrower. + If dy is positive, makes SkIRect taller. + If dy is negative, makes SkIRect shorter. + + @param dx subtracted to fLeft and added from fRight + @param dy subtracted to fTop and added from fBottom + */ + void outset(int32_t dx, int32_t dy) { this->inset(-dx, -dy); } + + /** Adjusts SkIRect by adding dL to fLeft, dT to fTop, dR to fRight, and dB to fBottom. + + If dL is positive, narrows SkIRect on the left. If negative, widens it on the left. + If dT is positive, shrinks SkIRect on the top. If negative, lengthens it on the top. + If dR is positive, narrows SkIRect on the right. If negative, widens it on the right. + If dB is positive, shrinks SkIRect on the bottom. If negative, lengthens it on the bottom. + + The resulting SkIRect is not checked for validity. Thus, if the resulting SkIRect left is + greater than right, the SkIRect will be considered empty. Call sort() after this call + if that is not the desired behavior. + + @param dL offset added to fLeft + @param dT offset added to fTop + @param dR offset added to fRight + @param dB offset added to fBottom + */ + void adjust(int32_t dL, int32_t dT, int32_t dR, int32_t dB) { + fLeft = Sk32_sat_add(fLeft, dL); + fTop = Sk32_sat_add(fTop, dT); + fRight = Sk32_sat_add(fRight, dR); + fBottom = Sk32_sat_add(fBottom, dB); + } + + /** Returns true if: fLeft <= x < fRight && fTop <= y < fBottom. + Returns false if SkIRect is empty. + + Considers input to describe constructed SkIRect: (x, y, x + 1, y + 1) and + returns true if constructed area is completely enclosed by SkIRect area. + + @param x test SkIPoint x-coordinate + @param y test SkIPoint y-coordinate + @return true if (x, y) is inside SkIRect + */ + bool contains(int32_t x, int32_t y) const { + return x >= fLeft && x < fRight && y >= fTop && y < fBottom; + } + + /** Returns true if SkIRect contains r. + Returns false if SkIRect is empty or r is empty. + + SkIRect contains r when SkIRect area completely includes r area. + + @param r SkIRect contained + @return true if all sides of SkIRect are outside r + */ + bool contains(const SkIRect& r) const { + return !r.isEmpty() && !this->isEmpty() && // check for empties + fLeft <= r.fLeft && fTop <= r.fTop && + fRight >= r.fRight && fBottom >= r.fBottom; + } + + /** Returns true if SkIRect contains r. + Returns false if SkIRect is empty or r is empty. + + SkIRect contains r when SkIRect area completely includes r area. + + @param r SkRect contained + @return true if all sides of SkIRect are outside r + */ + inline bool contains(const SkRect& r) const; + + /** Returns true if SkIRect contains construction. + Asserts if SkIRect is empty or construction is empty, and if SK_DEBUG is defined. + + Return is undefined if SkIRect is empty or construction is empty. + + @param r SkIRect contained + @return true if all sides of SkIRect are outside r + */ + bool containsNoEmptyCheck(const SkIRect& r) const { + SkASSERT(fLeft < fRight && fTop < fBottom); + SkASSERT(r.fLeft < r.fRight && r.fTop < r.fBottom); + return fLeft <= r.fLeft && fTop <= r.fTop && fRight >= r.fRight && fBottom >= r.fBottom; + } + + /** Returns true if SkIRect intersects r, and sets SkIRect to intersection. + Returns false if SkIRect does not intersect r, and leaves SkIRect unchanged. + + Returns false if either r or SkIRect is empty, leaving SkIRect unchanged. + + @param r limit of result + @return true if r and SkIRect have area in common + */ + bool intersect(const SkIRect& r) { + return this->intersect(*this, r); + } + + /** Returns true if a intersects b, and sets SkIRect to intersection. + Returns false if a does not intersect b, and leaves SkIRect unchanged. + + Returns false if either a or b is empty, leaving SkIRect unchanged. + + @param a SkIRect to intersect + @param b SkIRect to intersect + @return true if a and b have area in common + */ + [[nodiscard]] bool intersect(const SkIRect& a, const SkIRect& b); + + /** Returns true if a intersects b. + Returns false if either a or b is empty, or do not intersect. + + @param a SkIRect to intersect + @param b SkIRect to intersect + @return true if a and b have area in common + */ + static bool Intersects(const SkIRect& a, const SkIRect& b) { + return SkIRect{}.intersect(a, b); + } + + /** Sets SkIRect to the union of itself and r. + + Has no effect if r is empty. Otherwise, if SkIRect is empty, sets SkIRect to r. + + @param r expansion SkIRect + + example: https://fiddle.skia.org/c/@IRect_join_2 + */ + void join(const SkIRect& r); + + /** Swaps fLeft and fRight if fLeft is greater than fRight; and swaps + fTop and fBottom if fTop is greater than fBottom. Result may be empty, + and width() and height() will be zero or positive. + */ + void sort() { + using std::swap; + if (fLeft > fRight) { + swap(fLeft, fRight); + } + if (fTop > fBottom) { + swap(fTop, fBottom); + } + } + + /** Returns SkIRect with fLeft and fRight swapped if fLeft is greater than fRight; and + with fTop and fBottom swapped if fTop is greater than fBottom. Result may be empty; + and width() and height() will be zero or positive. + + @return sorted SkIRect + */ + SkIRect makeSorted() const { + return MakeLTRB(std::min(fLeft, fRight), std::min(fTop, fBottom), + std::max(fLeft, fRight), std::max(fTop, fBottom)); + } +}; + +/** \struct SkRect + SkRect holds four float coordinates describing the upper and + lower bounds of a rectangle. SkRect may be created from outer bounds or + from position, width, and height. SkRect describes an area; if its right + is less than or equal to its left, or if its bottom is less than or equal to + its top, it is considered empty. +*/ +struct SK_API SkRect { + float fLeft = 0; //!< smaller x-axis bounds + float fTop = 0; //!< smaller y-axis bounds + float fRight = 0; //!< larger x-axis bounds + float fBottom = 0; //!< larger y-axis bounds + + /** Returns constructed SkRect set to (0, 0, 0, 0). + Many other rectangles are empty; if left is equal to or greater than right, + or if top is equal to or greater than bottom. Setting all members to zero + is a convenience, but does not designate a special empty rectangle. + + @return bounds (0, 0, 0, 0) + */ + [[nodiscard]] static constexpr SkRect MakeEmpty() { + return SkRect{0, 0, 0, 0}; + } + + /** Returns constructed SkRect set to float values (0, 0, w, h). Does not + validate input; w or h may be negative. + + Passing integer values may generate a compiler warning since SkRect cannot + represent 32-bit integers exactly. Use SkIRect for an exact integer rectangle. + + @param w float width of constructed SkRect + @param h float height of constructed SkRect + @return bounds (0, 0, w, h) + */ + [[nodiscard]] static constexpr SkRect MakeWH(float w, float h) { + return SkRect{0, 0, w, h}; + } + + /** Returns constructed SkRect set to integer values (0, 0, w, h). Does not validate + input; w or h may be negative. + + Use to avoid a compiler warning that input may lose precision when stored. + Use SkIRect for an exact integer rectangle. + + @param w integer width of constructed SkRect + @param h integer height of constructed SkRect + @return bounds (0, 0, w, h) + */ + [[nodiscard]] static SkRect MakeIWH(int w, int h) { + return {0, 0, static_cast(w), static_cast(h)}; + } + + /** Returns constructed SkRect set to (0, 0, size.width(), size.height()). Does not + validate input; size.width() or size.height() may be negative. + + @param size float values for SkRect width and height + @return bounds (0, 0, size.width(), size.height()) + */ + [[nodiscard]] static constexpr SkRect MakeSize(const SkSize& size) { + return SkRect{0, 0, size.fWidth, size.fHeight}; + } + + /** Returns constructed SkRect set to (l, t, r, b). Does not sort input; SkRect may + result in fLeft greater than fRight, or fTop greater than fBottom. + + @param l float stored in fLeft + @param t float stored in fTop + @param r float stored in fRight + @param b float stored in fBottom + @return bounds (l, t, r, b) + */ + [[nodiscard]] static constexpr SkRect MakeLTRB(float l, float t, float r, float b) { + return SkRect {l, t, r, b}; + } + + /** Returns constructed SkRect set to (x, y, x + w, y + h). + Does not validate input; w or h may be negative. + + @param x stored in fLeft + @param y stored in fTop + @param w added to x and stored in fRight + @param h added to y and stored in fBottom + @return bounds at (x, y) with width w and height h + */ + [[nodiscard]] static constexpr SkRect MakeXYWH(float x, float y, float w, float h) { + return SkRect {x, y, x + w, y + h}; + } + + /** Returns constructed SkIRect set to (0, 0, size.width(), size.height()). + Does not validate input; size.width() or size.height() may be negative. + + @param size integer values for SkRect width and height + @return bounds (0, 0, size.width(), size.height()) + */ + static SkRect Make(const SkISize& size) { + return MakeIWH(size.width(), size.height()); + } + + /** Returns constructed SkIRect set to irect, promoting integers to float. + Does not validate input; fLeft may be greater than fRight, fTop may be greater + than fBottom. + + @param irect integer unsorted bounds + @return irect members converted to float + */ + [[nodiscard]] static SkRect Make(const SkIRect& irect) { + return { + static_cast(irect.fLeft), static_cast(irect.fTop), + static_cast(irect.fRight), static_cast(irect.fBottom) + }; + } + + /** Returns true if fLeft is equal to or greater than fRight, or if fTop is equal + to or greater than fBottom. Call sort() to reverse rectangles with negative + width() or height(). + + @return true if width() or height() are zero or negative + */ + bool isEmpty() const { + // We write it as the NOT of a non-empty rect, so we will return true if any values + // are NaN. + return !(fLeft < fRight && fTop < fBottom); + } + + /** Returns true if fLeft is equal to or less than fRight, or if fTop is equal + to or less than fBottom. Call sort() to reverse rectangles with negative + width() or height(). + + @return true if width() or height() are zero or positive + */ + bool isSorted() const { return fLeft <= fRight && fTop <= fBottom; } + + /** Returns true if all values in the rectangle are finite. + + @return true if no member is infinite or NaN + */ + bool isFinite() const { + return SkIsFinite(fLeft, fTop, fRight, fBottom); + } + + /** Returns left edge of SkRect, if sorted. Call isSorted() to see if SkRect is valid. + Call sort() to reverse fLeft and fRight if needed. + + @return fLeft + */ + constexpr float x() const { return fLeft; } + + /** Returns top edge of SkRect, if sorted. Call isEmpty() to see if SkRect may be invalid, + and sort() to reverse fTop and fBottom if needed. + + @return fTop + */ + constexpr float y() const { return fTop; } + + /** Returns left edge of SkRect, if sorted. Call isSorted() to see if SkRect is valid. + Call sort() to reverse fLeft and fRight if needed. + + @return fLeft + */ + constexpr float left() const { return fLeft; } + + /** Returns top edge of SkRect, if sorted. Call isEmpty() to see if SkRect may be invalid, + and sort() to reverse fTop and fBottom if needed. + + @return fTop + */ + constexpr float top() const { return fTop; } + + /** Returns right edge of SkRect, if sorted. Call isSorted() to see if SkRect is valid. + Call sort() to reverse fLeft and fRight if needed. + + @return fRight + */ + constexpr float right() const { return fRight; } + + /** Returns bottom edge of SkRect, if sorted. Call isEmpty() to see if SkRect may be invalid, + and sort() to reverse fTop and fBottom if needed. + + @return fBottom + */ + constexpr float bottom() const { return fBottom; } + + /** Returns span on the x-axis. This does not check if SkRect is sorted, or if + result fits in 32-bit float; result may be negative or infinity. + + @return fRight minus fLeft + */ + constexpr float width() const { return fRight - fLeft; } + + /** Returns span on the y-axis. This does not check if SkRect is sorted, or if + result fits in 32-bit float; result may be negative or infinity. + + @return fBottom minus fTop + */ + constexpr float height() const { return fBottom - fTop; } + + /** Returns average of left edge and right edge. Result does not change if SkRect + is sorted. Result may overflow to infinity if SkRect is far from the origin. + + @return midpoint on x-axis + */ + constexpr float centerX() const { + return sk_float_midpoint(fLeft, fRight); + } + + /** Returns average of top edge and bottom edge. Result does not change if SkRect + is sorted. + + @return midpoint on y-axis + */ + constexpr float centerY() const { + return sk_float_midpoint(fTop, fBottom); + } + + /** Returns the point this->centerX(), this->centerY(). + @return rectangle center + */ + constexpr SkPoint center() const { return {this->centerX(), this->centerY()}; } + + /** Returns true if all members in a: fLeft, fTop, fRight, and fBottom; are + equal to the corresponding members 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 to compare + @param b SkRect to compare + @return true if members are equal + */ + friend bool operator==(const SkRect& a, const SkRect& b) { + return a.fLeft == b.fLeft && + a.fTop == b.fTop && + a.fRight == b.fRight && + a.fBottom == b.fBottom; + } + + /** Returns true if any in a: fLeft, fTop, fRight, and fBottom; does not + equal the corresponding members 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 to compare + @param b SkRect to compare + @return true if members are not equal + */ + friend bool operator!=(const SkRect& a, const SkRect& b) { + return !(a == b); + } + + /** Returns four points in quad that enclose SkRect ordered as: top-left, top-right, + bottom-right, bottom-left. + + TODO: Consider adding parameter to control whether quad is clockwise or counterclockwise. + + @param quad storage for corners of SkRect + + example: https://fiddle.skia.org/c/@Rect_toQuad + */ + void toQuad(SkPoint quad[4]) const; + + /** Sets SkRect to (0, 0, 0, 0). + + Many other rectangles are empty; if left is equal to or greater than right, + or if top is equal to or greater than bottom. Setting all members to zero + is a convenience, but does not designate a special empty rectangle. + */ + void setEmpty() { *this = MakeEmpty(); } + + /** Sets SkRect to src, promoting src members from integer to float. + Very large values in src may lose precision. + + @param src integer SkRect + */ + void set(const SkIRect& src) { + fLeft = src.fLeft; + fTop = src.fTop; + fRight = src.fRight; + fBottom = src.fBottom; + } + + /** Sets SkRect to (left, top, right, bottom). + left and right are not sorted; left is not necessarily less than right. + top and bottom are not sorted; top is not necessarily less than bottom. + + @param left stored in fLeft + @param top stored in fTop + @param right stored in fRight + @param bottom stored in fBottom + */ + void setLTRB(float left, float top, float right, float bottom) { + fLeft = left; + fTop = top; + fRight = right; + fBottom = bottom; + } + + /** Sets to bounds of SkPoint array with count entries. If count is zero or smaller, + or if SkPoint array contains an infinity or NaN, sets to (0, 0, 0, 0). + + Result is either empty or sorted: fLeft is less than or equal to fRight, and + fTop is less than or equal to fBottom. + + @param pts SkPoint array + @param count entries in array + */ + void setBounds(const SkPoint pts[], int count) { + (void)this->setBoundsCheck(pts, count); + } + + /** Sets to bounds of SkPoint array with count entries. Returns false if count is + zero or smaller, or if SkPoint array contains an infinity or NaN; in these cases + sets SkRect to (0, 0, 0, 0). + + Result is either empty or sorted: fLeft is less than or equal to fRight, and + fTop is less than or equal to fBottom. + + @param pts SkPoint array + @param count entries in array + @return true if all SkPoint values are finite + + example: https://fiddle.skia.org/c/@Rect_setBoundsCheck + */ + bool setBoundsCheck(const SkPoint pts[], int count); + + /** Sets to bounds of SkPoint pts array with count entries. If any SkPoint in pts + contains infinity or NaN, all SkRect dimensions are set to NaN. + + @param pts SkPoint array + @param count entries in array + + example: https://fiddle.skia.org/c/@Rect_setBoundsNoCheck + */ + void setBoundsNoCheck(const SkPoint pts[], int count); + + /** Sets bounds to the smallest SkRect enclosing SkPoint p0 and p1. The result is + sorted and may be empty. Does not check to see if values are finite. + + @param p0 corner to include + @param p1 corner to include + */ + void set(const SkPoint& p0, const SkPoint& p1) { + fLeft = std::min(p0.fX, p1.fX); + fRight = std::max(p0.fX, p1.fX); + fTop = std::min(p0.fY, p1.fY); + fBottom = std::max(p0.fY, p1.fY); + } + + /** Sets SkRect to (x, y, x + width, y + height). + Does not validate input; width or height may be negative. + + @param x stored in fLeft + @param y stored in fTop + @param width added to x and stored in fRight + @param height added to y and stored in fBottom + */ + void setXYWH(float x, float y, float width, float height) { + fLeft = x; + fTop = y; + fRight = x + width; + fBottom = y + height; + } + + /** Sets SkRect to (0, 0, width, height). Does not validate input; + width or height may be negative. + + @param width stored in fRight + @param height stored in fBottom + */ + void setWH(float width, float height) { + fLeft = 0; + fTop = 0; + fRight = width; + fBottom = height; + } + void setIWH(int32_t width, int32_t height) { + this->setWH(width, height); + } + + /** Returns SkRect offset by (dx, dy). + + If dx is negative, SkRect returned is moved to the left. + If dx is positive, SkRect returned is moved to the right. + If dy is negative, SkRect returned is moved upward. + If dy is positive, SkRect returned is moved downward. + + @param dx added to fLeft and fRight + @param dy added to fTop and fBottom + @return SkRect offset on axes, with original width and height + */ + constexpr SkRect makeOffset(float dx, float dy) const { + return MakeLTRB(fLeft + dx, fTop + dy, fRight + dx, fBottom + dy); + } + + /** Returns SkRect offset by v. + + @param v added to rect + @return SkRect offset on axes, with original width and height + */ + constexpr SkRect makeOffset(SkVector v) const { return this->makeOffset(v.x(), v.y()); } + + /** Returns SkRect, inset by (dx, dy). + + If dx is negative, SkRect returned is wider. + If dx is positive, SkRect returned is narrower. + If dy is negative, SkRect returned is taller. + If dy is positive, SkRect returned is shorter. + + @param dx added to fLeft and subtracted from fRight + @param dy added to fTop and subtracted from fBottom + @return SkRect inset symmetrically left and right, top and bottom + */ + SkRect makeInset(float dx, float dy) const { + return MakeLTRB(fLeft + dx, fTop + dy, fRight - dx, fBottom - dy); + } + + /** Returns SkRect, outset by (dx, dy). + + If dx is negative, SkRect returned is narrower. + If dx is positive, SkRect returned is wider. + If dy is negative, SkRect returned is shorter. + If dy is positive, SkRect returned is taller. + + @param dx subtracted to fLeft and added from fRight + @param dy subtracted to fTop and added from fBottom + @return SkRect outset symmetrically left and right, top and bottom + */ + SkRect makeOutset(float dx, float dy) const { + return MakeLTRB(fLeft - dx, fTop - dy, fRight + dx, fBottom + dy); + } + + /** Offsets SkRect by adding dx to fLeft, fRight; and by adding dy to fTop, fBottom. + + If dx is negative, moves SkRect to the left. + If dx is positive, moves SkRect to the right. + If dy is negative, moves SkRect upward. + If dy is positive, moves SkRect downward. + + @param dx offset added to fLeft and fRight + @param dy offset added to fTop and fBottom + */ + void offset(float dx, float dy) { + fLeft += dx; + fTop += dy; + fRight += dx; + fBottom += dy; + } + + /** Offsets SkRect by adding delta.fX to fLeft, fRight; and by adding delta.fY to + fTop, fBottom. + + If delta.fX is negative, moves SkRect to the left. + If delta.fX is positive, moves SkRect to the right. + If delta.fY is negative, moves SkRect upward. + If delta.fY is positive, moves SkRect downward. + + @param delta added to SkRect + */ + void offset(const SkPoint& delta) { + this->offset(delta.fX, delta.fY); + } + + /** Offsets SkRect so that fLeft equals newX, and fTop equals newY. width and height + are unchanged. + + @param newX stored in fLeft, preserving width() + @param newY stored in fTop, preserving height() + */ + void offsetTo(float newX, float newY) { + fRight += newX - fLeft; + fBottom += newY - fTop; + fLeft = newX; + fTop = newY; + } + + /** Insets SkRect by (dx, dy). + + If dx is positive, makes SkRect narrower. + If dx is negative, makes SkRect wider. + If dy is positive, makes SkRect shorter. + If dy is negative, makes SkRect taller. + + @param dx added to fLeft and subtracted from fRight + @param dy added to fTop and subtracted from fBottom + */ + void inset(float dx, float dy) { + fLeft += dx; + fTop += dy; + fRight -= dx; + fBottom -= dy; + } + + /** Outsets SkRect by (dx, dy). + + If dx is positive, makes SkRect wider. + If dx is negative, makes SkRect narrower. + If dy is positive, makes SkRect taller. + If dy is negative, makes SkRect shorter. + + @param dx subtracted to fLeft and added from fRight + @param dy subtracted to fTop and added from fBottom + */ + void outset(float dx, float dy) { this->inset(-dx, -dy); } + + /** Returns true if SkRect intersects r, and sets SkRect to intersection. + Returns false if SkRect does not intersect r, and leaves SkRect unchanged. + + Returns false if either r or SkRect is empty, leaving SkRect unchanged. + + @param r limit of result + @return true if r and SkRect have area in common + + example: https://fiddle.skia.org/c/@Rect_intersect + */ + bool intersect(const SkRect& r); + + /** Returns true if a intersects b, and sets SkRect to intersection. + Returns false if a does not intersect b, and leaves SkRect unchanged. + + Returns false if either a or b is empty, leaving SkRect unchanged. + + @param a SkRect to intersect + @param b SkRect to intersect + @return true if a and b have area in common + */ + [[nodiscard]] bool intersect(const SkRect& a, const SkRect& b); + + +private: + static bool Intersects(float al, float at, float ar, float ab, + float bl, float bt, float br, float bb) { + float L = std::max(al, bl); + float R = std::min(ar, br); + float T = std::max(at, bt); + float B = std::min(ab, bb); + return L < R && T < B; + } + +public: + + /** Returns true if SkRect intersects r. + Returns false if either r or SkRect is empty, or do not intersect. + + @param r SkRect to intersect + @return true if r and SkRect have area in common + */ + bool intersects(const SkRect& r) const { + return Intersects(fLeft, fTop, fRight, fBottom, + r.fLeft, r.fTop, r.fRight, r.fBottom); + } + + /** Returns true if a intersects b. + Returns false if either a or b is empty, or do not intersect. + + @param a SkRect to intersect + @param b SkRect to intersect + @return true if a and b have area in common + */ + static bool Intersects(const SkRect& a, const SkRect& b) { + return Intersects(a.fLeft, a.fTop, a.fRight, a.fBottom, + b.fLeft, b.fTop, b.fRight, b.fBottom); + } + + /** Sets SkRect to the union of itself and r. + + Has no effect if r is empty. Otherwise, if SkRect is empty, sets + SkRect to r. + + @param r expansion SkRect + + example: https://fiddle.skia.org/c/@Rect_join_2 + */ + void join(const SkRect& r); + + /** Sets SkRect to the union of itself and r. + + Asserts if r is empty and SK_DEBUG is defined. + If SkRect is empty, sets SkRect to r. + + May produce incorrect results if r is empty. + + @param r expansion SkRect + */ + void joinNonEmptyArg(const SkRect& r) { + SkASSERT(!r.isEmpty()); + // if we are empty, just assign + if (fLeft >= fRight || fTop >= fBottom) { + *this = r; + } else { + this->joinPossiblyEmptyRect(r); + } + } + + /** Sets SkRect to the union of itself and the construction. + + May produce incorrect results if SkRect or r is empty. + + @param r expansion SkRect + */ + void joinPossiblyEmptyRect(const SkRect& r) { + fLeft = std::min(fLeft, r.left()); + fTop = std::min(fTop, r.top()); + fRight = std::max(fRight, r.right()); + fBottom = std::max(fBottom, r.bottom()); + } + + /** Returns true if: fLeft <= x < fRight && fTop <= y < fBottom. + Returns false if SkRect is empty. + + @param x test SkPoint x-coordinate + @param y test SkPoint y-coordinate + @return true if (x, y) is inside SkRect + */ + bool contains(float x, float y) const { + return x >= fLeft && x < fRight && y >= fTop && y < fBottom; + } + + /** Returns true if SkRect contains r. + Returns false if SkRect is empty or r is empty. + + SkRect contains r when SkRect area completely includes r area. + + @param r SkRect contained + @return true if all sides of SkRect are outside r + */ + bool contains(const SkRect& r) const { + // todo: can we eliminate the this->isEmpty check? + return !r.isEmpty() && !this->isEmpty() && + fLeft <= r.fLeft && fTop <= r.fTop && + fRight >= r.fRight && fBottom >= r.fBottom; + } + + /** Returns true if SkRect contains r. + Returns false if SkRect is empty or r is empty. + + SkRect contains r when SkRect area completely includes r area. + + @param r SkIRect contained + @return true if all sides of SkRect are outside r + */ + bool contains(const SkIRect& r) const { + // todo: can we eliminate the this->isEmpty check? + return !r.isEmpty() && !this->isEmpty() && + fLeft <= r.fLeft && fTop <= r.fTop && + fRight >= r.fRight && fBottom >= r.fBottom; + } + + /** Sets SkIRect by adding 0.5 and discarding the fractional portion of SkRect + members, using (sk_float_round2int(fLeft), sk_float_round2int(fTop), + sk_float_round2int(fRight), sk_float_round2int(fBottom)). + + @param dst storage for SkIRect + */ + void round(SkIRect* dst) const { + SkASSERT(dst); + dst->setLTRB(sk_float_round2int(fLeft), sk_float_round2int(fTop), + sk_float_round2int(fRight), sk_float_round2int(fBottom)); + } + + /** Sets SkIRect by discarding the fractional portion of fLeft and fTop; and rounding + up fRight and fBottom, using + (sk_float_floor2int(fLeft), sk_float_floor2int(fTop), + sk_float_ceil2int(fRight), sk_float_ceil2int(fBottom)). + + @param dst storage for SkIRect + */ + void roundOut(SkIRect* dst) const { + SkASSERT(dst); + dst->setLTRB(sk_float_floor2int(fLeft), sk_float_floor2int(fTop), + sk_float_ceil2int(fRight), sk_float_ceil2int(fBottom)); + } + + /** Sets SkRect by discarding the fractional portion of fLeft and fTop; and rounding + up fRight and fBottom, using + (std::floor(fLeft), std::floor(fTop), + std::ceil(fRight), std::ceil(fBottom)). + + @param dst storage for SkRect + */ + void roundOut(SkRect* dst) const { + dst->setLTRB(std::floor(fLeft), std::floor(fTop), + std::ceil(fRight), std::ceil(fBottom)); + } + + /** Sets SkRect by rounding up fLeft and fTop; and discarding the fractional portion + of fRight and fBottom, using + (sk_float_ceil2int(fLeft), sk_float_ceil2int(fTop), + sk_float_floor2int(fRight), sk_float_floor2int(fBottom)). + + @param dst storage for SkIRect + */ + void roundIn(SkIRect* dst) const { + SkASSERT(dst); + dst->setLTRB(sk_float_ceil2int(fLeft), sk_float_ceil2int(fTop), + sk_float_floor2int(fRight), sk_float_floor2int(fBottom)); + } + + /** Returns SkIRect by adding 0.5 and discarding the fractional portion of SkRect + members, using (sk_float_round2int(fLeft), sk_float_round2int(fTop), + sk_float_round2int(fRight), sk_float_round2int(fBottom)). + + @return rounded SkIRect + */ + SkIRect round() const { + SkIRect ir; + this->round(&ir); + return ir; + } + + /** Sets SkIRect by discarding the fractional portion of fLeft and fTop; and rounding + up fRight and fBottom, using + (sk_float_floor2int(fLeft), sk_float_floor2int(fTop), + sk_float_ceil2int(fRight), sk_float_ceil2int(fBottom)). + + @return rounded SkIRect + */ + SkIRect roundOut() const { + SkIRect ir; + this->roundOut(&ir); + return ir; + } + /** Sets SkIRect by rounding up fLeft and fTop; and discarding the fractional portion + of fRight and fBottom, using + (sk_float_ceil2int(fLeft), sk_float_ceil2int(fTop), + sk_float_floor2int(fRight), sk_float_floor2int(fBottom)). + + @return rounded SkIRect + */ + SkIRect roundIn() const { + SkIRect ir; + this->roundIn(&ir); + return ir; + } + + /** Swaps fLeft and fRight if fLeft is greater than fRight; and swaps + fTop and fBottom if fTop is greater than fBottom. Result may be empty; + and width() and height() will be zero or positive. + */ + void sort() { + using std::swap; + if (fLeft > fRight) { + swap(fLeft, fRight); + } + + if (fTop > fBottom) { + swap(fTop, fBottom); + } + } + + /** Returns SkRect with fLeft and fRight swapped if fLeft is greater than fRight; and + with fTop and fBottom swapped if fTop is greater than fBottom. Result may be empty; + and width() and height() will be zero or positive. + + @return sorted SkRect + */ + SkRect makeSorted() const { + return MakeLTRB(std::min(fLeft, fRight), std::min(fTop, fBottom), + std::max(fLeft, fRight), std::max(fTop, fBottom)); + } + + /** Returns pointer to first float in SkRect, to treat it as an array with four + entries. + + @return pointer to fLeft + */ + const float* asScalars() const { return &fLeft; } + + /** Writes text representation of SkRect to standard output. Set asHex to 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/@Rect_dump + */ + void dump(bool asHex) const; + + /** Writes text representation of SkRect 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 SkRect + from output. + */ + void dump() const { this->dump(false); } + + /** Writes text representation of SkRect 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 SkRect. + + Use instead of dump() when submitting + */ + void dumpHex() const { this->dump(true); } +}; + +inline bool SkIRect::contains(const SkRect& r) const { + return !r.isEmpty() && !this->isEmpty() && // check for empties + fLeft <= r.fLeft && fTop <= r.fTop && + fRight >= r.fRight && fBottom >= r.fBottom; +} + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkRefCnt.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkRefCnt.h new file mode 100644 index 0000000000..34274a461d --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkRefCnt.h @@ -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 +#include +#include +#include +#include +#include + +/** \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 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 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 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 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 +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 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 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& that) : fPtr(SkSafeRef(that.get())) {} + template ::value>::type> + sk_sp(const sk_sp& 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&& that) : fPtr(that.release()) {} + template ::value>::type> + sk_sp(sk_sp&& 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& 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& operator=(const sk_sp& that) { + if (this != &that) { + this->reset(SkSafeRef(that.get())); + } + return *this; + } + template ::value>::type> + sk_sp& operator=(const sk_sp& 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& operator=(sk_sp&& that) { + this->reset(that.release()); + return *this; + } + template ::value>::type> + sk_sp& operator=(sk_sp&& 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& that) /*noexcept*/ { + using std::swap; + swap(fPtr, that.fPtr); + } + + using sk_is_trivially_relocatable = std::true_type; + +private: + T* fPtr; +}; + +template inline void swap(sk_sp& a, sk_sp& b) /*noexcept*/ { + a.swap(b); +} + +template inline bool operator==(const sk_sp& a, const sk_sp& b) { + return a.get() == b.get(); +} +template inline bool operator==(const sk_sp& a, std::nullptr_t) /*noexcept*/ { + return !a; +} +template inline bool operator==(std::nullptr_t, const sk_sp& b) /*noexcept*/ { + return !b; +} + +template inline bool operator!=(const sk_sp& a, const sk_sp& b) { + return a.get() != b.get(); +} +template inline bool operator!=(const sk_sp& a, std::nullptr_t) /*noexcept*/ { + return static_cast(a); +} +template inline bool operator!=(std::nullptr_t, const sk_sp& b) /*noexcept*/ { + return static_cast(b); +} + +template +auto operator<<(std::basic_ostream& os, const sk_sp& sp) -> decltype(os << sp.get()) { + return os << sp.get(); +} + +template +sk_sp sk_make_sp(Args&&... args) { + return sk_sp(new T(std::forward(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 sk_sp sk_ref_sp(T* obj) { + return sk_sp(SkSafeRef(obj)); +} + +template sk_sp sk_ref_sp(const T* obj) { + return sk_sp(const_cast(SkSafeRef(obj))); +} + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkRegion.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkRegion.h new file mode 100644 index 0000000000..d72cd2ab7d --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkRegion.h @@ -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 +#include +#include + +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::value); + static_assert(::sk_is_trivially_relocatable::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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkSamplingOptions.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkSamplingOptions.h new file mode 100644 index 0000000000..4531a8c949 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkSamplingOptions.h @@ -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 +#include + +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(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(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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkScalar.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkScalar.h new file mode 100644 index 0000000000..d4150f6fb0 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkScalar.h @@ -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 + +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(x) +#define SkIntToFloat(x) static_cast(x) +#define SkScalarTruncToInt(x) sk_float_saturate2int(x) + +#define SkScalarToFloat(x) static_cast(x) +#define SkFloatToScalar(x) static_cast(x) +#define SkScalarToDouble(x) static_cast(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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkSerialProcs.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkSerialProcs.h new file mode 100644 index 0000000000..813488d0a7 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkSerialProcs.h @@ -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 +#include + +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 (*)(SkPicture*, void* ctx); +using SkSerialImageProc = sk_sp (*)(SkImage*, void* ctx); +using SkSerialTypefaceProc = sk_sp (*)(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 (*)(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 (*)(const void* data, size_t length, void* ctx); +#else +using SkDeserialImageProc = sk_sp (*)(const void* data, + size_t length, + std::optional, + void* ctx); +#endif +using SkDeserialImageFromDataProc = sk_sp (*)(sk_sp, + std::optional, + 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 (*)(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 (*)(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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkShader.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkShader.h new file mode 100644 index 0000000000..b650a03d7b --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkShader.h @@ -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 makeWithLocalMatrix(const SkMatrix&) const; + + /** + * Create a new shader that produces the same colors as invoking this shader and then applying + * the colorfilter. + */ + sk_sp makeWithColorFilter(sk_sp) 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 makeWithWorkingColorSpace(sk_sp) const; + +private: + SkShader() = default; + friend class SkShaderBase; + + using INHERITED = SkFlattenable; +}; + +namespace SkShaders { +SK_API sk_sp Empty(); +SK_API sk_sp Color(SkColor); +SK_API sk_sp Color(const SkColor4f&, sk_sp); +SK_API sk_sp Blend(SkBlendMode mode, sk_sp dst, sk_sp src); +SK_API sk_sp Blend(sk_sp, sk_sp dst, sk_sp src); +SK_API sk_sp CoordClamp(sk_sp, const SkRect& subset); + +/* + * Create an SkShader that will sample the 'image'. This is equivalent to SkImage::makeShader. + */ +SK_API sk_sp Image(sk_sp 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 RawImage(sk_sp image, + SkTileMode tmx, SkTileMode tmy, + const SkSamplingOptions& options, + const SkMatrix* localMatrix = nullptr); +} + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkSize.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkSize.h new file mode 100644 index 0000000000..3be747d274 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkSize.h @@ -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 + +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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkSpan.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkSpan.h new file mode 100644 index 0000000000..37cac632b1 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkSpan.h @@ -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 + diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkStream.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkStream.h new file mode 100644 index 0000000000..208bfe2903 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkStream.h @@ -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 +#include +#include +#include +#include +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 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 duplicate() const { + return std::unique_ptr(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 fork() const { + return std::unique_ptr(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 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 duplicate() const { + return std::unique_ptr(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 duplicate() const { + return std::unique_ptr(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 fork() const { + return std::unique_ptr(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 duplicate() const { + return std::unique_ptr(this->onDuplicate()); + } + std::unique_ptr fork() const { + return std::unique_ptr(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 duplicate() const { + return std::unique_ptr(this->onDuplicate()); + } + std::unique_ptr fork() const { + return std::unique_ptr(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 Make(const char path[]) { + std::unique_ptr 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 duplicate() const { + return std::unique_ptr(this->onDuplicate()); + } + + size_t getPosition() const override; + bool seek(size_t position) override; + bool move(long offset) override; + + std::unique_ptr fork() const { + return std::unique_ptr(this->onFork()); + } + + size_t getLength() const override; + +private: + explicit SkFILEStream(FILE*, size_t size, size_t start); + explicit SkFILEStream(std::shared_ptr, size_t end, size_t start); + explicit SkFILEStream(std::shared_ptr, size_t end, size_t start, size_t current); + + SkStreamAsset* onDuplicate() const override; + SkStreamAsset* onFork() const override; + + std::shared_ptr 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 data); + + /** Returns a stream with a copy of the input data. */ + static std::unique_ptr MakeCopy(const void* data, size_t length); + + /** Returns a stream with a bare pointer reference to the input data. */ + static std::unique_ptr MakeDirect(const void* data, size_t length); + + /** Returns a stream with a shared reference to the input data. */ + static std::unique_ptr Make(sk_sp 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 getData() const override { return fData; } + void setData(sk_sp 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 duplicate() const { + return std::unique_ptr(this->onDuplicate()); + } + + size_t getPosition() const override; + bool seek(size_t position) override; + bool move(long offset) override; + + std::unique_ptr fork() const { + return std::unique_ptr(this->onFork()); + } + + size_t getLength() const override; + + const void* getMemoryBase() override; + +private: + SkMemoryStream* onDuplicate() const override; + SkMemoryStream* onFork() const override; + + sk_sp 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 detachAsData(); + + /** Reset, returning a reader stream with the current content. */ + std::unique_ptr 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 diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkString.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkString.h new file mode 100644 index 0000000000..819e14d858 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkString.h @@ -0,0 +1,293 @@ +/* + * 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 SkString_DEFINED +#define SkString_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkTo.h" +#include "include/private/base/SkTypeTraits.h" + +#include +#include +#include +#include +#include +#include +#include + +/* Some helper functions for C strings */ +static inline bool SkStrStartsWith(const char string[], const char prefixStr[]) { + SkASSERT(string); + SkASSERT(prefixStr); + return !strncmp(string, prefixStr, strlen(prefixStr)); +} +static inline bool SkStrStartsWith(const char string[], const char prefixChar) { + SkASSERT(string); + return (prefixChar == *string); +} + +bool SkStrEndsWith(const char string[], const char suffixStr[]); +bool SkStrEndsWith(const char string[], const char suffixChar); + +int SkStrStartsWithOneOf(const char string[], const char prefixes[]); + +static inline int SkStrFind(const char string[], const char substring[]) { + const char *first = strstr(string, substring); + if (nullptr == first) return -1; + return SkToInt(first - &string[0]); +} + +static inline int SkStrFindLastOf(const char string[], const char subchar) { + const char* last = strrchr(string, subchar); + if (nullptr == last) return -1; + return SkToInt(last - &string[0]); +} + +static inline bool SkStrContains(const char string[], const char substring[]) { + SkASSERT(string); + SkASSERT(substring); + return (-1 != SkStrFind(string, substring)); +} +static inline bool SkStrContains(const char string[], const char subchar) { + SkASSERT(string); + char tmp[2]; + tmp[0] = subchar; + tmp[1] = '\0'; + return (-1 != SkStrFind(string, tmp)); +} + +/* + * The SkStrAppend... methods will write into the provided buffer, assuming it is large enough. + * Each method has an associated const (e.g. kSkStrAppendU32_MaxSize) which will be the largest + * value needed for that method's buffer. + * + * char storage[kSkStrAppendU32_MaxSize]; + * SkStrAppendU32(storage, value); + * + * Note : none of the SkStrAppend... methods write a terminating 0 to their buffers. Instead, + * the methods return the ptr to the end of the written part of the buffer. This can be used + * to compute the length, and/or know where to write a 0 if that is desired. + * + * char storage[kSkStrAppendU32_MaxSize + 1]; + * char* stop = SkStrAppendU32(storage, value); + * size_t len = stop - storage; + * *stop = 0; // valid, since storage was 1 byte larger than the max. + */ + +static constexpr int kSkStrAppendU32_MaxSize = 10; +char* SkStrAppendU32(char buffer[], uint32_t); +static constexpr int kSkStrAppendU64_MaxSize = 20; +char* SkStrAppendU64(char buffer[], uint64_t, int minDigits); + +static constexpr int kSkStrAppendS32_MaxSize = kSkStrAppendU32_MaxSize + 1; +char* SkStrAppendS32(char buffer[], int32_t); +static constexpr int kSkStrAppendS64_MaxSize = kSkStrAppendU64_MaxSize + 1; +char* SkStrAppendS64(char buffer[], int64_t, int minDigits); + +/** + * Floats have at most 8 significant digits, so we limit our %g to that. + * However, the total string could be 15 characters: -1.2345678e-005 + * + * In theory we should only expect up to 2 digits for the exponent, but on + * some platforms we have seen 3 (as in the example above). + */ +static constexpr int kSkStrAppendScalar_MaxSize = 15; + +/** + * Write the scalar in decimal format into buffer, and return a pointer to + * the next char after the last one written. Note: a terminating 0 is not + * written into buffer, which must be at least kSkStrAppendScalar_MaxSize. + * Thus if the caller wants to add a 0 at the end, buffer must be at least + * kSkStrAppendScalar_MaxSize + 1 bytes large. + */ +char* SkStrAppendScalar(char buffer[], SkScalar); + +/** \class SkString + + Light weight class for managing strings. Uses reference + counting to make string assignments and copies very fast + with no extra RAM cost. Assumes UTF8 encoding. +*/ +class SK_API SkString { +public: + SkString(); + explicit SkString(size_t len); + explicit SkString(const char text[]); + SkString(const char text[], size_t len); + SkString(const SkString&); + SkString(SkString&&); + explicit SkString(const std::string&); + explicit SkString(std::string_view); + ~SkString(); + + bool isEmpty() const { return 0 == fRec->fLength; } + size_t size() const { return (size_t) fRec->fLength; } + const char* data() const { return fRec->data(); } + const char* c_str() const { return fRec->data(); } + char operator[](size_t n) const { return this->c_str()[n]; } + + bool equals(const SkString&) const; + bool equals(const char text[]) const; + bool equals(const char text[], size_t len) const; + + bool startsWith(const char prefixStr[]) const { + return SkStrStartsWith(fRec->data(), prefixStr); + } + bool startsWith(const char prefixChar) const { + return SkStrStartsWith(fRec->data(), prefixChar); + } + bool endsWith(const char suffixStr[]) const { + return SkStrEndsWith(fRec->data(), suffixStr); + } + bool endsWith(const char suffixChar) const { + return SkStrEndsWith(fRec->data(), suffixChar); + } + bool contains(const char substring[]) const { + return SkStrContains(fRec->data(), substring); + } + bool contains(const char subchar) const { + return SkStrContains(fRec->data(), subchar); + } + int find(const char substring[]) const { + return SkStrFind(fRec->data(), substring); + } + int findLastOf(const char subchar) const { + return SkStrFindLastOf(fRec->data(), subchar); + } + + friend bool operator==(const SkString& a, const SkString& b) { + return a.equals(b); + } + friend bool operator!=(const SkString& a, const SkString& b) { + return !a.equals(b); + } + + // these methods edit the string + + SkString& operator=(const SkString&); + SkString& operator=(SkString&&); + SkString& operator=(const char text[]); + + char* data(); + char& operator[](size_t n) { return this->data()[n]; } + + void reset(); + /** String contents are preserved on resize. (For destructive resize, `set(nullptr, length)`.) + * `resize` automatically reserves an extra byte at the end of the buffer for a null terminator. + */ + void resize(size_t len); + void set(const SkString& src) { *this = src; } + void set(const char text[]); + void set(const char text[], size_t len); + void set(std::string_view str) { this->set(str.data(), str.size()); } + + void insert(size_t offset, const char text[]); + void insert(size_t offset, const char text[], size_t len); + void insert(size_t offset, const SkString& str) { this->insert(offset, str.c_str(), str.size()); } + void insert(size_t offset, std::string_view str) { this->insert(offset, str.data(), str.size()); } + void insertUnichar(size_t offset, SkUnichar); + void insertS32(size_t offset, int32_t value); + void insertS64(size_t offset, int64_t value, int minDigits = 0); + void insertU32(size_t offset, uint32_t value); + void insertU64(size_t offset, uint64_t value, int minDigits = 0); + void insertHex(size_t offset, uint32_t value, int minDigits = 0); + void insertScalar(size_t offset, SkScalar); + + void append(const char text[]) { this->insert((size_t)-1, text); } + void append(const char text[], size_t len) { this->insert((size_t)-1, text, len); } + void append(const SkString& str) { this->insert((size_t)-1, str.c_str(), str.size()); } + void append(std::string_view str) { this->insert((size_t)-1, str.data(), str.size()); } + void appendUnichar(SkUnichar uni) { this->insertUnichar((size_t)-1, uni); } + void appendS32(int32_t value) { this->insertS32((size_t)-1, value); } + void appendS64(int64_t value, int minDigits = 0) { this->insertS64((size_t)-1, value, minDigits); } + void appendU32(uint32_t value) { this->insertU32((size_t)-1, value); } + void appendU64(uint64_t value, int minDigits = 0) { this->insertU64((size_t)-1, value, minDigits); } + void appendHex(uint32_t value, int minDigits = 0) { this->insertHex((size_t)-1, value, minDigits); } + void appendScalar(SkScalar value) { this->insertScalar((size_t)-1, value); } + + void prepend(const char text[]) { this->insert(0, text); } + void prepend(const char text[], size_t len) { this->insert(0, text, len); } + void prepend(const SkString& str) { this->insert(0, str.c_str(), str.size()); } + void prepend(std::string_view str) { this->insert(0, str.data(), str.size()); } + void prependUnichar(SkUnichar uni) { this->insertUnichar(0, uni); } + void prependS32(int32_t value) { this->insertS32(0, value); } + void prependS64(int32_t value, int minDigits = 0) { this->insertS64(0, value, minDigits); } + void prependHex(uint32_t value, int minDigits = 0) { this->insertHex(0, value, minDigits); } + void prependScalar(SkScalar value) { this->insertScalar((size_t)-1, value); } + + void printf(const char format[], ...) SK_PRINTF_LIKE(2, 3); + void printVAList(const char format[], va_list) SK_PRINTF_LIKE(2, 0); + void appendf(const char format[], ...) SK_PRINTF_LIKE(2, 3); + void appendVAList(const char format[], va_list) SK_PRINTF_LIKE(2, 0); + void prependf(const char format[], ...) SK_PRINTF_LIKE(2, 3); + void prependVAList(const char format[], va_list) SK_PRINTF_LIKE(2, 0); + + void remove(size_t offset, size_t length); + + SkString& operator+=(const SkString& s) { this->append(s); return *this; } + SkString& operator+=(const char text[]) { this->append(text); return *this; } + SkString& operator+=(const char c) { this->append(&c, 1); return *this; } + + /** + * Swap contents between this and other. This function is guaranteed + * to never fail or throw. + */ + void swap(SkString& other); + + using sk_is_trivially_relocatable = std::true_type; + +private: + struct Rec { + public: + constexpr Rec(uint32_t len, int32_t refCnt) : fLength(len), fRefCnt(refCnt) {} + static sk_sp Make(const char text[], size_t len); + char* data() { return fBeginningOfData; } + const char* data() const { return fBeginningOfData; } + void ref() const; + void unref() const; + bool unique() const; +#ifdef SK_DEBUG + int32_t getRefCnt() const; +#endif + uint32_t fLength; // logically size_t, but we want it to stay 32 bits + + private: + mutable std::atomic fRefCnt; + char fBeginningOfData[1] = {'\0'}; + + // Ensure the unsized delete is called. + void operator delete(void* p) { ::operator delete(p); } + }; + sk_sp fRec; + + static_assert(::sk_is_trivially_relocatable::value); + +#ifdef SK_DEBUG + SkString& validate(); + const SkString& validate() const; +#else + SkString& validate() { return *this; } + const SkString& validate() const { return *this; } +#endif + + static const Rec gEmptyRec; +}; + +/// Creates a new string and writes into it using a printf()-style format. +SK_API SkString SkStringPrintf(const char* format, ...) SK_PRINTF_LIKE(1, 2); +/// This makes it easier to write a caller as a VAR_ARGS function where the format string is +/// optional. +static inline SkString SkStringPrintf() { return SkString(); } + +static inline void swap(SkString& a, SkString& b) { + a.swap(b); +} + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkStrokeRec.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkStrokeRec.h new file mode 100644 index 0000000000..8617b25407 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkStrokeRec.h @@ -0,0 +1,159 @@ +/* + * 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 SkStrokeRec_DEFINED +#define SkStrokeRec_DEFINED + +#include "include/core/SkPaint.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkMacros.h" + +#include +#include + +class SkPath; + +SK_BEGIN_REQUIRE_DENSE +class SK_API SkStrokeRec { +public: + enum InitStyle { + kHairline_InitStyle, + kFill_InitStyle + }; + SkStrokeRec(InitStyle style); + SkStrokeRec(const SkPaint&, SkPaint::Style, SkScalar resScale = 1); + explicit SkStrokeRec(const SkPaint&, SkScalar resScale = 1); + + enum Style { + kHairline_Style, + kFill_Style, + kStroke_Style, + kStrokeAndFill_Style + }; + + static constexpr int kStyleCount = kStrokeAndFill_Style + 1; + + Style getStyle() const; + SkScalar getWidth() const { return fWidth; } + SkScalar getMiter() const { return fMiterLimit; } + SkPaint::Cap getCap() const { return (SkPaint::Cap)fCap; } + SkPaint::Join getJoin() const { return (SkPaint::Join)fJoin; } + + bool isHairlineStyle() const { + return kHairline_Style == this->getStyle(); + } + + bool isFillStyle() const { + return kFill_Style == this->getStyle(); + } + + void setFillStyle(); + void setHairlineStyle(); + /** + * Specify the strokewidth, and optionally if you want stroke + fill. + * Note, if width==0, then this request is taken to mean: + * strokeAndFill==true -> new style will be Fill + * strokeAndFill==false -> new style will be Hairline + */ + void setStrokeStyle(SkScalar width, bool strokeAndFill = false); + + void setStrokeParams(SkPaint::Cap cap, SkPaint::Join join, SkScalar miterLimit) { + fCap = cap; + fJoin = join; + fMiterLimit = miterLimit; + } + + SkScalar getResScale() const { + return fResScale; + } + + void setResScale(SkScalar rs) { + SkASSERT(rs > 0 && std::isfinite(rs)); + fResScale = rs; + } + + /** + * Returns true if this specifes any thick stroking, i.e. applyToPath() + * will return true. + */ + bool needToApply() const { + Style style = this->getStyle(); + return (kStroke_Style == style) || (kStrokeAndFill_Style == style); + } + + /** + * Apply these stroke parameters to the src path, returning the result + * in dst. + * + * If there was no change (i.e. style == hairline or fill) this returns + * false and dst is unchanged. Otherwise returns true and the result is + * stored in dst. + * + * src and dst may be the same path. + */ + bool applyToPath(SkPath* dst, const SkPath& src) const; + + /** + * Apply these stroke parameters to a paint. + */ + void applyToPaint(SkPaint* paint) const; + + /** + * Gives a conservative value for the outset that should applied to a + * geometries bounds to account for any inflation due to applying this + * strokeRec to the geometry. + */ + SkScalar getInflationRadius() const; + + /** + * Equivalent to: + * SkStrokeRec rec(paint, style); + * rec.getInflationRadius(); + * This does not account for other effects on the paint (i.e. path + * effect). + */ + static SkScalar GetInflationRadius(const SkPaint&, SkPaint::Style); + + static SkScalar GetInflationRadius(SkPaint::Join, SkScalar miterLimit, SkPaint::Cap, + SkScalar strokeWidth); + + /** + * Compare if two SkStrokeRecs have an equal effect on a path. + * Equal SkStrokeRecs produce equal paths. Equality of produced + * paths does not take the ResScale parameter into account. + */ + bool hasEqualEffect(const SkStrokeRec& other) const { + if (!this->needToApply()) { + return this->getStyle() == other.getStyle(); + } + return fWidth == other.fWidth && + (fJoin != SkPaint::kMiter_Join || fMiterLimit == other.fMiterLimit) && + fCap == other.fCap && + fJoin == other.fJoin && + fStrokeAndFill == other.fStrokeAndFill; + } + +private: + void init(const SkPaint&, SkPaint::Style, SkScalar resScale); + + SkScalar fResScale; + SkScalar fWidth; + SkScalar fMiterLimit; + // The following three members are packed together into a single u32. + // This is to avoid unnecessary padding and ensure binary equality for + // hashing (because the padded areas might contain garbage values). + // + // fCap and fJoin are larger than needed to avoid having to initialize + // any pad values + uint32_t fCap : 16; // SkPaint::Cap + uint32_t fJoin : 15; // SkPaint::Join + uint32_t fStrokeAndFill : 1; // bool +}; +SK_END_REQUIRE_DENSE + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkSurface.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkSurface.h new file mode 100644 index 0000000000..72f1bc2bf0 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkSurface.h @@ -0,0 +1,659 @@ +/* + * 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 SkSurface_DEFINED +#define SkSurface_DEFINED + +#include "include/core/SkImage.h" +#include "include/core/SkImageInfo.h" +#include "include/core/SkPixmap.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkSamplingOptions.h" +#include "include/core/SkScalar.h" +#include "include/core/SkSurfaceProps.h" +#include "include/core/SkTypes.h" + +#include +#include +#include + +class GrBackendSemaphore; +class GrBackendTexture; +class GrRecordingContext; +class GrSurfaceCharacterization; +enum GrSurfaceOrigin : int; +class SkBitmap; +class SkCanvas; +class SkCapabilities; +class SkColorSpace; +class SkPaint; +class SkSurface; +struct SkIRect; +struct SkISize; + +namespace skgpu::graphite { +class Recorder; +} + +namespace SkSurfaces { + +enum class BackendSurfaceAccess { + kNoAccess, //!< back-end surface will not be used by client + kPresent, //!< back-end surface will be used for presenting to screen +}; + +/** Returns SkSurface without backing pixels. Drawing to SkCanvas returned from SkSurface + has no effect. Calling makeImageSnapshot() on returned SkSurface returns nullptr. + + @param width one or greater + @param height one or greater + @return SkSurface if width and height are positive; otherwise, nullptr + + example: https://fiddle.skia.org/c/@Surface_MakeNull +*/ +SK_API sk_sp Null(int width, int height); + +/** Allocates raster SkSurface. SkCanvas returned by SkSurface draws directly into those allocated + pixels, which are zeroed before use. Pixel memory size is imageInfo.height() times + imageInfo.minRowBytes() or rowBytes, if provided and non-zero. + + Pixel memory is deleted when SkSurface is deleted. + + Validity constraints include: + - info dimensions are greater than zero; + - info contains SkColorType and SkAlphaType supported by raster surface. + + @param imageInfo width, height, SkColorType, SkAlphaType, SkColorSpace, + of raster surface; width and height must be greater than zero + @param rowBytes interval from one SkSurface row to the next. + @param props LCD striping orientation and setting for device independent fonts; + may be nullptr + @return SkSurface if parameters are valid and memory was allocated, else nullptr. +*/ +SK_API sk_sp Raster(const SkImageInfo& imageInfo, + size_t rowBytes, + const SkSurfaceProps* surfaceProps); +inline sk_sp Raster(const SkImageInfo& imageInfo, + const SkSurfaceProps* props = nullptr) { + return Raster(imageInfo, 0, props); +} + +/** Allocates raster SkSurface. SkCanvas returned by SkSurface draws directly into the + provided pixels. + + SkSurface is returned if all parameters are valid. + Valid parameters include: + info dimensions are greater than zero; + info contains SkColorType and SkAlphaType supported by raster surface; + pixels is not nullptr; + rowBytes is large enough to contain info width pixels of SkColorType. + + Pixel buffer size should be info height times computed rowBytes. + Pixels are not initialized. + To access pixels after drawing, peekPixels() or readPixels(). + + @param imageInfo width, height, SkColorType, SkAlphaType, SkColorSpace, + of raster surface; width and height must be greater than zero + @param pixels pointer to destination pixels buffer + @param rowBytes interval from one SkSurface row to the next + @param surfaceProps LCD striping orientation and setting for device independent fonts; + may be nullptr + @return SkSurface if all parameters are valid; otherwise, nullptr +*/ + +SK_API sk_sp WrapPixels(const SkImageInfo& imageInfo, + void* pixels, + size_t rowBytes, + const SkSurfaceProps* surfaceProps = nullptr); +inline sk_sp WrapPixels(const SkPixmap& pm, const SkSurfaceProps* props = nullptr) { + return WrapPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), props); +} + +using PixelsReleaseProc = void(void* pixels, void* context); + +/** Allocates raster SkSurface. SkCanvas returned by SkSurface draws directly into the provided + pixels. releaseProc is called with pixels and context when SkSurface is deleted. + + SkSurface is returned if all parameters are valid. + Valid parameters include: + info dimensions are greater than zero; + info contains SkColorType and SkAlphaType supported by raster surface; + pixels is not nullptr; + rowBytes is large enough to contain info width pixels of SkColorType. + + Pixel buffer size should be info height times computed rowBytes. + Pixels are not initialized. + To access pixels after drawing, call flush() or peekPixels(). + + @param imageInfo width, height, SkColorType, SkAlphaType, SkColorSpace, + of raster surface; width and height must be greater than zero + @param pixels pointer to destination pixels buffer + @param rowBytes interval from one SkSurface row to the next + @param releaseProc called when SkSurface is deleted; may be nullptr + @param context passed to releaseProc; may be nullptr + @param surfaceProps LCD striping orientation and setting for device independent fonts; + may be nullptr + @return SkSurface if all parameters are valid; otherwise, nullptr +*/ +SK_API sk_sp WrapPixels(const SkImageInfo& imageInfo, + void* pixels, + size_t rowBytes, + PixelsReleaseProc, + void* context, + const SkSurfaceProps* surfaceProps = nullptr); +} // namespace SkSurfaces + +/** \class SkSurface + SkSurface is responsible for managing the pixels that a canvas draws into. The pixels can be + allocated either in CPU memory (a raster surface) or on the GPU (a GrRenderTarget surface). + SkSurface takes care of allocating a SkCanvas that will draw into the surface. Call + surface->getCanvas() to use that canvas (but don't delete it, it is owned by the surface). + SkSurface always has non-zero dimensions. If there is a request for a new surface, and either + of the requested dimensions are zero, then nullptr will be returned. + + Clients should *not* subclass SkSurface as there is a lot of internal machinery that is + not publicly accessible. +*/ +class SK_API SkSurface : public SkRefCnt { +public: + /** Is this surface compatible with the provided characterization? + + This method can be used to determine if an existing SkSurface is a viable destination + for an GrDeferredDisplayList. + + @param characterization The characterization for which a compatibility check is desired + @return true if this surface is compatible with the characterization; + false otherwise + */ + bool isCompatible(const GrSurfaceCharacterization& characterization) const; + + /** Returns pixel count in each row; may be zero or greater. + + @return number of pixel columns + */ + int width() const { return fWidth; } + + /** Returns pixel row count; may be zero or greater. + + @return number of pixel rows + */ + int height() const { return fHeight; } + + /** Returns an ImageInfo describing the surface. + */ + virtual SkImageInfo imageInfo() const { return SkImageInfo::MakeUnknown(fWidth, fHeight); } + + /** Returns unique value identifying the content of SkSurface. Returned value changes + each time the content changes. Content is changed by drawing, or by calling + notifyContentWillChange(). + + @return unique content identifier + + example: https://fiddle.skia.org/c/@Surface_notifyContentWillChange + */ + uint32_t generationID(); + + /** \enum SkSurface::ContentChangeMode + ContentChangeMode members are parameters to notifyContentWillChange(). + */ + enum ContentChangeMode { + kDiscard_ContentChangeMode, //!< discards surface on change + kRetain_ContentChangeMode, //!< preserves surface on change + }; + + /** Notifies that SkSurface contents will be changed by code outside of Skia. + Subsequent calls to generationID() return a different value. + + TODO: Can kRetain_ContentChangeMode be deprecated? + + example: https://fiddle.skia.org/c/@Surface_notifyContentWillChange + */ + void notifyContentWillChange(ContentChangeMode mode); + + /** Returns the recording context being used by the SkSurface. + + @return the recording context, if available; nullptr otherwise + */ + GrRecordingContext* recordingContext() const; + + /** Returns the recorder being used by the SkSurface. + + @return the recorder, if available; nullptr otherwise + */ + skgpu::graphite::Recorder* recorder() const; + + enum class BackendHandleAccess { + kFlushRead, //!< back-end object is readable + kFlushWrite, //!< back-end object is writable + kDiscardWrite, //!< back-end object must be overwritten + + // Legacy names, remove when clients are migrated + kFlushRead_BackendHandleAccess = kFlushRead, + kFlushWrite_BackendHandleAccess = kFlushWrite, + kDiscardWrite_BackendHandleAccess = kDiscardWrite, + }; + + // Legacy names, remove when clients are migrated + static constexpr BackendHandleAccess kFlushRead_BackendHandleAccess = + BackendHandleAccess::kFlushRead; + static constexpr BackendHandleAccess kFlushWrite_BackendHandleAccess = + BackendHandleAccess::kFlushWrite; + static constexpr BackendHandleAccess kDiscardWrite_BackendHandleAccess = + BackendHandleAccess::kDiscardWrite; + + /** Caller data passed to TextureReleaseProc; may be nullptr. */ + using ReleaseContext = void*; + /** User function called when supplied texture may be deleted. */ + using TextureReleaseProc = void (*)(ReleaseContext); + + /** If the surface was made via MakeFromBackendTexture then it's backing texture may be + substituted with a different texture. The contents of the previous backing texture are + copied into the new texture. SkCanvas state is preserved. The original sample count is + used. The GrBackendFormat and dimensions of replacement texture must match that of + the original. + + Upon success textureReleaseProc is called when it is safe to delete the texture in the + backend API (accounting only for use of the texture by this surface). If SkSurface creation + fails textureReleaseProc is called before this function returns. + + @param backendTexture the new backing texture for the surface + @param mode Retain or discard current Content + @param TextureReleaseProc function called when texture can be released + @param ReleaseContext state passed to textureReleaseProc + */ + virtual bool replaceBackendTexture(const GrBackendTexture& backendTexture, + GrSurfaceOrigin origin, + ContentChangeMode mode = kRetain_ContentChangeMode, + TextureReleaseProc = nullptr, + ReleaseContext = nullptr) = 0; + + /** Returns SkCanvas that draws into SkSurface. Subsequent calls return the same SkCanvas. + SkCanvas returned is managed and owned by SkSurface, and is deleted when SkSurface + is deleted. + + @return drawing SkCanvas for SkSurface + + example: https://fiddle.skia.org/c/@Surface_getCanvas + */ + SkCanvas* getCanvas(); + + /** Returns SkCapabilities that describes the capabilities of the SkSurface's device. + + @return SkCapabilities of SkSurface's device. + */ + sk_sp capabilities(); + + /** Returns a compatible SkSurface, or nullptr. Returned SkSurface contains + the same raster, GPU, or null properties as the original. Returned SkSurface + does not share the same pixels. + + Returns nullptr if imageInfo width or height are zero, or if imageInfo + is incompatible with SkSurface. + + @param imageInfo width, height, SkColorType, SkAlphaType, SkColorSpace, + of SkSurface; width and height must be greater than zero + @return compatible SkSurface or nullptr + + example: https://fiddle.skia.org/c/@Surface_makeSurface + */ + sk_sp makeSurface(const SkImageInfo& imageInfo); + + /** Calls makeSurface(ImageInfo) with the same ImageInfo as this surface, but with the + * specified width and height. + */ + sk_sp makeSurface(int width, int height); + + /** Returns SkImage capturing SkSurface contents. Subsequent drawing to SkSurface contents + are not captured. SkImage allocation is accounted for if SkSurface was created with + skgpu::Budgeted::kYes. + + @return SkImage initialized with SkSurface contents + + example: https://fiddle.skia.org/c/@Surface_makeImageSnapshot + */ + sk_sp makeImageSnapshot(); + + /** + * Like the no-parameter version, this returns an image of the current surface contents. + * This variant takes a rectangle specifying the subset of the surface that is of interest. + * These bounds will be sanitized before being used. + * - If bounds extends beyond the surface, it will be trimmed to just the intersection of + * it and the surface. + * - If bounds does not intersect the surface, then this returns nullptr. + * - If bounds == the surface, then this is the same as calling the no-parameter variant. + + example: https://fiddle.skia.org/c/@Surface_makeImageSnapshot_2 + */ + sk_sp makeImageSnapshot(const SkIRect& bounds); + + /** Draws SkSurface contents to canvas, with its top-left corner at (x, y). + + If SkPaint paint is not nullptr, apply SkColorFilter, alpha, SkImageFilter, and SkBlendMode. + + @param canvas SkCanvas drawn into + @param x horizontal offset in SkCanvas + @param y vertical offset in SkCanvas + @param sampling what technique to use when sampling the surface pixels + @param paint SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter, + and so on; or nullptr + + example: https://fiddle.skia.org/c/@Surface_draw + */ + void draw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkSamplingOptions& sampling, + const SkPaint* paint); + + void draw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint = nullptr) { + this->draw(canvas, x, y, SkSamplingOptions(), paint); + } + + /** Copies SkSurface pixel address, row bytes, and SkImageInfo to SkPixmap, if address + is available, and returns true. If pixel address is not available, return + false and leave SkPixmap unchanged. + + pixmap contents become invalid on any future change to SkSurface. + + @param pixmap storage for pixel state if pixels are readable; otherwise, ignored + @return true if SkSurface has direct access to pixels + + example: https://fiddle.skia.org/c/@Surface_peekPixels + */ + bool peekPixels(SkPixmap* pixmap); + + /** Copies SkRect of pixels to dst. + + Source SkRect corners are (srcX, srcY) and SkSurface (width(), height()). + Destination SkRect corners are (0, 0) and (dst.width(), dst.height()). + Copies each readable pixel intersecting both rectangles, without scaling, + converting to dst.colorType() and dst.alphaType() if required. + + Pixels are readable when SkSurface is raster, or backed by a GPU. + + The destination pixel storage must be allocated by the caller. + + Pixel values are converted only if SkColorType and SkAlphaType + do not match. Only pixels within both source and destination rectangles + are copied. dst contents outside SkRect intersection are unchanged. + + Pass negative values for srcX or srcY to offset pixels across or down destination. + + Does not copy, and returns false if: + - Source and destination rectangles do not intersect. + - SkPixmap pixels could not be allocated. + - dst.rowBytes() is too small to contain one row of pixels. + + @param dst storage for pixels copied from SkSurface + @param srcX offset into readable pixels on x-axis; may be negative + @param srcY offset into readable pixels on y-axis; may be negative + @return true if pixels were copied + + example: https://fiddle.skia.org/c/@Surface_readPixels + */ + bool readPixels(const SkPixmap& dst, int srcX, int srcY); + + /** Copies SkRect of pixels from SkCanvas into dstPixels. + + Source SkRect corners are (srcX, srcY) and SkSurface (width(), height()). + Destination SkRect corners are (0, 0) and (dstInfo.width(), dstInfo.height()). + Copies each readable pixel intersecting both rectangles, without scaling, + converting to dstInfo.colorType() and dstInfo.alphaType() if required. + + Pixels are readable when SkSurface is raster, or backed by a GPU. + + The destination pixel storage must be allocated by the caller. + + Pixel values are converted only if SkColorType and SkAlphaType + do not match. Only pixels within both source and destination rectangles + are copied. dstPixels contents outside SkRect intersection are unchanged. + + Pass negative values for srcX or srcY to offset pixels across or down destination. + + Does not copy, and returns false if: + - Source and destination rectangles do not intersect. + - SkSurface pixels could not be converted to dstInfo.colorType() or dstInfo.alphaType(). + - dstRowBytes is too small to contain one row of pixels. + + @param dstInfo width, height, SkColorType, and SkAlphaType of dstPixels + @param dstPixels storage for pixels; dstInfo.height() times dstRowBytes, or larger + @param dstRowBytes size of one destination row; dstInfo.width() times pixel size, or larger + @param srcX offset into readable pixels on x-axis; may be negative + @param srcY offset into readable pixels on y-axis; may be negative + @return true if pixels were copied + */ + bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, + int srcX, int srcY); + + /** Copies SkRect of pixels from SkSurface into bitmap. + + Source SkRect corners are (srcX, srcY) and SkSurface (width(), height()). + Destination SkRect corners are (0, 0) and (bitmap.width(), bitmap.height()). + Copies each readable pixel intersecting both rectangles, without scaling, + converting to bitmap.colorType() and bitmap.alphaType() if required. + + Pixels are readable when SkSurface is raster, or backed by a GPU. + + The destination pixel storage must be allocated by the caller. + + Pixel values are converted only if SkColorType and SkAlphaType + do not match. Only pixels within both source and destination rectangles + are copied. dst contents outside SkRect intersection are unchanged. + + Pass negative values for srcX or srcY to offset pixels across or down destination. + + Does not copy, and returns false if: + - Source and destination rectangles do not intersect. + - SkSurface pixels could not be converted to dst.colorType() or dst.alphaType(). + - dst pixels could not be allocated. + - dst.rowBytes() is too small to contain one row of pixels. + + @param dst storage for pixels copied from SkSurface + @param srcX offset into readable pixels on x-axis; may be negative + @param srcY offset into readable pixels on y-axis; may be negative + @return true if pixels were copied + + example: https://fiddle.skia.org/c/@Surface_readPixels_3 + */ + bool readPixels(const SkBitmap& dst, int srcX, int srcY); + + using AsyncReadResult = SkImage::AsyncReadResult; + + /** 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); + + /** Controls the gamma that rescaling occurs in for asyncRescaleAndReadPixels() and + asyncRescaleAndReadPixelsYUV420(). + */ + using RescaleGamma = SkImage::RescaleGamma; + using RescaleMode = SkImage::RescaleMode; + + /** Makes surface pixel data available to caller, possibly asynchronously. It can also rescale + the surface 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 surface + 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 surface 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 + SkSurface 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 surface to read + @param rescaleGamma controls whether rescaling is done in the surface's gamma or whether + the source data is transformed to a linear gamma before rescaling. + @param rescaleMode controls the technique 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); + + /** + 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 + surface 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 surface 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 + SkSurface 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 surface to rescale and convert to YUV planes. + @param dstSize The size to rescale srcRect to + @param rescaleGamma controls whether rescaling is done in the surface's gamma or whether + the source data is transformed to a linear gamma before rescaling. + @param rescaleMode controls the sampling technique of the rescaling + @param callback function to call with the planar read result + @param context passed to callback + */ + void asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace, + sk_sp dstColorSpace, + const SkIRect& srcRect, + const SkISize& dstSize, + RescaleGamma rescaleGamma, + RescaleMode rescaleMode, + ReadPixelsCallback callback, + ReadPixelsContext context); + + /** + * 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 dstColorSpace, + const SkIRect& srcRect, + const SkISize& dstSize, + RescaleGamma rescaleGamma, + RescaleMode rescaleMode, + ReadPixelsCallback callback, + ReadPixelsContext context); + + /** Copies SkRect of pixels from the src SkPixmap to the SkSurface. + + Source SkRect corners are (0, 0) and (src.width(), src.height()). + Destination SkRect corners are (dstX, dstY) and + (dstX + Surface width(), dstY + Surface height()). + + Copies each readable pixel intersecting both rectangles, without scaling, + converting to SkSurface colorType() and SkSurface alphaType() if required. + + @param src storage for pixels to copy to SkSurface + @param dstX x-axis position relative to SkSurface to begin copy; may be negative + @param dstY y-axis position relative to SkSurface to begin copy; may be negative + + example: https://fiddle.skia.org/c/@Surface_writePixels + */ + void writePixels(const SkPixmap& src, int dstX, int dstY); + + /** Copies SkRect of pixels from the src SkBitmap to the SkSurface. + + Source SkRect corners are (0, 0) and (src.width(), src.height()). + Destination SkRect corners are (dstX, dstY) and + (dstX + Surface width(), dstY + Surface height()). + + Copies each readable pixel intersecting both rectangles, without scaling, + converting to SkSurface colorType() and SkSurface alphaType() if required. + + @param src storage for pixels to copy to SkSurface + @param dstX x-axis position relative to SkSurface to begin copy; may be negative + @param dstY y-axis position relative to SkSurface to begin copy; may be negative + + example: https://fiddle.skia.org/c/@Surface_writePixels_2 + */ + void writePixels(const SkBitmap& src, int dstX, int dstY); + + /** Returns SkSurfaceProps for surface. + + @return LCD striping orientation and setting for device independent fonts + */ + const SkSurfaceProps& props() const { return fProps; } + + /** Inserts a list of GPU semaphores that the current GPU-backed API must wait on before + executing any more commands on the GPU for this surface. We only guarantee blocking + transfer and fragment shader work, but may block earlier stages as well depending on the + backend. + If this call returns false, then the GPU back-end will not wait on any passed in + semaphores, and the client will still own the semaphores, regardless of the value of + deleteSemaphoresAfterWait. + + If deleteSemaphoresAfterWait is false then Skia will not delete the semaphores. In this case + it is the client's responsibility to not destroy or attempt to reuse the semaphores until it + knows that Skia has finished waiting on them. This can be done by using finishedProcs + on flush calls. + + @param numSemaphores size of waitSemaphores array + @param waitSemaphores array of semaphore containers + @paramm deleteSemaphoresAfterWait who owns and should delete the semaphores + @return true if GPU is waiting on semaphores + */ + bool wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores, + bool deleteSemaphoresAfterWait = true); + + /** Initializes GrSurfaceCharacterization that can be used to perform GPU back-end + processing in a separate thread. Typically this is used to divide drawing + into multiple tiles. GrDeferredDisplayListRecorder records the drawing commands + for each tile. + + Return true if SkSurface supports characterization. raster surface returns false. + + @param characterization properties for parallel drawing + @return true if supported + + example: https://fiddle.skia.org/c/@Surface_characterize + */ + bool characterize(GrSurfaceCharacterization* characterization) const; + +protected: + SkSurface(int width, int height, const SkSurfaceProps* surfaceProps); + SkSurface(const SkImageInfo& imageInfo, const SkSurfaceProps* surfaceProps); + + // called by subclass if their contents have changed + void dirtyGenerationID() { + fGenerationID = 0; + } + +private: + const SkSurfaceProps fProps; + const int fWidth; + const int fHeight; + uint32_t fGenerationID; + + using INHERITED = SkRefCnt; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkSurfaceProps.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkSurfaceProps.h new file mode 100644 index 0000000000..d8509bf53e --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkSurfaceProps.h @@ -0,0 +1,116 @@ +/* + * 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 SkSurfaceProps_DEFINED +#define SkSurfaceProps_DEFINED + +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkTo.h" + +/** + * Description of how the LCD strips are arranged for each pixel. If this is unknown, or the + * pixels are meant to be "portable" and/or transformed before showing (e.g. rotated, scaled) + * then use kUnknown_SkPixelGeometry. + */ +enum SkPixelGeometry { + kUnknown_SkPixelGeometry, + kRGB_H_SkPixelGeometry, + kBGR_H_SkPixelGeometry, + kRGB_V_SkPixelGeometry, + kBGR_V_SkPixelGeometry, +}; + +// Returns true iff geo is a known geometry and is RGB. +static inline bool SkPixelGeometryIsRGB(SkPixelGeometry geo) { + return kRGB_H_SkPixelGeometry == geo || kRGB_V_SkPixelGeometry == geo; +} + +// Returns true iff geo is a known geometry and is BGR. +static inline bool SkPixelGeometryIsBGR(SkPixelGeometry geo) { + return kBGR_H_SkPixelGeometry == geo || kBGR_V_SkPixelGeometry == geo; +} + +// Returns true iff geo is a known geometry and is horizontal. +static inline bool SkPixelGeometryIsH(SkPixelGeometry geo) { + return kRGB_H_SkPixelGeometry == geo || kBGR_H_SkPixelGeometry == geo; +} + +// Returns true iff geo is a known geometry and is vertical. +static inline bool SkPixelGeometryIsV(SkPixelGeometry geo) { + return kRGB_V_SkPixelGeometry == geo || kBGR_V_SkPixelGeometry == geo; +} + +/** + * Describes properties and constraints of a given SkSurface. The rendering engine can parse these + * during drawing, and can sometimes optimize its performance (e.g. disabling an expensive + * feature). + */ +class SK_API SkSurfaceProps { +public: + enum Flags { + kDefault_Flag = 0, + kUseDeviceIndependentFonts_Flag = 1 << 0, + // Use internal MSAA to render to non-MSAA GPU surfaces. + kDynamicMSAA_Flag = 1 << 1, + // If set, all rendering will have dithering enabled + // Currently this only impacts GPU backends + kAlwaysDither_Flag = 1 << 2, + }; + + /** No flags, unknown pixel geometry, platform-default contrast/gamma. */ + SkSurfaceProps(); + /** TODO(kschmi): Remove this constructor and replace with the one below. **/ + SkSurfaceProps(uint32_t flags, SkPixelGeometry); + /** Specified pixel geometry, text contrast, and gamma **/ + SkSurfaceProps(uint32_t flags, SkPixelGeometry, SkScalar textContrast, SkScalar textGamma); + + SkSurfaceProps(const SkSurfaceProps&) = default; + SkSurfaceProps& operator=(const SkSurfaceProps&) = default; + + SkSurfaceProps cloneWithPixelGeometry(SkPixelGeometry newPixelGeometry) const { + return SkSurfaceProps(fFlags, newPixelGeometry, fTextContrast, fTextGamma); + } + + static constexpr SkScalar kMaxContrastInclusive = 1; + static constexpr SkScalar kMinContrastInclusive = 0; + static constexpr SkScalar kMaxGammaExclusive = 4; + static constexpr SkScalar kMinGammaInclusive = 0; + + uint32_t flags() const { return fFlags; } + SkPixelGeometry pixelGeometry() const { return fPixelGeometry; } + SkScalar textContrast() const { return fTextContrast; } + SkScalar textGamma() const { return fTextGamma; } + + bool isUseDeviceIndependentFonts() const { + return SkToBool(fFlags & kUseDeviceIndependentFonts_Flag); + } + + bool isAlwaysDither() const { + return SkToBool(fFlags & kAlwaysDither_Flag); + } + + bool operator==(const SkSurfaceProps& that) const { + return fFlags == that.fFlags && fPixelGeometry == that.fPixelGeometry && + fTextContrast == that.fTextContrast && fTextGamma == that.fTextGamma; + } + + bool operator!=(const SkSurfaceProps& that) const { + return !(*this == that); + } + +private: + uint32_t fFlags; + SkPixelGeometry fPixelGeometry; + + // This gamma value is specifically about blending of mask coverage. + // The surface also has a color space, but that applies to the colors. + SkScalar fTextContrast; + SkScalar fTextGamma; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkSwizzle.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkSwizzle.h new file mode 100644 index 0000000000..f7ef658892 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkSwizzle.h @@ -0,0 +1,21 @@ +/* + * 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 SkSwizzle_DEFINED +#define SkSwizzle_DEFINED + +#include "include/private/base/SkAPI.h" + +#include + +/** + Swizzles byte order of |count| 32-bit pixels, swapping R and B. + (RGBA <-> BGRA) +*/ +SK_API void SkSwapRB(uint32_t* dest, const uint32_t* src, int count); + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkTextBlob.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkTextBlob.h new file mode 100644 index 0000000000..23e2d9bf2a --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkTextBlob.h @@ -0,0 +1,519 @@ +/* + * 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 SkTextBlob_DEFINED +#define SkTextBlob_DEFINED + +#include "include/core/SkFont.h" +#include "include/core/SkFontTypes.h" +#include "include/core/SkRect.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkDebug.h" +#include "include/private/base/SkTemplates.h" + +#include +#include +#include + +class SkData; +class SkPaint; +class SkTypeface; +struct SkDeserialProcs; +struct SkPoint; +struct SkRSXform; +struct SkSerialProcs; + +namespace sktext { +class GlyphRunList; +} + +/** \class SkTextBlob + SkTextBlob combines multiple text runs into an immutable container. Each text + run consists of glyphs, SkPaint, and position. Only parts of SkPaint related to + fonts and text rendering are used by run. +*/ +class SK_API SkTextBlob final : public SkNVRefCnt { +private: + class RunRecord; + +public: + + /** Returns conservative bounding box. Uses SkPaint associated with each glyph to + determine glyph bounds, and unions all bounds. Returned bounds may be + larger than the bounds of all glyphs in runs. + + @return conservative bounding box + */ + const SkRect& bounds() const { return fBounds; } + + /** Returns a non-zero value unique among all text blobs. + + @return identifier for SkTextBlob + */ + uint32_t uniqueID() const { return fUniqueID; } + + /** Returns the number of intervals that intersect bounds. + bounds describes a pair of lines parallel to the text advance. + The return count is zero or a multiple of two, and is at most twice the number of glyphs in + the the blob. + + Pass nullptr for intervals to determine the size of the interval array. + + Runs within the blob that contain SkRSXform are ignored when computing intercepts. + + @param bounds lower and upper line parallel to the advance + @param intervals returned intersections; may be nullptr + @param paint specifies stroking, SkPathEffect that affects the result; may be nullptr + @return number of intersections; may be zero + */ + int getIntercepts(const SkScalar bounds[2], SkScalar intervals[], + const SkPaint* paint = nullptr) const; + + /** Creates SkTextBlob with a single run. + + font contains attributes used to define the run text. + + When encoding is SkTextEncoding::kUTF8, SkTextEncoding::kUTF16, or + SkTextEncoding::kUTF32, this function uses the default + character-to-glyph mapping from the SkTypeface in font. It does not + perform typeface fallback for characters not found in the SkTypeface. + It does not perform kerning or other complex shaping; glyphs are + positioned based on their default advances. + + @param text character code points or glyphs drawn + @param byteLength byte length of text array + @param font text size, typeface, text scale, and so on, used to draw + @param encoding text encoding used in the text array + @return SkTextBlob constructed from one run + */ + static sk_sp MakeFromText(const void* text, size_t byteLength, const SkFont& font, + SkTextEncoding encoding = SkTextEncoding::kUTF8); + + /** Creates SkTextBlob with a single run. string meaning depends on SkTextEncoding; + by default, string is encoded as UTF-8. + + font contains attributes used to define the run text. + + When encoding is SkTextEncoding::kUTF8, SkTextEncoding::kUTF16, or + SkTextEncoding::kUTF32, this function uses the default + character-to-glyph mapping from the SkTypeface in font. It does not + perform typeface fallback for characters not found in the SkTypeface. + It does not perform kerning or other complex shaping; glyphs are + positioned based on their default advances. + + @param string character code points or glyphs drawn + @param font text size, typeface, text scale, and so on, used to draw + @param encoding text encoding used in the text array + @return SkTextBlob constructed from one run + */ + static sk_sp MakeFromString(const char* string, const SkFont& font, + SkTextEncoding encoding = SkTextEncoding::kUTF8) { + if (!string) { + return nullptr; + } + return MakeFromText(string, strlen(string), font, encoding); + } + + /** Returns a textblob built from a single run of text with x-positions and a single y value. + This is equivalent to using SkTextBlobBuilder and calling allocRunPosH(). + Returns nullptr if byteLength is zero. + + @param text character code points or glyphs drawn (based on encoding) + @param byteLength byte length of text array + @param xpos array of x-positions, must contain values for all of the character points. + @param constY shared y-position for each character point, to be paired with each xpos. + @param font SkFont used for this run + @param encoding specifies the encoding of the text array. + @return new textblob or nullptr + */ + static sk_sp MakeFromPosTextH(const void* text, size_t byteLength, + const SkScalar xpos[], SkScalar constY, const SkFont& font, + SkTextEncoding encoding = SkTextEncoding::kUTF8); + + /** Returns a textblob built from a single run of text with positions. + This is equivalent to using SkTextBlobBuilder and calling allocRunPos(). + Returns nullptr if byteLength is zero. + + @param text character code points or glyphs drawn (based on encoding) + @param byteLength byte length of text array + @param pos array of positions, must contain values for all of the character points. + @param font SkFont used for this run + @param encoding specifies the encoding of the text array. + @return new textblob or nullptr + */ + static sk_sp MakeFromPosText(const void* text, size_t byteLength, + const SkPoint pos[], const SkFont& font, + SkTextEncoding encoding = SkTextEncoding::kUTF8); + + static sk_sp MakeFromRSXform(const void* text, size_t byteLength, + const SkRSXform xform[], const SkFont& font, + SkTextEncoding encoding = SkTextEncoding::kUTF8); + + /** Writes data to allow later reconstruction of SkTextBlob. memory points to storage + to receive the encoded data, and memory_size describes the size of storage. + Returns bytes used if provided storage is large enough to hold all data; + otherwise, returns zero. + + procs.fTypefaceProc permits supplying a custom function to encode SkTypeface. + If procs.fTypefaceProc is nullptr, default encoding is used. procs.fTypefaceCtx + may be used to provide user context to procs.fTypefaceProc; procs.fTypefaceProc + is called with a pointer to SkTypeface and user context. + + @param procs custom serial data encoders; may be nullptr + @param memory storage for data + @param memory_size size of storage + @return bytes written, or zero if required storage is larger than memory_size + + example: https://fiddle.skia.org/c/@TextBlob_serialize + */ + size_t serialize(const SkSerialProcs& procs, void* memory, size_t memory_size) const; + + /** Returns storage containing SkData describing SkTextBlob, using optional custom + encoders. + + procs.fTypefaceProc permits supplying a custom function to encode SkTypeface. + If procs.fTypefaceProc is nullptr, default encoding is used. procs.fTypefaceCtx + may be used to provide user context to procs.fTypefaceProc; procs.fTypefaceProc + is called with a pointer to SkTypeface and user context. + + @param procs custom serial data encoders; may be nullptr + @return storage containing serialized SkTextBlob + + example: https://fiddle.skia.org/c/@TextBlob_serialize_2 + */ + sk_sp serialize(const SkSerialProcs& procs) const; + + /** Recreates SkTextBlob that was serialized into data. Returns constructed SkTextBlob + if successful; otherwise, returns nullptr. Fails if size is smaller than + required data length, or if data does not permit constructing valid SkTextBlob. + + procs.fTypefaceProc permits supplying a custom function to decode SkTypeface. + If procs.fTypefaceProc is nullptr, default decoding is used. procs.fTypefaceCtx + may be used to provide user context to procs.fTypefaceProc; procs.fTypefaceProc + is called with a pointer to SkTypeface data, data byte length, and user context. + + @param data pointer for serial data + @param size size of data + @param procs custom serial data decoders; may be nullptr + @return SkTextBlob constructed from data in memory + */ + static sk_sp Deserialize(const void* data, size_t size, + const SkDeserialProcs& procs); + + class SK_API Iter { + public: + struct Run { + SkTypeface* fTypeface; + int fGlyphCount; + const uint16_t* fGlyphIndices; +#ifdef SK_UNTIL_CRBUG_1187654_IS_FIXED + const uint32_t* fClusterIndex_forTest; + int fUtf8Size_forTest; + const char* fUtf8_forTest; +#endif + }; + + Iter(const SkTextBlob&); + + /** + * Returns true for each "run" inside the textblob, setting the Run fields (if not null). + * If this returns false, there are no more runs, and the Run parameter will be ignored. + */ + bool next(Run*); + + // Experimental, DO NO USE, will change/go-away + struct ExperimentalRun { + SkFont font; + int count; + const uint16_t* glyphs; + const SkPoint* positions; + }; + bool experimentalNext(ExperimentalRun*); + + private: + const RunRecord* fRunRecord; + }; + +private: + friend class SkNVRefCnt; + + enum GlyphPositioning : uint8_t; + + explicit SkTextBlob(const SkRect& bounds); + + ~SkTextBlob(); + + // Memory for objects of this class is created with sk_malloc rather than operator new and must + // be freed with sk_free. + void operator delete(void* p); + void* operator new(size_t); + void* operator new(size_t, void* p); + + static unsigned ScalarsPerGlyph(GlyphPositioning pos); + + using PurgeDelegate = void (*)(uint32_t blobID, uint32_t cacheID); + + // Call when this blob is part of the key to a cache entry. This allows the cache + // to know automatically those entries can be purged when this SkTextBlob is deleted. + void notifyAddedToCache(uint32_t cacheID, PurgeDelegate purgeDelegate) const { + fCacheID.store(cacheID); + fPurgeDelegate.store(purgeDelegate); + } + + friend class sktext::GlyphRunList; + friend class SkTextBlobBuilder; + friend class SkTextBlobPriv; + friend class SkTextBlobRunIterator; + + const SkRect fBounds; + const uint32_t fUniqueID; + mutable std::atomic fCacheID; + mutable std::atomic fPurgeDelegate; + + SkDEBUGCODE(size_t fStorageSize;) + + // The actual payload resides in externally-managed storage, following the object. + // (see the .cpp for more details) + + using INHERITED = SkRefCnt; +}; + +/** \class SkTextBlobBuilder + Helper class for constructing SkTextBlob. +*/ +class SK_API SkTextBlobBuilder { +public: + + /** Constructs empty SkTextBlobBuilder. By default, SkTextBlobBuilder has no runs. + + @return empty SkTextBlobBuilder + + example: https://fiddle.skia.org/c/@TextBlobBuilder_empty_constructor + */ + SkTextBlobBuilder(); + + /** Deletes data allocated internally by SkTextBlobBuilder. + */ + ~SkTextBlobBuilder(); + + /** Returns SkTextBlob built from runs of glyphs added by builder. Returned + SkTextBlob is immutable; it may be copied, but its contents may not be altered. + Returns nullptr if no runs of glyphs were added by builder. + + Resets SkTextBlobBuilder to its initial empty state, allowing it to be + reused to build a new set of runs. + + @return SkTextBlob or nullptr + + example: https://fiddle.skia.org/c/@TextBlobBuilder_make + */ + sk_sp make(); + + /** \struct SkTextBlobBuilder::RunBuffer + RunBuffer supplies storage for glyphs and positions within a run. + + A run is a sequence of glyphs sharing font metrics and positioning. + Each run may position its glyphs in one of three ways: + by specifying where the first glyph is drawn, and allowing font metrics to + determine the advance to subsequent glyphs; by specifying a baseline, and + the position on that baseline for each glyph in run; or by providing SkPoint + array, one per glyph. + */ + struct RunBuffer { + SkGlyphID* glyphs; //!< storage for glyph indexes in run + SkScalar* pos; //!< storage for glyph positions in run + char* utf8text; //!< storage for text UTF-8 code units in run + uint32_t* clusters; //!< storage for glyph clusters (index of UTF-8 code unit) + + // Helpers, since the "pos" field can be different types (always some number of floats). + SkPoint* points() const { return reinterpret_cast(pos); } + SkRSXform* xforms() const { return reinterpret_cast(pos); } + }; + + /** Returns run with storage for glyphs. Caller must write count glyphs to + RunBuffer::glyphs before next call to SkTextBlobBuilder. + + RunBuffer::pos, RunBuffer::utf8text, and RunBuffer::clusters should be ignored. + + Glyphs share metrics in font. + + Glyphs are positioned on a baseline at (x, y), using font metrics to + determine their relative placement. + + bounds defines an optional bounding box, used to suppress drawing when SkTextBlob + bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds + is computed from (x, y) and RunBuffer::glyphs metrics. + + @param font SkFont used for this run + @param count number of glyphs + @param x horizontal offset within the blob + @param y vertical offset within the blob + @param bounds optional run bounding box + @return writable glyph buffer + */ + const RunBuffer& allocRun(const SkFont& font, int count, SkScalar x, SkScalar y, + const SkRect* bounds = nullptr); + + /** Returns run with storage for glyphs and positions along baseline. Caller must + write count glyphs to RunBuffer::glyphs and count scalars to RunBuffer::pos + before next call to SkTextBlobBuilder. + + RunBuffer::utf8text and RunBuffer::clusters should be ignored. + + Glyphs share metrics in font. + + Glyphs are positioned on a baseline at y, using x-axis positions written by + caller to RunBuffer::pos. + + bounds defines an optional bounding box, used to suppress drawing when SkTextBlob + bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds + is computed from y, RunBuffer::pos, and RunBuffer::glyphs metrics. + + @param font SkFont used for this run + @param count number of glyphs + @param y vertical offset within the blob + @param bounds optional run bounding box + @return writable glyph buffer and x-axis position buffer + */ + const RunBuffer& allocRunPosH(const SkFont& font, int count, SkScalar y, + const SkRect* bounds = nullptr); + + /** Returns run with storage for glyphs and SkPoint positions. Caller must + write count glyphs to RunBuffer::glyphs and count SkPoint to RunBuffer::pos + before next call to SkTextBlobBuilder. + + RunBuffer::utf8text and RunBuffer::clusters should be ignored. + + Glyphs share metrics in font. + + Glyphs are positioned using SkPoint written by caller to RunBuffer::pos, using + two scalar values for each SkPoint. + + bounds defines an optional bounding box, used to suppress drawing when SkTextBlob + bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds + is computed from RunBuffer::pos, and RunBuffer::glyphs metrics. + + @param font SkFont used for this run + @param count number of glyphs + @param bounds optional run bounding box + @return writable glyph buffer and SkPoint buffer + */ + const RunBuffer& allocRunPos(const SkFont& font, int count, + const SkRect* bounds = nullptr); + + // RunBuffer.pos points to SkRSXform array + const RunBuffer& allocRunRSXform(const SkFont& font, int count); + + /** Returns run with storage for glyphs, text, and clusters. Caller must + write count glyphs to RunBuffer::glyphs, textByteCount UTF-8 code units + into RunBuffer::utf8text, and count monotonic indexes into utf8text + into RunBuffer::clusters before next call to SkTextBlobBuilder. + + RunBuffer::pos should be ignored. + + Glyphs share metrics in font. + + Glyphs are positioned on a baseline at (x, y), using font metrics to + determine their relative placement. + + bounds defines an optional bounding box, used to suppress drawing when SkTextBlob + bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds + is computed from (x, y) and RunBuffer::glyphs metrics. + + @param font SkFont used for this run + @param count number of glyphs + @param x horizontal offset within the blob + @param y vertical offset within the blob + @param textByteCount number of UTF-8 code units + @param bounds optional run bounding box + @return writable glyph buffer, text buffer, and cluster buffer + */ + const RunBuffer& allocRunText(const SkFont& font, int count, SkScalar x, SkScalar y, + int textByteCount, const SkRect* bounds = nullptr); + + /** Returns run with storage for glyphs, positions along baseline, text, + and clusters. Caller must write count glyphs to RunBuffer::glyphs, + count scalars to RunBuffer::pos, textByteCount UTF-8 code units into + RunBuffer::utf8text, and count monotonic indexes into utf8text into + RunBuffer::clusters before next call to SkTextBlobBuilder. + + Glyphs share metrics in font. + + Glyphs are positioned on a baseline at y, using x-axis positions written by + caller to RunBuffer::pos. + + bounds defines an optional bounding box, used to suppress drawing when SkTextBlob + bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds + is computed from y, RunBuffer::pos, and RunBuffer::glyphs metrics. + + @param font SkFont used for this run + @param count number of glyphs + @param y vertical offset within the blob + @param textByteCount number of UTF-8 code units + @param bounds optional run bounding box + @return writable glyph buffer, x-axis position buffer, text buffer, and cluster buffer + */ + const RunBuffer& allocRunTextPosH(const SkFont& font, int count, SkScalar y, int textByteCount, + const SkRect* bounds = nullptr); + + /** Returns run with storage for glyphs, SkPoint positions, text, and + clusters. Caller must write count glyphs to RunBuffer::glyphs, count + SkPoint to RunBuffer::pos, textByteCount UTF-8 code units into + RunBuffer::utf8text, and count monotonic indexes into utf8text into + RunBuffer::clusters before next call to SkTextBlobBuilder. + + Glyphs share metrics in font. + + Glyphs are positioned using SkPoint written by caller to RunBuffer::pos, using + two scalar values for each SkPoint. + + bounds defines an optional bounding box, used to suppress drawing when SkTextBlob + bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds + is computed from RunBuffer::pos, and RunBuffer::glyphs metrics. + + @param font SkFont used for this run + @param count number of glyphs + @param textByteCount number of UTF-8 code units + @param bounds optional run bounding box + @return writable glyph buffer, SkPoint buffer, text buffer, and cluster buffer + */ + const RunBuffer& allocRunTextPos(const SkFont& font, int count, int textByteCount, + const SkRect* bounds = nullptr); + + // RunBuffer.pos points to SkRSXform array + const RunBuffer& allocRunTextRSXform(const SkFont& font, int count, int textByteCount, + const SkRect* bounds = nullptr); + +private: + void reserve(size_t size); + void allocInternal(const SkFont& font, SkTextBlob::GlyphPositioning positioning, + int count, int textBytes, SkPoint offset, const SkRect* bounds); + bool mergeRun(const SkFont& font, SkTextBlob::GlyphPositioning positioning, + uint32_t count, SkPoint offset); + void updateDeferredBounds(); + + static SkRect ConservativeRunBounds(const SkTextBlob::RunRecord&); + static SkRect TightRunBounds(const SkTextBlob::RunRecord&); + + friend class SkTextBlobPriv; + friend class SkTextBlobBuilderPriv; + + skia_private::AutoTMalloc fStorage; + size_t fStorageSize; + size_t fStorageUsed; + + SkRect fBounds; + int fRunCount; + bool fDeferredBounds; + size_t fLastRun; // index into fStorage + + RunBuffer fCurrentRunBuffer; +}; + +#endif // SkTextBlob_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkTextureCompressionType.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkTextureCompressionType.h new file mode 100644 index 0000000000..e9b441378d --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkTextureCompressionType.h @@ -0,0 +1,30 @@ +/* + * 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 SkTextureCompressionType_DEFINED +#define SkTextureCompressionType_DEFINED +/* + * Skia | GL_COMPRESSED_* | MTLPixelFormat* | VK_FORMAT_*_BLOCK + * -------------------------------------------------------------------------------------- + * kETC2_RGB8_UNORM | ETC1_RGB8 | ETC2_RGB8 (iOS-only) | ETC2_R8G8B8_UNORM + * | RGB8_ETC2 | | + * -------------------------------------------------------------------------------------- + * kBC1_RGB8_UNORM | RGB_S3TC_DXT1_EXT | N/A | BC1_RGB_UNORM + * -------------------------------------------------------------------------------------- + * kBC1_RGBA8_UNORM | RGBA_S3TC_DXT1_EXT | BC1_RGBA (macOS-only)| BC1_RGBA_UNORM + */ +enum class SkTextureCompressionType { + kNone, + kETC2_RGB8_UNORM, + + kBC1_RGB8_UNORM, + kBC1_RGBA8_UNORM, + kLast = kBC1_RGBA8_UNORM, + kETC1_RGB8 = kETC2_RGB8_UNORM, +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkTileMode.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkTileMode.h new file mode 100644 index 0000000000..8a9d020958 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkTileMode.h @@ -0,0 +1,41 @@ +/* + * Copyright 2019 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkTileModes_DEFINED +#define SkTileModes_DEFINED + +#include "include/core/SkTypes.h" + +enum class SkTileMode { + /** + * Replicate the edge color if the shader draws outside of its + * original bounds. + */ + kClamp, + + /** + * Repeat the shader's image horizontally and vertically. + */ + kRepeat, + + /** + * Repeat the shader's image horizontally and vertically, alternating + * mirror images so that adjacent images always seam. + */ + kMirror, + + /** + * Only draw within the original domain, return transparent-black everywhere else. + */ + kDecal, + + kLastTileMode = kDecal, +}; + +static constexpr int kSkTileModeCount = static_cast(SkTileMode::kLastTileMode) + 1; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkTiledImageUtils.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkTiledImageUtils.h new file mode 100644 index 0000000000..fc5a4f25c5 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkTiledImageUtils.h @@ -0,0 +1,125 @@ +/* + * 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 SkTiledImageUtils_DEFINED +#define SkTiledImageUtils_DEFINED + +#include "include/core/SkCanvas.h" +#include "include/core/SkImage.h" +#include "include/core/SkRect.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkSamplingOptions.h" +#include "include/core/SkScalar.h" +#include "include/private/base/SkAPI.h" + +#include + +class SkPaint; + +/** \namespace SkTiledImageUtils + SkTiledImageUtils' DrawImage/DrawImageRect methods are intended to be direct replacements + for their SkCanvas equivalents. The SkTiledImageUtils calls will break SkBitmap-backed + SkImages into smaller tiles and draw them if the original image is too large to be + uploaded to the GPU. If the original image doesn't need tiling or is already gpu-backed + the DrawImage/DrawImageRect calls will fall through to the matching SkCanvas call. +*/ +namespace SkTiledImageUtils { + +SK_API void DrawImageRect(SkCanvas* canvas, + const SkImage* image, + const SkRect& src, + const SkRect& dst, + const SkSamplingOptions& sampling = {}, + const SkPaint* paint = nullptr, + SkCanvas::SrcRectConstraint constraint = + SkCanvas::kFast_SrcRectConstraint); + +inline void DrawImageRect(SkCanvas* canvas, + const sk_sp& image, + const SkRect& src, + const SkRect& dst, + const SkSamplingOptions& sampling = {}, + const SkPaint* paint = nullptr, + SkCanvas::SrcRectConstraint constraint = + SkCanvas::kFast_SrcRectConstraint) { + DrawImageRect(canvas, image.get(), src, dst, sampling, paint, constraint); +} + +inline void DrawImageRect(SkCanvas* canvas, + const SkImage* image, + const SkRect& dst, + const SkSamplingOptions& sampling = {}, + const SkPaint* paint = nullptr, + SkCanvas::SrcRectConstraint constraint = + SkCanvas::kFast_SrcRectConstraint) { + if (!image) { + return; + } + + SkRect src = SkRect::MakeIWH(image->width(), image->height()); + + DrawImageRect(canvas, image, src, dst, sampling, paint, constraint); +} + +inline void DrawImageRect(SkCanvas* canvas, + const sk_sp& image, + const SkRect& dst, + const SkSamplingOptions& sampling = {}, + const SkPaint* paint = nullptr, + SkCanvas::SrcRectConstraint constraint = + SkCanvas::kFast_SrcRectConstraint) { + DrawImageRect(canvas, image.get(), dst, sampling, paint, constraint); +} + +inline void DrawImage(SkCanvas* canvas, + const SkImage* image, + SkScalar x, SkScalar y, + const SkSamplingOptions& sampling = {}, + const SkPaint* paint = nullptr, + SkCanvas::SrcRectConstraint constraint = + SkCanvas::kFast_SrcRectConstraint) { + if (!image) { + return; + } + + SkRect src = SkRect::MakeIWH(image->width(), image->height()); + SkRect dst = SkRect::MakeXYWH(x, y, image->width(), image->height()); + + DrawImageRect(canvas, image, src, dst, sampling, paint, constraint); +} + +inline void DrawImage(SkCanvas* canvas, + const sk_sp& image, + SkScalar x, SkScalar y, + const SkSamplingOptions& sampling = {}, + const SkPaint* paint = nullptr, + SkCanvas::SrcRectConstraint constraint = + SkCanvas::kFast_SrcRectConstraint) { + DrawImage(canvas, image.get(), x, y, sampling, paint, constraint); +} + +static constexpr int kNumImageKeyValues = 6; + +/** Retrieves a set of values that can be used as part of a cache key for the provided image. + + Unfortunately, SkImage::uniqueID isn't sufficient as an SkImage cache key. In particular, + SkBitmap-backed SkImages can share a single SkBitmap and refer to different subsets of it. + In this situation the optimal key is based on the SkBitmap's generation ID and the subset + rectangle. + For Picture-backed images this method will attempt to generate a concise internally-based + key (i.e., containing picture ID, matrix translation, width and height, etc.). For complicated + Picture-backed images (i.e., those w/ a paint or a full matrix) it will fall back to + using 'image's unique key. + + @param image The image for which key values are desired + @param keyValues The resulting key values +*/ +SK_API void GetImageKeyValues(const SkImage* image, uint32_t keyValues[kNumImageKeyValues]); + +} // namespace SkTiledImageUtils + +#endif // SkTiledImageUtils_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkTraceMemoryDump.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkTraceMemoryDump.h new file mode 100644 index 0000000000..d01b01bd68 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkTraceMemoryDump.h @@ -0,0 +1,114 @@ +/* + * 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 SkTraceMemoryDump_DEFINED +#define SkTraceMemoryDump_DEFINED + +#include "include/core/SkTypes.h" + +class SkDiscardableMemory; + +/** + * Interface for memory tracing. + * This interface is meant to be passed as argument to the memory dump methods of Skia objects. + * The implementation of this interface is provided by the embedder. + */ +class SK_API SkTraceMemoryDump { +public: + /** + * Enum to specify the level of the requested details for the dump from the Skia objects. + */ + enum LevelOfDetail { + // Dump only the minimal details to get the total memory usage (Usually just the totals). + kLight_LevelOfDetail, + + // Dump the detailed breakdown of the objects in the caches. + kObjectsBreakdowns_LevelOfDetail + }; + + /** + * Appends a new memory dump (i.e. a row) to the trace memory infrastructure. + * If dumpName does not exist yet, a new one is created. Otherwise, a new column is appended to + * the previously created dump. + * Arguments: + * dumpName: an absolute, slash-separated, name for the item being dumped + * e.g., "skia/CacheX/EntryY". + * valueName: a string indicating the name of the column. + * e.g., "size", "active_size", "number_of_objects". + * This string is supposed to be long lived and is NOT copied. + * units: a string indicating the units for the value. + * e.g., "bytes", "objects". + * This string is supposed to be long lived and is NOT copied. + * value: the actual value being dumped. + */ + virtual void dumpNumericValue(const char* dumpName, + const char* valueName, + const char* units, + uint64_t value) = 0; + + virtual void dumpStringValue(const char* /*dumpName*/, + const char* /*valueName*/, + const char* /*value*/) { } + + /** + * Sets the memory backing for an existing dump. + * backingType and backingObjectId are used by the embedder to associate the memory dumped via + * dumpNumericValue with the corresponding dump that backs the memory. + */ + virtual void setMemoryBacking(const char* dumpName, + const char* backingType, + const char* backingObjectId) = 0; + + /** + * Specialization for memory backed by discardable memory. + */ + virtual void setDiscardableMemoryBacking( + const char* dumpName, + const SkDiscardableMemory& discardableMemoryObject) = 0; + + /** + * Returns the type of details requested in the dump. The granularity of the dump is supposed to + * match the LevelOfDetail argument. The level of detail must not affect the total size + * reported, but only granularity of the child entries. + */ + virtual LevelOfDetail getRequestedDetails() const = 0; + + /** + * Returns true if we should dump wrapped objects. Wrapped objects come from outside Skia, and + * may be independently tracked there. + */ + virtual bool shouldDumpWrappedObjects() const { return true; } + + /** + * If shouldDumpWrappedObjects() returns true then this function will be called to populate + * the output with information on whether the item being dumped is a wrapped object. + */ + virtual void dumpWrappedState(const char* /*dumpName*/, bool /*isWrappedObject*/) {} + + /** + * Returns true if we should dump unbudgeted objects. Unbudgeted objects can either come from + * wrapped objects passed into Skia from the client or from Skia created objects currently held + * by the client in a public Skia object (e.g. SkSurface or SkImage). This call is only used + * when dumping Graphite memory statistics. + */ + virtual bool shouldDumpUnbudgetedObjects() const { return true; } + + /** + * If shouldDumpUnbudgetedObjects() returns true then this function will be called to populate + * the output with information on whether the item being dumped is budgeted. This call is only + * used when dumping Graphite memory statistics. + */ + virtual void dumpBudgetedState(const char* /*dumpName*/, bool /*isBudgeted*/) {} + +protected: + virtual ~SkTraceMemoryDump() = default; + SkTraceMemoryDump() = default; + SkTraceMemoryDump(const SkTraceMemoryDump&) = delete; + SkTraceMemoryDump& operator=(const SkTraceMemoryDump&) = delete; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkTypeface.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkTypeface.h new file mode 100644 index 0000000000..d35396a9f2 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkTypeface.h @@ -0,0 +1,434 @@ +/* + * 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 SkTypeface_DEFINED +#define SkTypeface_DEFINED + +#include "include/core/SkFontArguments.h" +#include "include/core/SkFontParameters.h" +#include "include/core/SkFontStyle.h" +#include "include/core/SkRect.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkString.h" +#include "include/core/SkTypes.h" +#include "include/private/SkWeakRefCnt.h" +#include "include/private/base/SkOnce.h" + +#include +#include +#include + +class SkData; +class SkDescriptor; +class SkFontMgr; +class SkFontDescriptor; +class SkScalerContext; +class SkStream; +class SkStreamAsset; +class SkWStream; +enum class SkTextEncoding; +struct SkAdvancedTypefaceMetrics; +struct SkScalerContextEffects; +struct SkScalerContextRec; + +using SkTypefaceID = uint32_t; + +/** Machine endian. */ +typedef uint32_t SkFontTableTag; + +/** \class SkTypeface + + The SkTypeface class specifies the typeface and intrinsic style of a font. + This is used in the paint, along with optionally algorithmic settings like + textSize, textSkewX, textScaleX, kFakeBoldText_Mask, to specify + how text appears when drawn (and measured). + + Typeface objects are immutable, and so they can be shared between threads. +*/ +class SK_API SkTypeface : public SkWeakRefCnt { +public: + /** Returns the typeface's intrinsic style attributes. */ + SkFontStyle fontStyle() const { + return fStyle; + } + + /** Returns true if style() has the kBold bit set. */ + bool isBold() const { return fStyle.weight() >= SkFontStyle::kSemiBold_Weight; } + + /** Returns true if style() has the kItalic bit set. */ + bool isItalic() const { return fStyle.slant() != SkFontStyle::kUpright_Slant; } + + /** Returns true if the typeface claims to be fixed-pitch. + * This is a style bit, advance widths may vary even if this returns true. + */ + bool isFixedPitch() const { return fIsFixedPitch; } + + /** Copy into 'coordinates' (allocated by the caller) the design variation coordinates. + * + * @param coordinates the buffer into which to write the design variation coordinates. + * @param coordinateCount the number of entries available through 'coordinates'. + * + * @return The number of axes, or -1 if there is an error. + * If 'coordinates != nullptr' and 'coordinateCount >= numAxes' then 'coordinates' will be + * filled with the variation coordinates describing the position of this typeface in design + * variation space. It is possible the number of axes can be retrieved but actual position + * cannot. + */ + int getVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[], + int coordinateCount) const; + + /** Copy into 'parameters' (allocated by the caller) the design variation parameters. + * + * @param parameters the buffer into which to write the design variation parameters. + * @param coordinateCount the number of entries available through 'parameters'. + * + * @return The number of axes, or -1 if there is an error. + * If 'parameters != nullptr' and 'parameterCount >= numAxes' then 'parameters' will be + * filled with the variation parameters describing the position of this typeface in design + * variation space. It is possible the number of axes can be retrieved but actual parameters + * cannot. + */ + int getVariationDesignParameters(SkFontParameters::Variation::Axis parameters[], + int parameterCount) const; + + /** Return a 32bit value for this typeface, unique for the underlying font + data. Will never return 0. + */ + SkTypefaceID uniqueID() const { return fUniqueID; } + + /** Returns true if the two typefaces reference the same underlying font, + handling either being null (treating null as not equal to any font). + */ + static bool Equal(const SkTypeface* facea, const SkTypeface* faceb); + + /** Returns a non-null typeface which contains no glyphs. */ + static sk_sp MakeEmpty(); + + /** Return a new typeface based on this typeface but parameterized as specified in the + SkFontArguments. If the SkFontArguments does not supply an argument for a parameter + in the font then the value from this typeface will be used as the value for that + argument. If the cloned typeface would be exaclty the same as this typeface then + this typeface may be ref'ed and returned. May return nullptr on failure. + */ + sk_sp makeClone(const SkFontArguments&) const; + + /** + * A typeface can serialize just a descriptor (names, etc.), or it can also include the + * actual font data (which can be large). This enum controls how serialize() decides what + * to serialize. + */ + enum class SerializeBehavior { + kDoIncludeData, + kDontIncludeData, + kIncludeDataIfLocal, + }; + + /** Write a unique signature to a stream, sufficient to reconstruct a + typeface referencing the same font when Deserialize is called. + */ + void serialize(SkWStream*, SerializeBehavior = SerializeBehavior::kIncludeDataIfLocal) const; + + /** + * Same as serialize(SkWStream*, ...) but returns the serialized data in SkData, instead of + * writing it to a stream. + */ + sk_sp serialize(SerializeBehavior = SerializeBehavior::kIncludeDataIfLocal) const; + + /** Given the data previously written by serialize(), return a new instance + of a typeface referring to the same font. If that font is not available, + return nullptr. + Goes through all registered typeface factories and lastResortMgr (if non-null). + Does not affect ownership of SkStream. + */ + + static sk_sp MakeDeserialize(SkStream*, sk_sp lastResortMgr); + + /** + * Given an array of UTF32 character codes, return their corresponding glyph IDs. + * + * @param chars pointer to the array of UTF32 chars + * @param number of chars and glyphs + * @param glyphs returns the corresponding glyph IDs for each character. + */ + void unicharsToGlyphs(const SkUnichar uni[], int count, SkGlyphID glyphs[]) const; + + int textToGlyphs(const void* text, size_t byteLength, SkTextEncoding encoding, + SkGlyphID glyphs[], int maxGlyphCount) const; + + /** + * Return the glyphID that corresponds to the specified unicode code-point + * (in UTF32 encoding). If the unichar is not supported, returns 0. + * + * This is a short-cut for calling unicharsToGlyphs(). + */ + SkGlyphID unicharToGlyph(SkUnichar unichar) const; + + /** + * Return the number of glyphs in the typeface. + */ + int countGlyphs() const; + + // Table getters -- may fail if the underlying font format is not organized + // as 4-byte tables. + + /** Return the number of tables in the font. */ + int countTables() const; + + /** Copy into tags[] (allocated by the caller) the list of table tags in + * the font, and return the number. This will be the same as CountTables() + * or 0 if an error occured. If tags == NULL, this only returns the count + * (the same as calling countTables()). + */ + int getTableTags(SkFontTableTag tags[]) const; + + /** Given a table tag, return the size of its contents, or 0 if not present + */ + size_t getTableSize(SkFontTableTag) const; + + /** Copy the contents of a table into data (allocated by the caller). Note + * that the contents of the table will be in their native endian order + * (which for most truetype tables is big endian). If the table tag is + * not found, or there is an error copying the data, then 0 is returned. + * If this happens, it is possible that some or all of the memory pointed + * to by data may have been written to, even though an error has occured. + * + * @param tag The table tag whose contents are to be copied + * @param offset The offset in bytes into the table's contents where the + * copy should start from. + * @param length The number of bytes, starting at offset, of table data + * to copy. + * @param data storage address where the table contents are copied to + * @return the number of bytes actually copied into data. If offset+length + * exceeds the table's size, then only the bytes up to the table's + * size are actually copied, and this is the value returned. If + * offset > the table's size, or tag is not a valid table, + * then 0 is returned. + */ + size_t getTableData(SkFontTableTag tag, size_t offset, size_t length, + void* data) const; + + /** + * Return an immutable copy of the requested font table, or nullptr if that table was + * not found. This can sometimes be faster than calling getTableData() twice: once to find + * the length, and then again to copy the data. + * + * @param tag The table tag whose contents are to be copied + * @return an immutable copy of the table's data, or nullptr. + */ + sk_sp copyTableData(SkFontTableTag tag) const; + + /** + * Return the units-per-em value for this typeface, or zero if there is an + * error. + */ + int getUnitsPerEm() const; + + /** + * Given a run of glyphs, return the associated horizontal adjustments. + * Adjustments are in "design units", which are integers relative to the + * typeface's units per em (see getUnitsPerEm). + * + * Some typefaces are known to never support kerning. Calling this method + * with all zeros (e.g. getKerningPairAdustments(NULL, 0, NULL)) returns + * a boolean indicating if the typeface might support kerning. If it + * returns false, then it will always return false (no kerning) for all + * possible glyph runs. If it returns true, then it *may* return true for + * somne glyph runs. + * + * If count is non-zero, then the glyphs parameter must point to at least + * [count] valid glyph IDs, and the adjustments parameter must be + * sized to at least [count - 1] entries. If the method returns true, then + * [count-1] entries in the adjustments array will be set. If the method + * returns false, then no kerning should be applied, and the adjustments + * array will be in an undefined state (possibly some values may have been + * written, but none of them should be interpreted as valid values). + */ + bool getKerningPairAdjustments(const SkGlyphID glyphs[], int count, + int32_t adjustments[]) const; + + struct LocalizedString { + SkString fString; + SkString fLanguage; + }; + class LocalizedStrings { + public: + LocalizedStrings() = default; + virtual ~LocalizedStrings() { } + virtual bool next(LocalizedString* localizedString) = 0; + void unref() { delete this; } + + private: + LocalizedStrings(const LocalizedStrings&) = delete; + LocalizedStrings& operator=(const LocalizedStrings&) = delete; + }; + /** + * Returns an iterator which will attempt to enumerate all of the + * family names specified by the font. + * It is the caller's responsibility to unref() the returned pointer. + */ + LocalizedStrings* createFamilyNameIterator() const; + + /** + * Return the family name for this typeface. It will always be returned + * encoded as UTF8, but the language of the name is whatever the host + * platform chooses. + */ + void getFamilyName(SkString* name) const; + + /** + * Return the PostScript name for this typeface. + * Value may change based on variation parameters. + * Returns false if no PostScript name is available. + */ + bool getPostScriptName(SkString* name) const; + + /** + * Return a stream for the contents of the font data, or NULL on failure. + * If ttcIndex is not null, it is set to the TrueTypeCollection index + * of this typeface within the stream, or 0 if the stream is not a + * collection. + * The caller is responsible for deleting the stream. + */ + std::unique_ptr openStream(int* ttcIndex) const; + + /** + * Return a stream for the contents of the font data. + * Returns nullptr on failure or if the font data isn't already available in stream form. + * Use when the stream can be used opportunistically but the calling code would prefer + * to fall back to table access if creating the stream would be expensive. + * Otherwise acts the same as openStream. + */ + std::unique_ptr openExistingStream(int* ttcIndex) const; + + /** + * Return a scalercontext for the given descriptor. It may return a + * stub scalercontext that will not crash, but will draw nothing. + */ + std::unique_ptr createScalerContext(const SkScalerContextEffects&, + const SkDescriptor*) const; + + /** + * Return a rectangle (scaled to 1-pt) that represents the union of the bounds of all + * of the glyphs, but each one positioned at (0,). This may be conservatively large, and + * will not take into account any hinting or other size-specific adjustments. + */ + SkRect getBounds() const; + + // PRIVATE / EXPERIMENTAL -- do not call + void filterRec(SkScalerContextRec* rec) const { + this->onFilterRec(rec); + } + // PRIVATE / EXPERIMENTAL -- do not call + void getFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const { + this->onGetFontDescriptor(desc, isLocal); + } + // PRIVATE / EXPERIMENTAL -- do not call + void* internal_private_getCTFontRef() const { + return this->onGetCTFontRef(); + } + + /* Skia reserves all tags that begin with a lower case letter and 0 */ + using FactoryId = SkFourByteTag; + static void Register( + FactoryId id, + sk_sp (*make)(std::unique_ptr, const SkFontArguments&)); + +protected: + explicit SkTypeface(const SkFontStyle& style, bool isFixedPitch = false); + ~SkTypeface() override; + + virtual sk_sp onMakeClone(const SkFontArguments&) const = 0; + + /** Sets the fixedPitch bit. If used, must be called in the constructor. */ + void setIsFixedPitch(bool isFixedPitch) { fIsFixedPitch = isFixedPitch; } + /** Sets the font style. If used, must be called in the constructor. */ + void setFontStyle(SkFontStyle style) { fStyle = style; } + + // Must return a valid scaler context. It can not return nullptr. + virtual std::unique_ptr onCreateScalerContext(const SkScalerContextEffects&, + const SkDescriptor*) const = 0; + virtual void onFilterRec(SkScalerContextRec*) const = 0; + friend class SkScalerContext; // onFilterRec + + // Subclasses *must* override this method to work with the PDF backend. + virtual std::unique_ptr onGetAdvancedMetrics() const = 0; + // For type1 postscript fonts only, set the glyph names for each glyph. + // destination array is non-null, and points to an array of size this->countGlyphs(). + // Backends that do not suport type1 fonts should not override. + virtual void getPostScriptGlyphNames(SkString*) const = 0; + + // The mapping from glyph to Unicode; array indices are glyph ids. + // For each glyph, give the default Unicode value, if it exists. + // dstArray is non-null, and points to an array of size this->countGlyphs(). + virtual void getGlyphToUnicodeMap(SkUnichar* dstArray) const = 0; + + virtual std::unique_ptr onOpenStream(int* ttcIndex) const = 0; + + virtual std::unique_ptr onOpenExistingStream(int* ttcIndex) const; + + virtual bool onGlyphMaskNeedsCurrentColor() const = 0; + + virtual int onGetVariationDesignPosition( + SkFontArguments::VariationPosition::Coordinate coordinates[], + int coordinateCount) const = 0; + + virtual int onGetVariationDesignParameters( + SkFontParameters::Variation::Axis parameters[], int parameterCount) const = 0; + + virtual void onGetFontDescriptor(SkFontDescriptor*, bool* isLocal) const = 0; + + virtual void onCharsToGlyphs(const SkUnichar* chars, int count, SkGlyphID glyphs[]) const = 0; + virtual int onCountGlyphs() const = 0; + + virtual int onGetUPEM() const = 0; + virtual bool onGetKerningPairAdjustments(const SkGlyphID glyphs[], int count, + int32_t adjustments[]) const; + + /** Returns the family name of the typeface as known by its font manager. + * This name may or may not be produced by the family name iterator. + */ + virtual void onGetFamilyName(SkString* familyName) const = 0; + virtual bool onGetPostScriptName(SkString*) const = 0; + + /** Returns an iterator over the family names in the font. */ + virtual LocalizedStrings* onCreateFamilyNameIterator() const = 0; + + virtual int onGetTableTags(SkFontTableTag tags[]) const = 0; + virtual size_t onGetTableData(SkFontTableTag, size_t offset, + size_t length, void* data) const = 0; + virtual sk_sp onCopyTableData(SkFontTableTag) const; + + virtual bool onComputeBounds(SkRect*) const; + + virtual void* onGetCTFontRef() const { return nullptr; } + +private: + /** Returns true if the typeface's glyph masks may refer to the foreground + * paint foreground color. This is needed to determine caching requirements. Usually true for + * typefaces that contain a COLR table. + */ + bool glyphMaskNeedsCurrentColor() const; + friend class SkStrikeServerImpl; // glyphMaskNeedsCurrentColor + friend class SkTypefaceProxyPrototype; // glyphMaskNeedsCurrentColor + + /** Retrieve detailed typeface metrics. Used by the PDF backend. */ + std::unique_ptr getAdvancedMetrics() const; + friend class SkRandomTypeface; // getAdvancedMetrics + friend class SkPDFFont; // getAdvancedMetrics + + friend class SkFontPriv; // getGlyphToUnicodeMap + +private: + SkTypefaceID fUniqueID; + SkFontStyle fStyle; + mutable SkRect fBounds; + mutable SkOnce fBoundsOnce; + bool fIsFixedPitch; + + using INHERITED = SkWeakRefCnt; +}; +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkTypes.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkTypes.h new file mode 100644 index 0000000000..722e7354ff --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkTypes.h @@ -0,0 +1,199 @@ +/* + * 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 SkTypes_DEFINED +#define SkTypes_DEFINED + +// All of these files should be independent of things users can set via the user config file. +// They should also be able to be included in any order. +// IWYU pragma: begin_exports +#include "include/private/base/SkFeatures.h" + +// Load and verify defines from the user config file. +#include "include/private/base/SkLoadUserConfig.h" + +// Any includes or defines below can be configured by the user config file. +#include "include/private/base/SkAPI.h" +#include "include/private/base/SkAssert.h" +#include "include/private/base/SkAttributes.h" +#include "include/private/base/SkDebug.h" +// IWYU pragma: end_exports + +#include +#include + +#if !defined(SK_GANESH) && !defined(SK_GRAPHITE) +# undef SK_GL +# undef SK_VULKAN +# undef SK_METAL +# undef SK_DAWN +# undef SK_DIRECT3D +#endif + +// If SK_R32_SHIFT is set, we'll use that to choose RGBA or BGRA. +// If not, we'll default to RGBA everywhere except BGRA on Windows. +#if defined(SK_R32_SHIFT) + static_assert(SK_R32_SHIFT == 0 || SK_R32_SHIFT == 16, ""); +#elif defined(SK_BUILD_FOR_WIN) + #define SK_R32_SHIFT 16 +#else + #define SK_R32_SHIFT 0 +#endif + +#if defined(SK_B32_SHIFT) + static_assert(SK_B32_SHIFT == (16-SK_R32_SHIFT), ""); +#else + #define SK_B32_SHIFT (16-SK_R32_SHIFT) +#endif + +#define SK_G32_SHIFT 8 +#define SK_A32_SHIFT 24 + +/** + * SK_PMCOLOR_BYTE_ORDER can be used to query the byte order of SkPMColor at compile time. + */ +#ifdef SK_CPU_BENDIAN +# define SK_PMCOLOR_BYTE_ORDER(C0, C1, C2, C3) \ + (SK_ ## C3 ## 32_SHIFT == 0 && \ + SK_ ## C2 ## 32_SHIFT == 8 && \ + SK_ ## C1 ## 32_SHIFT == 16 && \ + SK_ ## C0 ## 32_SHIFT == 24) +#else +# define SK_PMCOLOR_BYTE_ORDER(C0, C1, C2, C3) \ + (SK_ ## C0 ## 32_SHIFT == 0 && \ + SK_ ## C1 ## 32_SHIFT == 8 && \ + SK_ ## C2 ## 32_SHIFT == 16 && \ + SK_ ## C3 ## 32_SHIFT == 24) +#endif + +#if defined SK_DEBUG && defined SK_BUILD_FOR_WIN + #ifdef free + #undef free + #endif + #include + #undef free +#endif + +#ifndef SK_ALLOW_STATIC_GLOBAL_INITIALIZERS + #define SK_ALLOW_STATIC_GLOBAL_INITIALIZERS 0 +#endif + +#if !defined(SK_GAMMA_EXPONENT) + #define SK_GAMMA_EXPONENT (0.0f) // SRGB +#endif + +#if !defined(SK_GAMMA_CONTRAST) + // A value of 0.5 for SK_GAMMA_CONTRAST appears to be a good compromise. + // With lower values small text appears washed out (though correctly so). + // With higher values lcd fringing is worse and the smoothing effect of + // partial coverage is diminished. + #define SK_GAMMA_CONTRAST (0.5f) +#endif + +#if defined(SK_HISTOGRAM_ENUMERATION) || \ + defined(SK_HISTOGRAM_BOOLEAN) || \ + defined(SK_HISTOGRAM_EXACT_LINEAR) || \ + defined(SK_HISTOGRAM_MEMORY_KB) +# define SK_HISTOGRAMS_ENABLED 1 +#else +# define SK_HISTOGRAMS_ENABLED 0 +#endif + +#ifndef SK_HISTOGRAM_BOOLEAN +# define SK_HISTOGRAM_BOOLEAN(name, sample) +#endif + +#ifndef SK_HISTOGRAM_ENUMERATION +# define SK_HISTOGRAM_ENUMERATION(name, sample, enum_size) +#endif + +#ifndef SK_HISTOGRAM_EXACT_LINEAR +# define SK_HISTOGRAM_EXACT_LINEAR(name, sample, value_max) +#endif + +#ifndef SK_HISTOGRAM_MEMORY_KB +# define SK_HISTOGRAM_MEMORY_KB(name, sample) +#endif + +#define SK_HISTOGRAM_PERCENTAGE(name, percent_as_int) \ + SK_HISTOGRAM_EXACT_LINEAR(name, percent_as_int, 101) + +// The top-level define SK_ENABLE_OPTIMIZE_SIZE can be used to remove several large features at once +#if defined(SK_ENABLE_OPTIMIZE_SIZE) + #if !defined(SK_FORCE_RASTER_PIPELINE_BLITTER) + #define SK_FORCE_RASTER_PIPELINE_BLITTER + #endif + #define SK_DISABLE_SDF_TEXT +#endif + +#ifndef SK_DISABLE_LEGACY_SHADERCONTEXT +# define SK_ENABLE_LEGACY_SHADERCONTEXT +#endif + +#if defined(SK_BUILD_FOR_LIBFUZZER) || defined(SK_BUILD_FOR_AFL_FUZZ) +#if !defined(SK_BUILD_FOR_FUZZER) + #define SK_BUILD_FOR_FUZZER +#endif +#endif + +/** + * These defines are set to 0 or 1, rather than being undefined or defined + * TODO: consider updating these for consistency + */ + +#if !defined(GR_CACHE_STATS) + #if defined(SK_DEBUG) || defined(SK_DUMP_STATS) + #define GR_CACHE_STATS 1 + #else + #define GR_CACHE_STATS 0 + #endif +#endif + +#if !defined(GR_GPU_STATS) + #if defined(SK_DEBUG) || defined(SK_DUMP_STATS) || defined(GR_TEST_UTILS) + #define GR_GPU_STATS 1 + #else + #define GR_GPU_STATS 0 + #endif +#endif + +//////////////////////////////////////////////////////////////////////////////// + +typedef uint32_t SkFourByteTag; +static inline constexpr SkFourByteTag SkSetFourByteTag(char a, char b, char c, char d) { + return (((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)c << 8) | (uint32_t)d); +} + +//////////////////////////////////////////////////////////////////////////////// + +/** 32 bit integer to hold a unicode value +*/ +typedef int32_t SkUnichar; + +/** 16 bit unsigned integer to hold a glyph index +*/ +typedef uint16_t SkGlyphID; + +/** 32 bit value to hold a millisecond duration + Note that SK_MSecMax is about 25 days. +*/ +typedef uint32_t SkMSec; + +/** Maximum representable milliseconds; 24d 20h 31m 23.647s. +*/ +static constexpr SkMSec SK_MSecMax = INT32_MAX; + +/** The generation IDs in Skia reserve 0 has an invalid marker. +*/ +static constexpr uint32_t SK_InvalidGenID = 0; + +/** The unique IDs in Skia reserve 0 has an invalid marker. +*/ +static constexpr uint32_t SK_InvalidUniqueID = 0; + + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkUnPreMultiply.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkUnPreMultiply.h new file mode 100644 index 0000000000..649c89f9cc --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkUnPreMultiply.h @@ -0,0 +1,55 @@ + +/* + * 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 SkUnPreMultiply_DEFINED +#define SkUnPreMultiply_DEFINED + +#include "include/core/SkColor.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkCPUTypes.h" + +#include + +class SK_API SkUnPreMultiply { +public: + typedef uint32_t Scale; + + // index this table with alpha [0..255] + static const Scale* GetScaleTable() { + return gTable; + } + + static Scale GetScale(U8CPU alpha) { + SkASSERT(alpha <= 255); + return gTable[alpha]; + } + + /** Usage: + + const Scale* table = SkUnPreMultiply::GetScaleTable(); + + for (...) { + unsigned a = ... + SkUnPreMultiply::Scale scale = table[a]; + + red = SkUnPreMultiply::ApplyScale(scale, red); + ... + // now red is unpremultiplied + } + */ + static U8CPU ApplyScale(Scale scale, U8CPU component) { + SkASSERT(component <= 255); + return (scale * component + (1 << 23)) >> 24; + } + + static SkColor PMColorToColor(SkPMColor c); + +private: + static const uint32_t gTable[256]; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkVertices.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkVertices.h new file mode 100644 index 0000000000..0f17e45216 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkVertices.h @@ -0,0 +1,136 @@ +/* + * 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 SkVertices_DEFINED +#define SkVertices_DEFINED + +#include "include/core/SkColor.h" +#include "include/core/SkPoint.h" +#include "include/core/SkRect.h" +#include "include/core/SkRefCnt.h" +#include "include/private/base/SkAPI.h" + +#include +#include +#include + +class SkVerticesPriv; + +/** + * An immutable set of vertex data that can be used with SkCanvas::drawVertices. + */ +class SK_API SkVertices : public SkNVRefCnt { + struct Desc; + struct Sizes; +public: + enum VertexMode { + kTriangles_VertexMode, + kTriangleStrip_VertexMode, + kTriangleFan_VertexMode, + + kLast_VertexMode = kTriangleFan_VertexMode, + }; + + /** + * Create a vertices by copying the specified arrays. texs, colors may be nullptr, + * and indices is ignored if indexCount == 0. + */ + static sk_sp MakeCopy(VertexMode mode, int vertexCount, + const SkPoint positions[], + const SkPoint texs[], + const SkColor colors[], + int indexCount, + const uint16_t indices[]); + + static sk_sp MakeCopy(VertexMode mode, int vertexCount, + const SkPoint positions[], + const SkPoint texs[], + const SkColor colors[]) { + return MakeCopy(mode, + vertexCount, + positions, + texs, + colors, + 0, + nullptr); + } + + enum BuilderFlags { + kHasTexCoords_BuilderFlag = 1 << 0, + kHasColors_BuilderFlag = 1 << 1, + }; + class SK_API Builder { + public: + Builder(VertexMode mode, int vertexCount, int indexCount, uint32_t flags); + + bool isValid() const { return fVertices != nullptr; } + + SkPoint* positions(); + uint16_t* indices(); // returns null if there are no indices + + // If we have custom attributes, these will always be null + SkPoint* texCoords(); // returns null if there are no texCoords + SkColor* colors(); // returns null if there are no colors + + // Detach the built vertices object. After the first call, this will always return null. + sk_sp detach(); + + private: + Builder(const Desc&); + + void init(const Desc&); + + // holds a partially complete object. only completed in detach() + sk_sp fVertices; + // Extra storage for intermediate vertices in the case where the client specifies indexed + // triangle fans. These get converted to indexed triangles when the Builder is finalized. + std::unique_ptr fIntermediateFanIndices; + + friend class SkVertices; + friend class SkVerticesPriv; + }; + + uint32_t uniqueID() const { return fUniqueID; } + const SkRect& bounds() const { return fBounds; } + + // returns approximate byte size of the vertices object + size_t approximateSize() const; + + // Provides access to functions that aren't part of the public API. + SkVerticesPriv priv(); + const SkVerticesPriv priv() const; // NOLINT(readability-const-return-type) + +private: + SkVertices() {} + + friend class SkVerticesPriv; + + // these are needed since we've manually sized our allocation (see Builder::init) + friend class SkNVRefCnt; + void operator delete(void* p); + + Sizes getSizes() const; + + // we store this first, to pair with the refcnt in our base-class, so we don't have an + // unnecessary pad between it and the (possibly 8-byte aligned) ptrs. + uint32_t fUniqueID; + + // these point inside our allocation, so none of these can be "freed" + SkPoint* fPositions; // [vertexCount] + uint16_t* fIndices; // [indexCount] or null + SkPoint* fTexs; // [vertexCount] or null + SkColor* fColors; // [vertexCount] or null + + SkRect fBounds; // computed to be the union of the fPositions[] + int fVertexCount; + int fIndexCount; + + VertexMode fMode; + // below here is where the actual array data is stored. +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkYUVAInfo.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkYUVAInfo.h new file mode 100644 index 0000000000..bbbae5d383 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkYUVAInfo.h @@ -0,0 +1,308 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkYUVAInfo_DEFINED +#define SkYUVAInfo_DEFINED + +#include "include/codec/SkEncodedOrigin.h" +#include "include/core/SkImageInfo.h" +#include "include/core/SkMatrix.h" +#include "include/core/SkSize.h" +#include "include/core/SkTypes.h" + +#include +#include +#include +#include + +/** + * Specifies the structure of planes for a YUV image with optional alpha. The actual planar data + * is not part of this structure and depending on usage is in external textures or pixmaps. + */ +class SK_API SkYUVAInfo { +public: + enum YUVAChannels { kY, kU, kV, kA, kLast = kA }; + static constexpr int kYUVAChannelCount = static_cast(YUVAChannels::kLast + 1); + + struct YUVALocation; // For internal use. + using YUVALocations = std::array; + + /** + * Specifies how YUV (and optionally A) are divided among planes. Planes are separated by + * underscores in the enum value names. Within each plane the pixmap/texture channels are + * mapped to the YUVA channels in the order specified, e.g. for kY_UV Y is in channel 0 of plane + * 0, U is in channel 0 of plane 1, and V is in channel 1 of plane 1. Channel ordering + * within a pixmap/texture given the channels it contains: + * A: 0:A + * Luminance/Gray: 0:Gray + * Luminance/Gray + Alpha: 0:Gray, 1:A + * RG 0:R, 1:G + * RGB 0:R, 1:G, 2:B + * RGBA 0:R, 1:G, 2:B, 3:A + */ + enum class PlaneConfig { + kUnknown, + + kY_U_V, ///< Plane 0: Y, Plane 1: U, Plane 2: V + kY_V_U, ///< Plane 0: Y, Plane 1: V, Plane 2: U + kY_UV, ///< Plane 0: Y, Plane 1: UV + kY_VU, ///< Plane 0: Y, Plane 1: VU + kYUV, ///< Plane 0: YUV + kUYV, ///< Plane 0: UYV + + kY_U_V_A, ///< Plane 0: Y, Plane 1: U, Plane 2: V, Plane 3: A + kY_V_U_A, ///< Plane 0: Y, Plane 1: V, Plane 2: U, Plane 3: A + kY_UV_A, ///< Plane 0: Y, Plane 1: UV, Plane 2: A + kY_VU_A, ///< Plane 0: Y, Plane 1: VU, Plane 2: A + kYUVA, ///< Plane 0: YUVA + kUYVA, ///< Plane 0: UYVA + + kLast = kUYVA + }; + + /** + * UV subsampling is also specified in the enum value names using J:a:b notation (e.g. 4:2:0 is + * 1/2 horizontal and 1/2 vertical resolution for U and V). If alpha is present it is not sub- + * sampled. Note that Subsampling values other than k444 are only valid with PlaneConfig values + * that have U and V in different planes than Y (and A, if present). + */ + enum class Subsampling { + kUnknown, + + k444, ///< No subsampling. UV values for each Y. + k422, ///< 1 set of UV values for each 2x1 block of Y values. + k420, ///< 1 set of UV values for each 2x2 block of Y values. + k440, ///< 1 set of UV values for each 1x2 block of Y values. + k411, ///< 1 set of UV values for each 4x1 block of Y values. + k410, ///< 1 set of UV values for each 4x2 block of Y values. + + kLast = k410 + }; + + /** + * Describes how subsampled chroma values are sited relative to luma values. + * + * Currently only centered siting is supported but will expand to support additional sitings. + */ + enum class Siting { + /** + * Subsampled chroma value is sited at the center of the block of corresponding luma values. + */ + kCentered, + }; + + static constexpr int kMaxPlanes = 4; + + /** ratio of Y/A values to U/V values in x and y. */ + static std::tuple SubsamplingFactors(Subsampling); + + /** + * SubsamplingFactors(Subsampling) if planedIdx refers to a U/V plane and otherwise {1, 1} if + * inputs are valid. Invalid inputs consist of incompatible PlaneConfig/Subsampling/planeIdx + * combinations. {0, 0} is returned for invalid inputs. + */ + static std::tuple PlaneSubsamplingFactors(PlaneConfig, Subsampling, int planeIdx); + + /** + * Given image dimensions, a planer configuration, subsampling, and origin, determine the + * expected size of each plane. Returns the number of expected planes. planeDimensions[0] + * through planeDimensions[] are written. The input image dimensions are as displayed + * (after the planes have been transformed to the intended display orientation). The plane + * dimensions are output as the planes are stored in memory (may be rotated from image + * dimensions). + */ + static int PlaneDimensions(SkISize imageDimensions, + PlaneConfig, + Subsampling, + SkEncodedOrigin, + SkISize planeDimensions[kMaxPlanes]); + + /** Number of planes for a given PlaneConfig. */ + static constexpr int NumPlanes(PlaneConfig); + + /** + * Number of Y, U, V, A channels in the ith plane for a given PlaneConfig (or 0 if i is + * invalid). + */ + static constexpr int NumChannelsInPlane(PlaneConfig, int i); + + /** + * Given a PlaneConfig and a set of channel flags for each plane, convert to YUVALocations + * representation. Fails if channel flags aren't valid for the PlaneConfig (i.e. don't have + * enough channels in a plane) by returning an invalid set of locations (plane indices are -1). + */ + static YUVALocations GetYUVALocations(PlaneConfig, const uint32_t* planeChannelFlags); + + /** Does the PlaneConfig have alpha values? */ + static bool HasAlpha(PlaneConfig); + + SkYUVAInfo() = default; + SkYUVAInfo(const SkYUVAInfo&) = default; + + /** + * 'dimensions' should specify the size of the full resolution image (after planes have been + * oriented to how the image is displayed as indicated by 'origin'). + */ + SkYUVAInfo(SkISize dimensions, + PlaneConfig, + Subsampling, + SkYUVColorSpace, + SkEncodedOrigin origin = kTopLeft_SkEncodedOrigin, + Siting sitingX = Siting::kCentered, + Siting sitingY = Siting::kCentered); + + SkYUVAInfo& operator=(const SkYUVAInfo& that) = default; + + PlaneConfig planeConfig() const { return fPlaneConfig; } + Subsampling subsampling() const { return fSubsampling; } + + std::tuple planeSubsamplingFactors(int planeIdx) const { + return PlaneSubsamplingFactors(fPlaneConfig, fSubsampling, planeIdx); + } + + /** + * Dimensions of the full resolution image (after planes have been oriented to how the image + * is displayed as indicated by fOrigin). + */ + SkISize dimensions() const { return fDimensions; } + int width() const { return fDimensions.width(); } + int height() const { return fDimensions.height(); } + + SkYUVColorSpace yuvColorSpace() const { return fYUVColorSpace; } + Siting sitingX() const { return fSitingX; } + Siting sitingY() const { return fSitingY; } + + SkEncodedOrigin origin() const { return fOrigin; } + + SkMatrix originMatrix() const { + return SkEncodedOriginToMatrix(fOrigin, this->width(), this->height()); + } + + bool hasAlpha() const { return HasAlpha(fPlaneConfig); } + + /** + * Returns the number of planes and initializes planeDimensions[0]..planeDimensions[] to + * the expected dimensions for each plane. Dimensions are as stored in memory, before + * transformation to image display space as indicated by origin(). + */ + int planeDimensions(SkISize planeDimensions[kMaxPlanes]) const { + return PlaneDimensions(fDimensions, fPlaneConfig, fSubsampling, fOrigin, planeDimensions); + } + + /** + * Given a per-plane row bytes, determine size to allocate for all planes. Optionally retrieves + * the per-plane byte sizes in planeSizes if not null. If total size overflows will return + * SIZE_MAX and set all planeSizes to SIZE_MAX. + */ + size_t computeTotalBytes(const size_t rowBytes[kMaxPlanes], + size_t planeSizes[kMaxPlanes] = nullptr) const; + + int numPlanes() const { return NumPlanes(fPlaneConfig); } + + int numChannelsInPlane(int i) const { return NumChannelsInPlane(fPlaneConfig, i); } + + /** + * Given a set of channel flags for each plane, converts this->planeConfig() to YUVALocations + * representation. Fails if the channel flags aren't valid for the PlaneConfig (i.e. don't have + * enough channels in a plane) by returning default initialized locations (all plane indices are + * -1). + */ + YUVALocations toYUVALocations(const uint32_t* channelFlags) const; + + /** + * Makes a SkYUVAInfo that is identical to this one but with the passed Subsampling. If the + * passed Subsampling is not k444 and this info's PlaneConfig is not compatible with chroma + * subsampling (because Y is in the same plane as UV) then the result will be an invalid + * SkYUVAInfo. + */ + SkYUVAInfo makeSubsampling(SkYUVAInfo::Subsampling) const; + + /** + * Makes a SkYUVAInfo that is identical to this one but with the passed dimensions. If the + * passed dimensions is empty then the result will be an invalid SkYUVAInfo. + */ + SkYUVAInfo makeDimensions(SkISize) const; + + bool operator==(const SkYUVAInfo& that) const; + bool operator!=(const SkYUVAInfo& that) const { return !(*this == that); } + + bool isValid() const { return fPlaneConfig != PlaneConfig::kUnknown; } + +private: + SkISize fDimensions = {0, 0}; + + PlaneConfig fPlaneConfig = PlaneConfig::kUnknown; + Subsampling fSubsampling = Subsampling::kUnknown; + + SkYUVColorSpace fYUVColorSpace = SkYUVColorSpace::kIdentity_SkYUVColorSpace; + + /** + * YUVA data often comes from formats like JPEG that support EXIF orientation. + * Code that operates on the raw YUV data often needs to know that orientation. + */ + SkEncodedOrigin fOrigin = kTopLeft_SkEncodedOrigin; + + Siting fSitingX = Siting::kCentered; + Siting fSitingY = Siting::kCentered; +}; + +constexpr int SkYUVAInfo::NumPlanes(PlaneConfig planeConfig) { + switch (planeConfig) { + case PlaneConfig::kUnknown: return 0; + case PlaneConfig::kY_U_V: return 3; + case PlaneConfig::kY_V_U: return 3; + case PlaneConfig::kY_UV: return 2; + case PlaneConfig::kY_VU: return 2; + case PlaneConfig::kYUV: return 1; + case PlaneConfig::kUYV: return 1; + case PlaneConfig::kY_U_V_A: return 4; + case PlaneConfig::kY_V_U_A: return 4; + case PlaneConfig::kY_UV_A: return 3; + case PlaneConfig::kY_VU_A: return 3; + case PlaneConfig::kYUVA: return 1; + case PlaneConfig::kUYVA: return 1; + } + SkUNREACHABLE; +} + +constexpr int SkYUVAInfo::NumChannelsInPlane(PlaneConfig config, int i) { + switch (config) { + case PlaneConfig::kUnknown: + return 0; + + case SkYUVAInfo::PlaneConfig::kY_U_V: + case SkYUVAInfo::PlaneConfig::kY_V_U: + return i >= 0 && i < 3 ? 1 : 0; + case SkYUVAInfo::PlaneConfig::kY_UV: + case SkYUVAInfo::PlaneConfig::kY_VU: + switch (i) { + case 0: return 1; + case 1: return 2; + default: return 0; + } + case SkYUVAInfo::PlaneConfig::kYUV: + case SkYUVAInfo::PlaneConfig::kUYV: + return i == 0 ? 3 : 0; + case SkYUVAInfo::PlaneConfig::kY_U_V_A: + case SkYUVAInfo::PlaneConfig::kY_V_U_A: + return i >= 0 && i < 4 ? 1 : 0; + case SkYUVAInfo::PlaneConfig::kY_UV_A: + case SkYUVAInfo::PlaneConfig::kY_VU_A: + switch (i) { + case 0: return 1; + case 1: return 2; + case 2: return 1; + default: return 0; + } + case SkYUVAInfo::PlaneConfig::kYUVA: + case SkYUVAInfo::PlaneConfig::kUYVA: + return i == 0 ? 4 : 0; + } + return 0; +} + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkYUVAPixmaps.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkYUVAPixmaps.h new file mode 100644 index 0000000000..11ec6c01a6 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/core/SkYUVAPixmaps.h @@ -0,0 +1,337 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkYUVAPixmaps_DEFINED +#define SkYUVAPixmaps_DEFINED + +#include "include/core/SkColorType.h" +#include "include/core/SkData.h" +#include "include/core/SkImageInfo.h" +#include "include/core/SkPixmap.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkSize.h" +#include "include/core/SkTypes.h" +#include "include/core/SkYUVAInfo.h" +#include "include/private/base/SkTo.h" + +#include +#include +#include +#include + +/** + * SkYUVAInfo combined with per-plane SkColorTypes and row bytes. Fully specifies the SkPixmaps + * for a YUVA image without the actual pixel memory and data. + */ +class SK_API SkYUVAPixmapInfo { +public: + static constexpr auto kMaxPlanes = SkYUVAInfo::kMaxPlanes; + + using PlaneConfig = SkYUVAInfo::PlaneConfig; + using Subsampling = SkYUVAInfo::Subsampling; + + /** + * Data type for Y, U, V, and possibly A channels independent of how values are packed into + * planes. + **/ + enum class DataType { + kUnorm8, ///< 8 bit unsigned normalized + kUnorm16, ///< 16 bit unsigned normalized + kFloat16, ///< 16 bit (half) floating point + kUnorm10_Unorm2, ///< 10 bit unorm for Y, U, and V. 2 bit unorm for alpha (if present). + + kLast = kUnorm10_Unorm2 + }; + static constexpr int kDataTypeCnt = static_cast(DataType::kLast) + 1; + + class SK_API SupportedDataTypes { + public: + /** Defaults to nothing supported. */ + constexpr SupportedDataTypes() = default; + + /** All legal combinations of PlaneConfig and DataType are supported. */ + static constexpr SupportedDataTypes All(); + + /** + * Checks whether there is a supported combination of color types for planes structured + * as indicated by PlaneConfig with channel data types as indicated by DataType. + */ + constexpr bool supported(PlaneConfig, DataType) const; + + /** + * Update to add support for pixmaps with numChannel channels where each channel is + * represented as DataType. + */ + void enableDataType(DataType, int numChannels); + + private: + // The bit for DataType dt with n channels is at index kDataTypeCnt*(n-1) + dt. + std::bitset fDataTypeSupport = {}; + }; + + /** + * Gets the default SkColorType to use with numChannels channels, each represented as DataType. + * Returns kUnknown_SkColorType if no such color type. + */ + static constexpr SkColorType DefaultColorTypeForDataType(DataType dataType, int numChannels); + + /** + * If the SkColorType is supported for YUVA pixmaps this will return the number of YUVA channels + * that can be stored in a plane of this color type and what the DataType is of those channels. + * If the SkColorType is not supported as a YUVA plane the number of channels is reported as 0 + * and the DataType returned should be ignored. + */ + static std::tuple NumChannelsAndDataType(SkColorType); + + /** Default SkYUVAPixmapInfo is invalid. */ + SkYUVAPixmapInfo() = default; + + /** + * Initializes the SkYUVAPixmapInfo from a SkYUVAInfo with per-plane color types and row bytes. + * This will be invalid if the colorTypes aren't compatible with the SkYUVAInfo or if a + * rowBytes entry is not valid for the plane dimensions and color type. Color type and + * row byte values beyond the number of planes in SkYUVAInfo are ignored. All SkColorTypes + * must have the same DataType or this will be invalid. + * + * If rowBytes is nullptr then bpp*width is assumed for each plane. + */ + SkYUVAPixmapInfo(const SkYUVAInfo&, + const SkColorType[kMaxPlanes], + const size_t rowBytes[kMaxPlanes]); + /** + * Like above but uses DefaultColorTypeForDataType to determine each plane's SkColorType. If + * rowBytes is nullptr then bpp*width is assumed for each plane. + */ + SkYUVAPixmapInfo(const SkYUVAInfo&, DataType, const size_t rowBytes[kMaxPlanes]); + + SkYUVAPixmapInfo(const SkYUVAPixmapInfo&) = default; + + SkYUVAPixmapInfo& operator=(const SkYUVAPixmapInfo&) = default; + + bool operator==(const SkYUVAPixmapInfo&) const; + bool operator!=(const SkYUVAPixmapInfo& that) const { return !(*this == that); } + + const SkYUVAInfo& yuvaInfo() const { return fYUVAInfo; } + + SkYUVColorSpace yuvColorSpace() const { return fYUVAInfo.yuvColorSpace(); } + + /** The number of SkPixmap planes, 0 if this SkYUVAPixmapInfo is invalid. */ + int numPlanes() const { return fYUVAInfo.numPlanes(); } + + /** The per-YUV[A] channel data type. */ + DataType dataType() const { return fDataType; } + + /** + * Row bytes for the ith plane. Returns zero if i >= numPlanes() or this SkYUVAPixmapInfo is + * invalid. + */ + size_t rowBytes(int i) const { return fRowBytes[static_cast(i)]; } + + /** Image info for the ith plane, or default SkImageInfo if i >= numPlanes() */ + const SkImageInfo& planeInfo(int i) const { return fPlaneInfos[static_cast(i)]; } + + /** + * Determine size to allocate for all planes. Optionally retrieves the per-plane sizes in + * planeSizes if not null. If total size overflows will return SIZE_MAX and set all planeSizes + * to SIZE_MAX. Returns 0 and fills planesSizes with 0 if this SkYUVAPixmapInfo is not valid. + */ + size_t computeTotalBytes(size_t planeSizes[kMaxPlanes] = nullptr) const; + + /** + * Takes an allocation that is assumed to be at least computeTotalBytes() in size and configures + * the first numPlanes() entries in pixmaps array to point into that memory. The remaining + * entries of pixmaps are default initialized. Fails if this SkYUVAPixmapInfo not valid. + */ + bool initPixmapsFromSingleAllocation(void* memory, SkPixmap pixmaps[kMaxPlanes]) const; + + /** + * Returns true if this has been configured with a non-empty dimensioned SkYUVAInfo with + * compatible color types and row bytes. + */ + bool isValid() const { return fYUVAInfo.isValid(); } + + /** Is this valid and does it use color types allowed by the passed SupportedDataTypes? */ + bool isSupported(const SupportedDataTypes&) const; + +private: + SkYUVAInfo fYUVAInfo; + std::array fPlaneInfos = {}; + std::array fRowBytes = {}; + DataType fDataType = DataType::kUnorm8; + static_assert(kUnknown_SkColorType == 0, "default init isn't kUnknown"); +}; + +/** + * Helper to store SkPixmap planes as described by a SkYUVAPixmapInfo. Can be responsible for + * allocating/freeing memory for pixmaps or use external memory. + */ +class SK_API SkYUVAPixmaps { +public: + using DataType = SkYUVAPixmapInfo::DataType; + static constexpr auto kMaxPlanes = SkYUVAPixmapInfo::kMaxPlanes; + + static SkColorType RecommendedRGBAColorType(DataType); + + /** Allocate space for pixmaps' pixels in the SkYUVAPixmaps. */ + static SkYUVAPixmaps Allocate(const SkYUVAPixmapInfo& yuvaPixmapInfo); + + /** + * Use storage in SkData as backing store for pixmaps' pixels. SkData is retained by the + * SkYUVAPixmaps. + */ + static SkYUVAPixmaps FromData(const SkYUVAPixmapInfo&, sk_sp); + + /** + * Makes a deep copy of the src SkYUVAPixmaps. The returned SkYUVAPixmaps owns its planes' + * backing stores. + */ + static SkYUVAPixmaps MakeCopy(const SkYUVAPixmaps& src); + + /** + * Use passed in memory as backing store for pixmaps' pixels. Caller must ensure memory remains + * allocated while pixmaps are in use. There must be at least + * SkYUVAPixmapInfo::computeTotalBytes() allocated starting at memory. + */ + static SkYUVAPixmaps FromExternalMemory(const SkYUVAPixmapInfo&, void* memory); + + /** + * Wraps existing SkPixmaps. The SkYUVAPixmaps will have no ownership of the SkPixmaps' pixel + * memory so the caller must ensure it remains valid. Will return an invalid SkYUVAPixmaps if + * the SkYUVAInfo isn't compatible with the SkPixmap array (number of planes, plane dimensions, + * sufficient color channels in planes, ...). + */ + static SkYUVAPixmaps FromExternalPixmaps(const SkYUVAInfo&, const SkPixmap[kMaxPlanes]); + + /** Default SkYUVAPixmaps is invalid. */ + SkYUVAPixmaps() = default; + ~SkYUVAPixmaps() = default; + + SkYUVAPixmaps(SkYUVAPixmaps&& that) = default; + SkYUVAPixmaps& operator=(SkYUVAPixmaps&& that) = default; + SkYUVAPixmaps(const SkYUVAPixmaps&) = default; + SkYUVAPixmaps& operator=(const SkYUVAPixmaps& that) = default; + + /** Does have initialized pixmaps compatible with its SkYUVAInfo. */ + bool isValid() const { return !fYUVAInfo.dimensions().isEmpty(); } + + const SkYUVAInfo& yuvaInfo() const { return fYUVAInfo; } + + DataType dataType() const { return fDataType; } + + SkYUVAPixmapInfo pixmapsInfo() const; + + /** Number of pixmap planes or 0 if this SkYUVAPixmaps is invalid. */ + int numPlanes() const { return this->isValid() ? fYUVAInfo.numPlanes() : 0; } + + /** + * Access the SkPixmap planes. They are default initialized if this is not a valid + * SkYUVAPixmaps. + */ + const std::array& planes() const { return fPlanes; } + + /** + * Get the ith SkPixmap plane. SkPixmap will be default initialized if i >= numPlanes or this + * SkYUVAPixmaps is invalid. + */ + const SkPixmap& plane(int i) const { return fPlanes[SkToSizeT(i)]; } + + /** + * Computes a YUVALocations representation of the planar layout. The result is guaranteed to be + * valid if this->isValid(). + */ + SkYUVAInfo::YUVALocations toYUVALocations() const; + + /** Does this SkPixmaps own the backing store of the planes? */ + bool ownsStorage() const { return SkToBool(fData); } + +private: + SkYUVAPixmaps(const SkYUVAPixmapInfo&, sk_sp); + SkYUVAPixmaps(const SkYUVAInfo&, DataType, const SkPixmap[kMaxPlanes]); + + std::array fPlanes = {}; + sk_sp fData; + SkYUVAInfo fYUVAInfo; + DataType fDataType; +}; + +////////////////////////////////////////////////////////////////////////////// + +constexpr SkYUVAPixmapInfo::SupportedDataTypes SkYUVAPixmapInfo::SupportedDataTypes::All() { + using ULL = unsigned long long; // bitset cons. takes this. + ULL bits = 0; + for (ULL c = 1; c <= 4; ++c) { + for (ULL dt = 0; dt <= ULL(kDataTypeCnt); ++dt) { + if (DefaultColorTypeForDataType(static_cast(dt), + static_cast(c)) != kUnknown_SkColorType) { + bits |= ULL(1) << (dt + static_cast(kDataTypeCnt)*(c - 1)); + } + } + } + SupportedDataTypes combinations; + combinations.fDataTypeSupport = bits; + return combinations; +} + +constexpr bool SkYUVAPixmapInfo::SupportedDataTypes::supported(PlaneConfig config, + DataType type) const { + int n = SkYUVAInfo::NumPlanes(config); + for (int i = 0; i < n; ++i) { + auto c = static_cast(SkYUVAInfo::NumChannelsInPlane(config, i)); + SkASSERT(c >= 1 && c <= 4); + if (!fDataTypeSupport[static_cast(type) + + (c - 1)*static_cast(kDataTypeCnt)]) { + return false; + } + } + return true; +} + +constexpr SkColorType SkYUVAPixmapInfo::DefaultColorTypeForDataType(DataType dataType, + int numChannels) { + switch (numChannels) { + case 1: + switch (dataType) { + case DataType::kUnorm8: return kGray_8_SkColorType; + case DataType::kUnorm16: return kA16_unorm_SkColorType; + case DataType::kFloat16: return kA16_float_SkColorType; + case DataType::kUnorm10_Unorm2: return kUnknown_SkColorType; + } + break; + case 2: + switch (dataType) { + case DataType::kUnorm8: return kR8G8_unorm_SkColorType; + case DataType::kUnorm16: return kR16G16_unorm_SkColorType; + case DataType::kFloat16: return kR16G16_float_SkColorType; + case DataType::kUnorm10_Unorm2: return kUnknown_SkColorType; + } + break; + case 3: + // None of these are tightly packed. The intended use case is for interleaved YUVA + // planes where we're forcing opaqueness by ignoring the alpha values. + // There are "x" rather than "A" variants for Unorm8 and Unorm10_Unorm2 but we don't + // choose them because 1) there is no inherent advantage and 2) there is better support + // in the GPU backend for the "A" versions. + switch (dataType) { + case DataType::kUnorm8: return kRGBA_8888_SkColorType; + case DataType::kUnorm16: return kR16G16B16A16_unorm_SkColorType; + case DataType::kFloat16: return kRGBA_F16_SkColorType; + case DataType::kUnorm10_Unorm2: return kRGBA_1010102_SkColorType; + } + break; + case 4: + switch (dataType) { + case DataType::kUnorm8: return kRGBA_8888_SkColorType; + case DataType::kUnorm16: return kR16G16B16A16_unorm_SkColorType; + case DataType::kFloat16: return kRGBA_F16_SkColorType; + case DataType::kUnorm10_Unorm2: return kRGBA_1010102_SkColorType; + } + break; + } + return kUnknown_SkColorType; +} + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/docs/SkMultiPictureDocument.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/docs/SkMultiPictureDocument.h new file mode 100644 index 0000000000..5b8b8063b1 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/docs/SkMultiPictureDocument.h @@ -0,0 +1,53 @@ +/* + * 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 SkMultiPictureDocument_DEFINED +#define SkMultiPictureDocument_DEFINED + +#include "include/core/SkPicture.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkSize.h" +#include "include/core/SkTypes.h" + +#include + +class SkDocument; +class SkStreamSeekable; +class SkWStream; +struct SkDeserialProcs; +struct SkSerialProcs; + +struct SkDocumentPage { + sk_sp fPicture; + SkSize fSize; +}; + +namespace SkMultiPictureDocument { +/** + * Writes into a file format that is similar to SkPicture::serialize() + * Accepts a callback for endPage behavior + */ +SK_API sk_sp Make(SkWStream* dst, const SkSerialProcs* = nullptr, + std::function onEndPage = nullptr); + +/** + * Returns the number of pages in the SkMultiPictureDocument. + */ +SK_API int ReadPageCount(SkStreamSeekable* src); + +/** + * Read the SkMultiPictureDocument into the provided array of pages. + * dstArrayCount must equal SkMultiPictureDocumentReadPageCount(). + * Return false on error. + */ +SK_API bool Read(SkStreamSeekable* src, + SkDocumentPage* dstArray, + int dstArrayCount, + const SkDeserialProcs* = nullptr); +} // namespace SkMultiPictureDocument + +#endif // SkMultiPictureDocument_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/docs/SkPDFDocument.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/docs/SkPDFDocument.h new file mode 100644 index 0000000000..bf5fe9dd8e --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/docs/SkPDFDocument.h @@ -0,0 +1,224 @@ +// Copyright 2018 Google LLC. +// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. +#ifndef SkPDFDocument_DEFINED +#define SkPDFDocument_DEFINED + +#include "include/core/SkDocument.h" +#include "include/core/SkMilestone.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" +#include "include/core/SkString.h" +#include "include/private/base/SkAPI.h" +#include "include/private/base/SkNoncopyable.h" + +#include +#include +#include + +class SkCanvas; +class SkExecutor; +class SkPDFArray; +class SkPDFTagTree; +class SkWStream; + +#define SKPDF_STRING(X) SKPDF_STRING_IMPL(X) +#define SKPDF_STRING_IMPL(X) #X + +namespace SkPDF { + +/** Attributes for nodes in the PDF tree. */ +class SK_API AttributeList : SkNoncopyable { +public: + AttributeList(); + ~AttributeList(); + + // Each attribute must have an owner (e.g. "Layout", "List", "Table", etc) + // and an attribute name (e.g. "BBox", "RowSpan", etc.) from PDF32000_2008 14.8.5, + // and then a value of the proper type according to the spec. + void appendInt(const char* owner, const char* name, int value); + void appendFloat(const char* owner, const char* name, float value); + void appendName(const char* owner, const char* attrName, const char* value); + void appendFloatArray(const char* owner, + const char* name, + const std::vector& value); + void appendNodeIdArray(const char* owner, + const char* attrName, + const std::vector& nodeIds); + +private: + friend class ::SkPDFTagTree; + + std::unique_ptr fAttrs; +}; + +/** A node in a PDF structure tree, giving a semantic representation + of the content. Each node ID is associated with content + by passing the SkCanvas and node ID to SkPDF::SetNodeId() when drawing. + NodeIDs should be unique within each tree. +*/ +struct StructureElementNode { + SkString fTypeString; + std::vector> fChildVector; + int fNodeId = 0; + std::vector fAdditionalNodeIds; + AttributeList fAttributes; + SkString fAlt; + SkString fLang; +}; + +struct DateTime { + int16_t fTimeZoneMinutes; // The number of minutes that this + // is ahead of or behind UTC. + uint16_t fYear; //!< e.g. 2005 + uint8_t fMonth; //!< 1..12 + uint8_t fDayOfWeek; //!< 0..6, 0==Sunday + uint8_t fDay; //!< 1..31 + uint8_t fHour; //!< 0..23 + uint8_t fMinute; //!< 0..59 + uint8_t fSecond; //!< 0..59 + + void toISO8601(SkString* dst) const; +}; + +/** Optional metadata to be passed into the PDF factory function. +*/ +struct Metadata { + /** The document's title. + */ + SkString fTitle; + + /** The name of the person who created the document. + */ + SkString fAuthor; + + /** The subject of the document. + */ + SkString fSubject; + + /** Keywords associated with the document. Commas may be used to delineate + keywords within the string. + */ + SkString fKeywords; + + /** If the document was converted to PDF from another format, + the name of the conforming product that created the + original document from which it was converted. + */ + SkString fCreator; + + /** The product that is converting this document to PDF. + */ + SkString fProducer = SkString("Skia/PDF m" SKPDF_STRING(SK_MILESTONE)); + + /** The date and time the document was created. + The zero default value represents an unknown/unset time. + */ + DateTime fCreation = {0, 0, 0, 0, 0, 0, 0, 0}; + + /** The date and time the document was most recently modified. + The zero default value represents an unknown/unset time. + */ + DateTime fModified = {0, 0, 0, 0, 0, 0, 0, 0}; + + /** The natural language of the text in the PDF. If fLang is empty, the root + StructureElementNode::fLang will be used (if not empty). Text not in + this language should be marked with StructureElementNode::fLang. + */ + SkString fLang; + + /** The DPI (pixels-per-inch) at which features without native PDF support + will be rasterized (e.g. draw image with perspective, draw text with + perspective, ...) A larger DPI would create a PDF that reflects the + original intent with better fidelity, but it can make for larger PDF + files too, which would use more memory while rendering, and it would be + slower to be processed or sent online or to printer. + */ + SkScalar fRasterDPI = SK_ScalarDefaultRasterDPI; + + /** If true, include XMP metadata, a document UUID, and sRGB output intent + information. This adds length to the document and makes it + non-reproducable, but are necessary features for PDF/A-2b conformance + */ + bool fPDFA = false; + + /** Encoding quality controls the trade-off between size and quality. By + default this is set to 101 percent, which corresponds to lossless + encoding. If this value is set to a value <= 100, and the image is + opaque, it will be encoded (using JPEG) with that quality setting. + */ + int fEncodingQuality = 101; + + /** An optional tree of structured document tags that provide + a semantic representation of the content. The caller + should retain ownership. + */ + StructureElementNode* fStructureElementTreeRoot = nullptr; + + enum class Outline : int { + None = 0, + StructureElementHeaders = 1, + } fOutline = Outline::None; + + /** Executor to handle threaded work within PDF Backend. If this is nullptr, + then all work will be done serially on the main thread. To have worker + threads assist with various tasks, set this to a valid SkExecutor + instance. Currently used for executing Deflate algorithm in parallel. + + If set, the PDF output will be non-reproducible in the order and + internal numbering of objects, but should render the same. + + Experimental. + */ + SkExecutor* fExecutor = nullptr; + + /** PDF streams may be compressed to save space. + Use this to specify the desired compression vs time tradeoff. + */ + enum class CompressionLevel : int { + Default = -1, + None = 0, + LowButFast = 1, + Average = 6, + HighButSlow = 9, + } fCompressionLevel = CompressionLevel::Default; + + /** Preferred Subsetter. */ + enum Subsetter { + kHarfbuzz_Subsetter, + } fSubsetter = kHarfbuzz_Subsetter; +}; + +/** Associate a node ID with subsequent drawing commands in an + SkCanvas. The same node ID can appear in a StructureElementNode + in order to associate a document's structure element tree with + its content. + + A node ID of zero indicates no node ID. + + @param canvas The canvas used to draw to the PDF. + @param nodeId The node ID for subsequent drawing commands. +*/ +SK_API void SetNodeId(SkCanvas* dst, int nodeID); + +/** Create a PDF-backed document, writing the results into a SkWStream. + + PDF pages are sized in point units. 1 pt == 1/72 inch == 127/360 mm. + + @param stream A PDF document will be written to this stream. The document may write + to the stream at anytime during its lifetime, until either close() is + called or the document is deleted. + @param metadata a PDFmetadata object. Any fields may be left empty. + + @returns NULL if there is an error, otherwise a newly created PDF-backed SkDocument. +*/ +SK_API sk_sp MakeDocument(SkWStream* stream, const Metadata& metadata); + +static inline sk_sp MakeDocument(SkWStream* stream) { + return MakeDocument(stream, Metadata()); +} + +} // namespace SkPDF + +#undef SKPDF_STRING +#undef SKPDF_STRING_IMPL +#endif // SkPDFDocument_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/docs/SkXPSDocument.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/docs/SkXPSDocument.h new file mode 100644 index 0000000000..5cd0777c9b --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/docs/SkXPSDocument.h @@ -0,0 +1,27 @@ +/* + * 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 SkXPSDocument_DEFINED +#define SkXPSDocument_DEFINED + +#include "include/core/SkTypes.h" + +#ifdef SK_BUILD_FOR_WIN + +#include "include/core/SkDocument.h" + +struct IXpsOMObjectFactory; + +namespace SkXPS { + +SK_API sk_sp MakeDocument(SkWStream* stream, + IXpsOMObjectFactory* xpsFactory, + SkScalar dpi = SK_ScalarDefaultRasterDPI); + +} // namespace SkXPS +#endif // SK_BUILD_FOR_WIN +#endif // SkXPSDocument_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/Sk1DPathEffect.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/Sk1DPathEffect.h new file mode 100644 index 0000000000..fd05c52df7 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/Sk1DPathEffect.h @@ -0,0 +1,40 @@ +/* + * 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 Sk1DPathEffect_DEFINED +#define Sk1DPathEffect_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" + +class SkPath; +class SkPathEffect; + +class SK_API SkPath1DPathEffect { +public: + enum Style { + kTranslate_Style, // translate the shape to each position + kRotate_Style, // rotate the shape about its center + kMorph_Style, // transform each point, and turn lines into curves + + kLastEnum_Style = kMorph_Style, + }; + + /** Dash by replicating the specified path. + @param path The path to replicate (dash) + @param advance The space between instances of path + @param phase distance (mod advance) along path for its initial position + @param style how to transform path at each point (based on the current + position and tangent) + */ + static sk_sp Make(const SkPath& path, SkScalar advance, SkScalar phase, Style); + + static void RegisterFlattenables(); +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/Sk2DPathEffect.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/Sk2DPathEffect.h new file mode 100644 index 0000000000..b8b3ba3981 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/Sk2DPathEffect.h @@ -0,0 +1,33 @@ +/* + * 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 Sk2DPathEffect_DEFINED +#define Sk2DPathEffect_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" + +class SkMatrix; +class SkPath; +class SkPathEffect; + +class SK_API SkLine2DPathEffect { +public: + static sk_sp Make(SkScalar width, const SkMatrix& matrix); + + static void RegisterFlattenables(); +}; + +class SK_API SkPath2DPathEffect { +public: + static sk_sp Make(const SkMatrix& matrix, const SkPath& path); + + static void RegisterFlattenables(); +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkBlenders.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkBlenders.h new file mode 100644 index 0000000000..7507071b05 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkBlenders.h @@ -0,0 +1,27 @@ +/* + * 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 SkBlenders_DEFINED +#define SkBlenders_DEFINED + +#include "include/core/SkBlender.h" + +class SK_API SkBlenders { +public: + /** + * Create a blender that implements the following: + * k1 * src * dst + k2 * src + k3 * dst + k4 + * @param k1, k2, k3, k4 The four coefficients. + * @param enforcePMColor If true, the RGB channels will be clamped to the calculated alpha. + */ + static sk_sp Arithmetic(float k1, float k2, float k3, float k4, bool enforcePremul); + +private: + SkBlenders() = delete; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkBlurMaskFilter.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkBlurMaskFilter.h new file mode 100644 index 0000000000..1b9319869e --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkBlurMaskFilter.h @@ -0,0 +1,35 @@ +/* + * 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 SkBlurMaskFilter_DEFINED +#define SkBlurMaskFilter_DEFINED + +// we include this since our callers will need to at least be able to ref/unref +#include "include/core/SkBlurTypes.h" +#include "include/core/SkMaskFilter.h" +#include "include/core/SkRect.h" +#include "include/core/SkScalar.h" + +class SkRRect; + +class SK_API SkBlurMaskFilter { +public: +#ifdef SK_SUPPORT_LEGACY_EMBOSSMASKFILTER + /** Create an emboss maskfilter + @param blurSigma standard deviation of the Gaussian blur to apply + before applying lighting (e.g. 3) + @param direction array of 3 scalars [x, y, z] specifying the direction of the light source + @param ambient 0...1 amount of ambient light + @param specular coefficient for specular highlights (e.g. 8) + @return the emboss maskfilter + */ + static sk_sp MakeEmboss(SkScalar blurSigma, const SkScalar direction[3], + SkScalar ambient, SkScalar specular); +#endif +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkColorMatrix.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkColorMatrix.h new file mode 100644 index 0000000000..5092278f0d --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkColorMatrix.h @@ -0,0 +1,57 @@ +/* + * 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 SkColorMatrix_DEFINED +#define SkColorMatrix_DEFINED + +#include "include/core/SkTypes.h" + +#include +#include + +enum SkYUVColorSpace : int; + +class SK_API SkColorMatrix { +public: + constexpr SkColorMatrix() : SkColorMatrix(1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0) {} + + constexpr SkColorMatrix(float m00, float m01, float m02, float m03, float m04, + float m10, float m11, float m12, float m13, float m14, + float m20, float m21, float m22, float m23, float m24, + float m30, float m31, float m32, float m33, float m34) + : fMat { m00, m01, m02, m03, m04, + m10, m11, m12, m13, m14, + m20, m21, m22, m23, m24, + m30, m31, m32, m33, m34 } {} + + static SkColorMatrix RGBtoYUV(SkYUVColorSpace); + static SkColorMatrix YUVtoRGB(SkYUVColorSpace); + + void setIdentity(); + void setScale(float rScale, float gScale, float bScale, float aScale = 1.0f); + + void postTranslate(float dr, float dg, float db, float da); + + void setConcat(const SkColorMatrix& a, const SkColorMatrix& b); + void preConcat(const SkColorMatrix& mat) { this->setConcat(*this, mat); } + void postConcat(const SkColorMatrix& mat) { this->setConcat(mat, *this); } + + void setSaturation(float sat); + + void setRowMajor(const float src[20]) { std::copy_n(src, 20, fMat.begin()); } + void getRowMajor(float dst[20]) const { std::copy_n(fMat.begin(), 20, dst); } + +private: + std::array fMat; + + friend class SkColorFilters; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkColorMatrixFilter.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkColorMatrixFilter.h new file mode 100644 index 0000000000..3e5337b0cf --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkColorMatrixFilter.h @@ -0,0 +1,22 @@ +/* + * 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 SkColorMatrixFilter_DEFINED +#define SkColorMatrixFilter_DEFINED + +#include "include/core/SkColorFilter.h" + +// (DEPRECATED) This factory function is deprecated. Please use the one in +// SkColorFilters (i.e., Lighting). +class SK_API SkColorMatrixFilter : public SkColorFilter { +public: + static sk_sp MakeLightingFilter(SkColor mul, SkColor add) { + return SkColorFilters::Lighting(mul, add); + } +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkCornerPathEffect.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkCornerPathEffect.h new file mode 100644 index 0000000000..7f7e7159f3 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkCornerPathEffect.h @@ -0,0 +1,32 @@ +/* + * 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 SkCornerPathEffect_DEFINED +#define SkCornerPathEffect_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" + +class SkPathEffect; + +/** \class SkCornerPathEffect + + SkCornerPathEffect is a subclass of SkPathEffect that can turn sharp corners + into various treatments (e.g. rounded corners) +*/ +class SK_API SkCornerPathEffect { +public: + /** radius must be > 0 to have an effect. It specifies the distance from each corner + that should be "rounded". + */ + static sk_sp Make(SkScalar radius); + + static void RegisterFlattenables(); +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkDashPathEffect.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkDashPathEffect.h new file mode 100644 index 0000000000..f30064aa94 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkDashPathEffect.h @@ -0,0 +1,43 @@ +/* + * 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 SkDashPathEffect_DEFINED +#define SkDashPathEffect_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" + +class SkPathEffect; + +class SK_API SkDashPathEffect { +public: + /** intervals: array containing an even number of entries (>=2), with + the even indices specifying the length of "on" intervals, and the odd + indices specifying the length of "off" intervals. This array will be + copied in Make, and can be disposed of freely after. + count: number of elements in the intervals array + phase: offset into the intervals array (mod the sum of all of the + intervals). + + For example: if intervals[] = {10, 20}, count = 2, and phase = 25, + this will set up a dashed path like so: + 5 pixels off + 10 pixels on + 20 pixels off + 10 pixels on + 20 pixels off + ... + A phase of -5, 25, 55, 85, etc. would all result in the same path, + because the sum of all the intervals is 30. + + Note: only affects stroked paths. + */ + static sk_sp Make(const SkScalar intervals[], int count, SkScalar phase); +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkDiscretePathEffect.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkDiscretePathEffect.h new file mode 100644 index 0000000000..6054cbdc99 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkDiscretePathEffect.h @@ -0,0 +1,37 @@ +/* + * 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 SkDiscretePathEffect_DEFINED +#define SkDiscretePathEffect_DEFINED + +#include "include/core/SkPathEffect.h" + +/** \class SkDiscretePathEffect + + This path effect chops a path into discrete segments, and randomly displaces them. +*/ +class SK_API SkDiscretePathEffect { +public: + /** Break the path into segments of segLength length, and randomly move the endpoints + away from the original path by a maximum of deviation. + Note: works on filled or framed paths + + @param seedAssist This is a caller-supplied seedAssist that modifies + the seed value that is used to randomize the path + segments' endpoints. If not supplied it defaults to 0, + in which case filtering a path multiple times will + result in the same set of segments (this is useful for + testing). If a caller does not want this behaviour + they can pass in a different seedAssist to get a + different set of path segments. + */ + static sk_sp Make(SkScalar segLength, SkScalar dev, uint32_t seedAssist = 0); + + static void RegisterFlattenables(); +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkGradientShader.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkGradientShader.h new file mode 100644 index 0000000000..d725c2d8b1 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkGradientShader.h @@ -0,0 +1,354 @@ +/* + * 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 SkGradientShader_DEFINED +#define SkGradientShader_DEFINED + +#include "include/core/SkColor.h" +#include "include/core/SkColorSpace.h" +#include "include/core/SkPoint.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" +#include "include/core/SkShader.h" // IWYU pragma: keep +#include "include/core/SkTileMode.h" +#include "include/private/base/SkAPI.h" + +#include +#include + +class SkMatrix; + +/** \class SkGradientShader + + SkGradientShader hosts factories for creating subclasses of SkShader that + render linear and radial gradients. In general, degenerate cases should not + produce surprising results, but there are several types of degeneracies: + + * A linear gradient made from the same two points. + * A radial gradient with a radius of zero. + * A sweep gradient where the start and end angle are the same. + * A two point conical gradient where the two centers and the two radii are + the same. + + For any degenerate gradient with a decal tile mode, it will draw empty since the interpolating + region is zero area and the outer region is discarded by the decal mode. + + For any degenerate gradient with a repeat or mirror tile mode, it will draw a solid color that + is the average gradient color, since infinitely many repetitions of the gradients will fill the + shape. + + For a clamped gradient, every type is well-defined at the limit except for linear gradients. The + radial gradient with zero radius becomes the last color. The sweep gradient draws the sector + from 0 to the provided angle with the first color, with a hardstop switching to the last color. + When the provided angle is 0, this is just the solid last color again. Similarly, the two point + conical gradient becomes a circle filled with the first color, sized to the provided radius, + with a hardstop switching to the last color. When the two radii are both zero, this is just the + solid last color. + + As a linear gradient approaches the degenerate case, its shader will approach the appearance of + two half planes, each filled by the first and last colors of the gradient. The planes will be + oriented perpendicular to the vector between the two defining points of the gradient. However, + once they become the same point, Skia cannot reconstruct what that expected orientation is. To + provide a stable and predictable color in this case, Skia just uses the last color as a solid + fill to be similar to many of the other degenerate gradients' behaviors in clamp mode. +*/ +class SK_API SkGradientShader { +public: + enum Flags { + /** By default gradients will interpolate their colors in unpremul space + * and then premultiply each of the results. By setting this flag, the + * gradients will premultiply their colors first, and then interpolate + * between them. + * example: https://fiddle.skia.org/c/@GradientShader_MakeLinear + */ + kInterpolateColorsInPremul_Flag = 1 << 0, + }; + + struct Interpolation { + enum class InPremul : bool { kNo = false, kYes = true }; + + enum class ColorSpace : uint8_t { + // Default Skia behavior: interpolate in the color space of the destination surface + kDestination, + + // https://www.w3.org/TR/css-color-4/#interpolation-space + kSRGBLinear, + kLab, + kOKLab, + // This is the same as kOKLab, except it has a simplified version of the CSS gamut + // mapping algorithm (https://www.w3.org/TR/css-color-4/#css-gamut-mapping) + // into Rec2020 space applied to it. + // Warning: This space is experimental and should not be used in production. + kOKLabGamutMap, + kLCH, + kOKLCH, + // This is the same as kOKLCH, except it has the same gamut mapping applied to it + // as kOKLabGamutMap does. + // Warning: This space is experimental and should not be used in production. + kOKLCHGamutMap, + kSRGB, + kHSL, + kHWB, + + kLastColorSpace = kHWB, + }; + static constexpr int kColorSpaceCount = static_cast(ColorSpace::kLastColorSpace) + 1; + + enum class HueMethod : uint8_t { + // https://www.w3.org/TR/css-color-4/#hue-interpolation + kShorter, + kLonger, + kIncreasing, + kDecreasing, + + kLastHueMethod = kDecreasing, + }; + static constexpr int kHueMethodCount = static_cast(HueMethod::kLastHueMethod) + 1; + + InPremul fInPremul = InPremul::kNo; + ColorSpace fColorSpace = ColorSpace::kDestination; + HueMethod fHueMethod = HueMethod::kShorter; // Only relevant for LCH, OKLCH, HSL, or HWB + + static Interpolation FromFlags(uint32_t flags) { + return {flags & kInterpolateColorsInPremul_Flag ? InPremul::kYes : InPremul::kNo, + ColorSpace::kDestination, + HueMethod::kShorter}; + } + }; + + /** Returns a shader that generates a linear gradient between the two specified points. +

+ @param pts The start and end points for the gradient. + @param colors The array[count] of colors, to be distributed between the two points + @param pos May be NULL. array[count] of SkScalars, or NULL, of the relative position of + each corresponding color in the colors array. If this is NULL, + the the colors are distributed evenly between the start and end point. + If this is not null, the values must lie between 0.0 and 1.0, and be + strictly increasing. If the first value is not 0.0, then an additional + color stop is added at position 0.0, with the same color as colors[0]. + If the the last value is not 1.0, then an additional color stop is added + at position 1.0, with the same color as colors[count - 1]. + @param count Must be >=2. The number of colors (and pos if not NULL) entries. + @param mode The tiling mode + + example: https://fiddle.skia.org/c/@GradientShader_MakeLinear + */ + static sk_sp MakeLinear(const SkPoint pts[2], + const SkColor colors[], const SkScalar pos[], int count, + SkTileMode mode, + uint32_t flags = 0, const SkMatrix* localMatrix = nullptr); + + /** Returns a shader that generates a linear gradient between the two specified points. +

+ @param pts The start and end points for the gradient. + @param colors The array[count] of colors, to be distributed between the two points + @param pos May be NULL. array[count] of SkScalars, or NULL, of the relative position of + each corresponding color in the colors array. If this is NULL, + the the colors are distributed evenly between the start and end point. + If this is not null, the values must lie between 0.0 and 1.0, and be + strictly increasing. If the first value is not 0.0, then an additional + color stop is added at position 0.0, with the same color as colors[0]. + If the the last value is not 1.0, then an additional color stop is added + at position 1.0, with the same color as colors[count - 1]. + @param count Must be >=2. The number of colors (and pos if not NULL) entries. + @param mode The tiling mode + + example: https://fiddle.skia.org/c/@GradientShader_MakeLinear + */ + static sk_sp MakeLinear(const SkPoint pts[2], + const SkColor4f colors[], sk_sp colorSpace, + const SkScalar pos[], int count, SkTileMode mode, + const Interpolation& interpolation, + const SkMatrix* localMatrix); + static sk_sp MakeLinear(const SkPoint pts[2], + const SkColor4f colors[], sk_sp colorSpace, + const SkScalar pos[], int count, SkTileMode mode, + uint32_t flags = 0, const SkMatrix* localMatrix = nullptr) { + return MakeLinear(pts, colors, std::move(colorSpace), pos, count, mode, + Interpolation::FromFlags(flags), localMatrix); + } + + /** Returns a shader that generates a radial gradient given the center and radius. +

+ @param center The center of the circle for this gradient + @param radius Must be positive. The radius of the circle for this gradient + @param colors The array[count] of colors, to be distributed between the center and edge of the circle + @param pos May be NULL. The array[count] of SkScalars, or NULL, of the relative position of + each corresponding color in the colors array. If this is NULL, + the the colors are distributed evenly between the center and edge of the circle. + If this is not null, the values must lie between 0.0 and 1.0, and be + strictly increasing. If the first value is not 0.0, then an additional + color stop is added at position 0.0, with the same color as colors[0]. + If the the last value is not 1.0, then an additional color stop is added + at position 1.0, with the same color as colors[count - 1]. + @param count Must be >= 2. The number of colors (and pos if not NULL) entries + @param mode The tiling mode + */ + static sk_sp MakeRadial(const SkPoint& center, SkScalar radius, + const SkColor colors[], const SkScalar pos[], int count, + SkTileMode mode, + uint32_t flags = 0, const SkMatrix* localMatrix = nullptr); + + /** Returns a shader that generates a radial gradient given the center and radius. +

+ @param center The center of the circle for this gradient + @param radius Must be positive. The radius of the circle for this gradient + @param colors The array[count] of colors, to be distributed between the center and edge of the circle + @param pos May be NULL. The array[count] of SkScalars, or NULL, of the relative position of + each corresponding color in the colors array. If this is NULL, + the the colors are distributed evenly between the center and edge of the circle. + If this is not null, the values must lie between 0.0 and 1.0, and be + strictly increasing. If the first value is not 0.0, then an additional + color stop is added at position 0.0, with the same color as colors[0]. + If the the last value is not 1.0, then an additional color stop is added + at position 1.0, with the same color as colors[count - 1]. + @param count Must be >= 2. The number of colors (and pos if not NULL) entries + @param mode The tiling mode + */ + static sk_sp MakeRadial(const SkPoint& center, SkScalar radius, + const SkColor4f colors[], sk_sp colorSpace, + const SkScalar pos[], int count, SkTileMode mode, + const Interpolation& interpolation, + const SkMatrix* localMatrix); + static sk_sp MakeRadial(const SkPoint& center, SkScalar radius, + const SkColor4f colors[], sk_sp colorSpace, + const SkScalar pos[], int count, SkTileMode mode, + uint32_t flags = 0, const SkMatrix* localMatrix = nullptr) { + return MakeRadial(center, radius, colors, std::move(colorSpace), pos, count, mode, + Interpolation::FromFlags(flags), localMatrix); + } + + /** + * Returns a shader that generates a conical gradient given two circles, or + * returns NULL if the inputs are invalid. The gradient interprets the + * two circles according to the following HTML spec. + * http://dev.w3.org/html5/2dcontext/#dom-context-2d-createradialgradient + */ + static sk_sp MakeTwoPointConical(const SkPoint& start, SkScalar startRadius, + const SkPoint& end, SkScalar endRadius, + const SkColor colors[], const SkScalar pos[], + int count, SkTileMode mode, + uint32_t flags = 0, + const SkMatrix* localMatrix = nullptr); + + /** + * Returns a shader that generates a conical gradient given two circles, or + * returns NULL if the inputs are invalid. The gradient interprets the + * two circles according to the following HTML spec. + * http://dev.w3.org/html5/2dcontext/#dom-context-2d-createradialgradient + */ + static sk_sp MakeTwoPointConical(const SkPoint& start, SkScalar startRadius, + const SkPoint& end, SkScalar endRadius, + const SkColor4f colors[], + sk_sp colorSpace, const SkScalar pos[], + int count, SkTileMode mode, + const Interpolation& interpolation, + const SkMatrix* localMatrix); + static sk_sp MakeTwoPointConical(const SkPoint& start, SkScalar startRadius, + const SkPoint& end, SkScalar endRadius, + const SkColor4f colors[], + sk_sp colorSpace, const SkScalar pos[], + int count, SkTileMode mode, + uint32_t flags = 0, + const SkMatrix* localMatrix = nullptr) { + return MakeTwoPointConical(start, startRadius, end, endRadius, colors, + std::move(colorSpace), pos, count, mode, + Interpolation::FromFlags(flags), localMatrix); + } + + /** Returns a shader that generates a sweep gradient given a center. + + The shader accepts negative angles and angles larger than 360, draws + between 0 and 360 degrees, similar to the CSS conic-gradient + semantics. 0 degrees means horizontal positive x axis. The start angle + must be less than the end angle, otherwise a null pointer is + returned. If color stops do not contain 0 and 1 but are within this + range, the respective outer color stop is repeated for 0 and 1. Color + stops less than 0 are clamped to 0, and greater than 1 are clamped to 1. +

+ @param cx The X coordinate of the center of the sweep + @param cx The Y coordinate of the center of the sweep + @param colors The array[count] of colors, to be distributed around the center, within + the gradient angle range. + @param pos May be NULL. The array[count] of SkScalars, or NULL, of the relative + position of each corresponding color in the colors array. If this is + NULL, then the colors are distributed evenly within the angular range. + If this is not null, the values must lie between 0.0 and 1.0, and be + strictly increasing. If the first value is not 0.0, then an additional + color stop is added at position 0.0, with the same color as colors[0]. + If the the last value is not 1.0, then an additional color stop is added + at position 1.0, with the same color as colors[count - 1]. + @param count Must be >= 2. The number of colors (and pos if not NULL) entries + @param mode Tiling mode: controls drawing outside of the gradient angular range. + @param startAngle Start of the angular range, corresponding to pos == 0. + @param endAngle End of the angular range, corresponding to pos == 1. + */ + static sk_sp MakeSweep(SkScalar cx, SkScalar cy, + const SkColor colors[], const SkScalar pos[], int count, + SkTileMode mode, + SkScalar startAngle, SkScalar endAngle, + uint32_t flags, const SkMatrix* localMatrix); + static sk_sp MakeSweep(SkScalar cx, SkScalar cy, + const SkColor colors[], const SkScalar pos[], int count, + uint32_t flags = 0, const SkMatrix* localMatrix = nullptr) { + return MakeSweep(cx, cy, colors, pos, count, SkTileMode::kClamp, 0, 360, flags, + localMatrix); + } + + /** Returns a shader that generates a sweep gradient given a center. + + The shader accepts negative angles and angles larger than 360, draws + between 0 and 360 degrees, similar to the CSS conic-gradient + semantics. 0 degrees means horizontal positive x axis. The start angle + must be less than the end angle, otherwise a null pointer is + returned. If color stops do not contain 0 and 1 but are within this + range, the respective outer color stop is repeated for 0 and 1. Color + stops less than 0 are clamped to 0, and greater than 1 are clamped to 1. +

+ @param cx The X coordinate of the center of the sweep + @param cx The Y coordinate of the center of the sweep + @param colors The array[count] of colors, to be distributed around the center, within + the gradient angle range. + @param pos May be NULL. The array[count] of SkScalars, or NULL, of the relative + position of each corresponding color in the colors array. If this is + NULL, then the colors are distributed evenly within the angular range. + If this is not null, the values must lie between 0.0 and 1.0, and be + strictly increasing. If the first value is not 0.0, then an additional + color stop is added at position 0.0, with the same color as colors[0]. + If the the last value is not 1.0, then an additional color stop is added + at position 1.0, with the same color as colors[count - 1]. + @param count Must be >= 2. The number of colors (and pos if not NULL) entries + @param mode Tiling mode: controls drawing outside of the gradient angular range. + @param startAngle Start of the angular range, corresponding to pos == 0. + @param endAngle End of the angular range, corresponding to pos == 1. + */ + static sk_sp MakeSweep(SkScalar cx, SkScalar cy, + const SkColor4f colors[], sk_sp colorSpace, + const SkScalar pos[], int count, + SkTileMode mode, + SkScalar startAngle, SkScalar endAngle, + const Interpolation& interpolation, + const SkMatrix* localMatrix); + static sk_sp MakeSweep(SkScalar cx, SkScalar cy, + const SkColor4f colors[], sk_sp colorSpace, + const SkScalar pos[], int count, + SkTileMode mode, + SkScalar startAngle, SkScalar endAngle, + uint32_t flags, const SkMatrix* localMatrix) { + return MakeSweep(cx, cy, colors, std::move(colorSpace), pos, count, mode, startAngle, + endAngle, Interpolation::FromFlags(flags), localMatrix); + } + static sk_sp MakeSweep(SkScalar cx, SkScalar cy, + const SkColor4f colors[], sk_sp colorSpace, + const SkScalar pos[], int count, + uint32_t flags = 0, const SkMatrix* localMatrix = nullptr) { + return MakeSweep(cx, cy, colors, std::move(colorSpace), pos, count, SkTileMode::kClamp, + 0, 360, flags, localMatrix); + } +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkHighContrastFilter.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkHighContrastFilter.h new file mode 100644 index 0000000000..6badf8486e --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkHighContrastFilter.h @@ -0,0 +1,84 @@ +/* +* 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 SkHighContrastFilter_DEFINED +#define SkHighContrastFilter_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" + +class SkColorFilter; + +/** + * Configuration struct for SkHighContrastFilter. + * + * Provides transformations to improve contrast for users with low vision. + */ +struct SkHighContrastConfig { + enum class InvertStyle { + kNoInvert, + kInvertBrightness, + kInvertLightness, + + kLast = kInvertLightness + }; + + SkHighContrastConfig() { + fGrayscale = false; + fInvertStyle = InvertStyle::kNoInvert; + fContrast = 0.0f; + } + + SkHighContrastConfig(bool grayscale, + InvertStyle invertStyle, + SkScalar contrast) + : fGrayscale(grayscale) + , fInvertStyle(invertStyle) + , fContrast(contrast) {} + + // Returns true if all of the fields are set within the valid range. + bool isValid() const { + return fInvertStyle >= InvertStyle::kNoInvert && + fInvertStyle <= InvertStyle::kInvertLightness && + fContrast >= -1.0 && + fContrast <= 1.0; + } + + // If true, the color will be converted to grayscale. + bool fGrayscale; + + // Whether to invert brightness, lightness, or neither. + InvertStyle fInvertStyle; + + // After grayscale and inverting, the contrast can be adjusted linearly. + // The valid range is -1.0 through 1.0, where 0.0 is no adjustment. + SkScalar fContrast; +}; + +/** + * Color filter that provides transformations to improve contrast + * for users with low vision. + * + * Applies the following transformations in this order. Each of these + * can be configured using SkHighContrastConfig. + * + * - Conversion to grayscale + * - Color inversion (either in RGB or HSL space) + * - Increasing the resulting contrast. + * + * Calling SkHighContrastFilter::Make will return nullptr if the config is + * not valid, e.g. if you try to call it with a contrast outside the range of + * -1.0 to 1.0. + */ + +struct SK_API SkHighContrastFilter { + // Returns the filter, or nullptr if the config is invalid. + static sk_sp Make(const SkHighContrastConfig& config); +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkImageFilters.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkImageFilters.h new file mode 100644 index 0000000000..926896f9ed --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkImageFilters.h @@ -0,0 +1,615 @@ +/* + * 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 SkImageFilters_DEFINED +#define SkImageFilters_DEFINED + +#include "include/core/SkColor.h" +#include "include/core/SkImage.h" +#include "include/core/SkImageFilter.h" +#include "include/core/SkPicture.h" +#include "include/core/SkRect.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" +#include "include/core/SkShader.h" +#include "include/core/SkTileMode.h" +#include "include/core/SkTypes.h" + +#include +#include +#include +#include + +class SkBlender; +class SkColorFilter; +class SkMatrix; +class SkRuntimeShaderBuilder; +enum class SkBlendMode; +struct SkIPoint; +struct SkISize; +struct SkPoint3; +struct SkSamplingOptions; + +// A set of factory functions providing useful SkImageFilter effects. For image filters that take an +// input filter, providing nullptr means it will automatically use the dynamic source image. This +// source depends on how the filter is applied, but is either the contents of a saved layer when +// drawing with SkCanvas, or an explicit SkImage if using one of the SkImages::MakeWithFilter +// factories. +class SK_API SkImageFilters { +public: + // This is just a convenience type to allow passing SkIRects, SkRects, and optional pointers + // to those types as a crop rect for the image filter factories. It's not intended to be used + // directly. + struct CropRect : public std::optional { + CropRect() {} + // Intentionally not explicit so callers don't have to use this type but can use SkIRect or + // SkRect as desired. + CropRect(const SkIRect& crop) : std::optional(SkRect::Make(crop)) {} + CropRect(const SkRect& crop) : std::optional(crop) {} + CropRect(const std::optional& crop) : std::optional(crop) {} + CropRect(const std::nullopt_t&) : std::optional() {} + + // Backwards compatibility for when the APIs used to explicitly accept "const SkRect*" + CropRect(std::nullptr_t) {} + CropRect(const SkIRect* optionalCrop) { + if (optionalCrop) { + *this = SkRect::Make(*optionalCrop); + } + } + CropRect(const SkRect* optionalCrop) { + if (optionalCrop) { + *this = *optionalCrop; + } + } + + // std::optional doesn't define == when comparing to another optional... + bool operator==(const CropRect& o) const { + return this->has_value() == o.has_value() && + (!this->has_value() || this->value() == *o); + } + }; + + /** + * Create a filter that implements a custom blend mode. Each output pixel is the result of + * combining the corresponding background and foreground pixels using the 4 coefficients: + * k1 * foreground * background + k2 * foreground + k3 * background + k4 + * @param k1, k2, k3, k4 The four coefficients used to combine the foreground and background. + * @param enforcePMColor If true, the RGB channels will be clamped to the calculated alpha. + * @param background The background content, using the source bitmap when this is null. + * @param foreground The foreground content, using the source bitmap when this is null. + * @param cropRect Optional rectangle that crops the inputs and output. + */ + static sk_sp Arithmetic(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4, + bool enforcePMColor, sk_sp background, + sk_sp foreground, + const CropRect& cropRect = {}); + + /** + * This filter takes an SkBlendMode and uses it to composite the two filters together. + * @param mode The blend mode that defines the compositing operation + * @param background The Dst pixels used in blending, if null the source bitmap is used. + * @param foreground The Src pixels used in blending, if null the source bitmap is used. + * @cropRect Optional rectangle to crop input and output. + */ + static sk_sp Blend(SkBlendMode mode, sk_sp background, + sk_sp foreground = nullptr, + const CropRect& cropRect = {}); + + /** + * This filter takes an SkBlendMode and uses it to composite the two filters together. + * @param blender The blender that defines the compositing operation + * @param background The Dst pixels used in blending, if null the source bitmap is used. + * @param foreground The Src pixels used in blending, if null the source bitmap is used. + * @cropRect Optional rectangle to crop input and output. + */ + static sk_sp Blend(sk_sp blender, sk_sp background, + sk_sp foreground = nullptr, + const CropRect& cropRect = {}); + + /** + * Create a filter that blurs its input by the separate X and Y sigmas. The provided tile mode + * is used when the blur kernel goes outside the input image. + * @param sigmaX The Gaussian sigma value for blurring along the X axis. + * @param sigmaY The Gaussian sigma value for blurring along the Y axis. + * @param tileMode The tile mode applied at edges . + * TODO (michaelludwig) - kMirror is not supported yet + * @param input The input filter that is blurred, uses source bitmap if this is null. + * @param cropRect Optional rectangle that crops the input and output. + */ + static sk_sp Blur(SkScalar sigmaX, SkScalar sigmaY, SkTileMode tileMode, + sk_sp input, const CropRect& cropRect = {}); + // As above, but defaults to the decal tile mode. + static sk_sp Blur(SkScalar sigmaX, SkScalar sigmaY, sk_sp input, + const CropRect& cropRect = {}) { + return Blur(sigmaX, sigmaY, SkTileMode::kDecal, std::move(input), cropRect); + } + + /** + * Create a filter that applies the color filter to the input filter results. + * @param cf The color filter that transforms the input image. + * @param input The input filter, or uses the source bitmap if this is null. + * @param cropRect Optional rectangle that crops the input and output. + */ + static sk_sp ColorFilter(sk_sp cf, sk_sp input, + const CropRect& cropRect = {}); + + /** + * Create a filter that composes 'inner' with 'outer', such that the results of 'inner' are + * treated as the source bitmap passed to 'outer', i.e. result = outer(inner(source)). + * @param outer The outer filter that evaluates the results of inner. + * @param inner The inner filter that produces the input to outer. + */ + static sk_sp Compose(sk_sp outer, sk_sp inner); + + /** + * Create a filter that applies a crop to the result of the 'input' filter. Pixels within the + * crop rectangle are unmodified from what 'input' produced. Pixels outside of crop match the + * provided SkTileMode (defaulting to kDecal). + * + * NOTE: The optional CropRect argument for many of the factories is equivalent to creating the + * filter without a CropRect and then wrapping it in ::Crop(rect, kDecal). Explicitly adding + * Crop filters lets you control their tiling and use different geometry for the input and the + * output of another filter. + * + * @param rect The cropping geometry + * @param tileMode The tilemode applied to pixels *outside* of 'crop' + * @param input The input filter that is cropped, uses source image if this is null + */ + static sk_sp Crop(const SkRect& rect, + SkTileMode tileMode, + sk_sp input); + static sk_sp Crop(const SkRect& rect, sk_sp input) { + return Crop(rect, SkTileMode::kDecal, std::move(input)); + } + + /** + * Create a filter that moves each pixel in its color input based on an (x,y) vector encoded + * in its displacement input filter. Two color components of the displacement image are + * mapped into a vector as scale * (color[xChannel], color[yChannel]), where the channel + * selectors are one of R, G, B, or A. + * @param xChannelSelector RGBA channel that encodes the x displacement per pixel. + * @param yChannelSelector RGBA channel that encodes the y displacement per pixel. + * @param scale Scale applied to displacement extracted from image. + * @param displacement The filter defining the displacement image, or null to use source. + * @param color The filter providing the color pixels to be displaced. If null, + * it will use the source. + * @param cropRect Optional rectangle that crops the color input and output. + */ + static sk_sp DisplacementMap(SkColorChannel xChannelSelector, + SkColorChannel yChannelSelector, + SkScalar scale, sk_sp displacement, + sk_sp color, + const CropRect& cropRect = {}); + + /** + * Create a filter that draws a drop shadow under the input content. This filter produces an + * image that includes the inputs' content. + * @param dx The X offset of the shadow. + * @param dy The Y offset of the shadow. + * @param sigmaX The blur radius for the shadow, along the X axis. + * @param sigmaY The blur radius for the shadow, along the Y axis. + * @param color The color of the drop shadow. + * @param input The input filter, or will use the source bitmap if this is null. + * @param cropRect Optional rectangle that crops the input and output. + */ + static sk_sp DropShadow(SkScalar dx, SkScalar dy, + SkScalar sigmaX, SkScalar sigmaY, + SkColor color, sk_sp input, + const CropRect& cropRect = {}); + /** + * Create a filter that renders a drop shadow, in exactly the same manner as ::DropShadow, + * except that the resulting image does not include the input content. This allows the shadow + * and input to be composed by a filter DAG in a more flexible manner. + * @param dx The X offset of the shadow. + * @param dy The Y offset of the shadow. + * @param sigmaX The blur radius for the shadow, along the X axis. + * @param sigmaY The blur radius for the shadow, along the Y axis. + * @param color The color of the drop shadow. + * @param input The input filter, or will use the source bitmap if this is null. + * @param cropRect Optional rectangle that crops the input and output. + */ + static sk_sp DropShadowOnly(SkScalar dx, SkScalar dy, + SkScalar sigmaX, SkScalar sigmaY, + SkColor color, sk_sp input, + const CropRect& cropRect = {}); + + /** + * Create a filter that always produces transparent black. + */ + static sk_sp Empty(); + + /** + * Create a filter that draws the 'srcRect' portion of image into 'dstRect' using the given + * filter quality. Similar to SkCanvas::drawImageRect. The returned image filter evaluates + * to transparent black if 'image' is null. + * + * @param image The image that is output by the filter, subset by 'srcRect'. + * @param srcRect The source pixels sampled into 'dstRect' + * @param dstRect The local rectangle to draw the image into. + * @param sampling The sampling to use when drawing the image. + */ + static sk_sp Image(sk_sp image, const SkRect& srcRect, + const SkRect& dstRect, const SkSamplingOptions& sampling); + + /** + * Create a filter that draws the image using the given sampling. + * Similar to SkCanvas::drawImage. The returned image filter evaluates to transparent black if + * 'image' is null. + * + * @param image The image that is output by the filter. + * @param sampling The sampling to use when drawing the image. + */ + static sk_sp Image(sk_sp image, const SkSamplingOptions& sampling) { + if (image) { + SkRect r = SkRect::Make(image->bounds()); + return Image(std::move(image), r, r, sampling); + } else { + return nullptr; + } + } + + /** + * Create a filter that fills 'lensBounds' with a magnification of the input. + * + * @param lensBounds The outer bounds of the magnifier effect + * @param zoomAmount The amount of magnification applied to the input image + * @param inset The size or width of the fish-eye distortion around the magnified content + * @param sampling The SkSamplingOptions applied to the input image when magnified + * @param input The input filter that is magnified; if null the source bitmap is used + * @param cropRect Optional rectangle that crops the input and output. + */ + static sk_sp Magnifier(const SkRect& lensBounds, + SkScalar zoomAmount, + SkScalar inset, + const SkSamplingOptions& sampling, + sk_sp input, + const CropRect& cropRect = {}); + + /** + * Create a filter that applies an NxM image processing kernel to the input image. This can be + * used to produce effects such as sharpening, blurring, edge detection, etc. + * @param kernelSize The kernel size in pixels, in each dimension (N by M). + * @param kernel The image processing kernel. Must contain N * M elements, in row order. + * @param gain A scale factor applied to each pixel after convolution. This can be + * used to normalize the kernel, if it does not already sum to 1. + * @param bias A bias factor added to each pixel after convolution. + * @param kernelOffset An offset applied to each pixel coordinate before convolution. + * This can be used to center the kernel over the image + * (e.g., a 3x3 kernel should have an offset of {1, 1}). + * @param tileMode How accesses outside the image are treated. + * TODO (michaelludwig) - kMirror is not supported yet + * @param convolveAlpha If true, all channels are convolved. If false, only the RGB channels + * are convolved, and alpha is copied from the source image. + * @param input The input image filter, if null the source bitmap is used instead. + * @param cropRect Optional rectangle to which the output processing will be limited. + */ + static sk_sp MatrixConvolution(const SkISize& kernelSize, + const SkScalar kernel[], SkScalar gain, + SkScalar bias, const SkIPoint& kernelOffset, + SkTileMode tileMode, bool convolveAlpha, + sk_sp input, + const CropRect& cropRect = {}); + + /** + * Create a filter that transforms the input image by 'matrix'. This matrix transforms the + * local space, which means it effectively happens prior to any transformation coming from the + * SkCanvas initiating the filtering. + * @param matrix The matrix to apply to the original content. + * @param sampling How the image will be sampled when it is transformed + * @param input The image filter to transform, or null to use the source image. + */ + static sk_sp MatrixTransform(const SkMatrix& matrix, + const SkSamplingOptions& sampling, + sk_sp input); + + /** + * Create a filter that merges the 'count' filters together by drawing their results in order + * with src-over blending. + * @param filters The input filter array to merge, which must have 'count' elements. Any null + * filter pointers will use the source bitmap instead. + * @param count The number of input filters to be merged. + * @param cropRect Optional rectangle that crops all input filters and the output. + */ + static sk_sp Merge(sk_sp* const filters, int count, + const CropRect& cropRect = {}); + /** + * Create a filter that merges the results of the two filters together with src-over blending. + * @param first The first input filter, or the source bitmap if this is null. + * @param second The second input filter, or the source bitmap if this null. + * @param cropRect Optional rectangle that crops the inputs and output. + */ + static sk_sp Merge(sk_sp first, sk_sp second, + const CropRect& cropRect = {}) { + sk_sp array[] = { std::move(first), std::move(second) }; + return Merge(array, 2, cropRect); + } + + /** + * Create a filter that offsets the input filter by the given vector. + * @param dx The x offset in local space that the image is shifted. + * @param dy The y offset in local space that the image is shifted. + * @param input The input that will be moved, if null the source bitmap is used instead. + * @param cropRect Optional rectangle to crop the input and output. + */ + static sk_sp Offset(SkScalar dx, SkScalar dy, sk_sp input, + const CropRect& cropRect = {}); + + /** + * Create a filter that produces the SkPicture as its output, clipped to both 'targetRect' and + * the picture's internal cull rect. + * + * If 'pic' is null, the returned image filter produces transparent black. + * + * @param pic The picture that is drawn for the filter output. + * @param targetRect The drawing region for the picture. + */ + static sk_sp Picture(sk_sp pic, const SkRect& targetRect); + // As above, but uses SkPicture::cullRect for the drawing region. + static sk_sp Picture(sk_sp pic) { + SkRect target = pic ? pic->cullRect() : SkRect::MakeEmpty(); + return Picture(std::move(pic), target); + } + + /** + * Create a filter that fills the output with the per-pixel evaluation of the SkShader produced + * by the SkRuntimeShaderBuilder. The shader is defined in the image filter's local coordinate + * system, so it will automatically be affected by SkCanvas' transform. + * + * This variant assumes that the runtime shader samples 'childShaderName' with the same input + * coordinate passed to to shader. + * + * This requires a GPU backend or SkSL to be compiled in. + * + * @param builder The builder used to produce the runtime shader, that will in turn + * fill the result image + * @param childShaderName The name of the child shader defined in the builder that will be + * bound to the input param (or the source image if the input param + * is null). If empty, the builder can have exactly one child shader, + * which automatically binds the input param. + * @param input The image filter that will be provided as input to the runtime + * shader. If null the implicit source image is used instead + */ + static sk_sp RuntimeShader(const SkRuntimeShaderBuilder& builder, + std::string_view childShaderName, + sk_sp input) { + return RuntimeShader(builder, /*sampleRadius=*/0.f, childShaderName, std::move(input)); + } + + /** + * As above, but 'sampleRadius' defines the sampling radius of 'childShaderName' relative to + * the runtime shader produced by 'builder'. If greater than 0, the coordinate passed to + * childShader.eval() will be up to 'sampleRadius' away (maximum absolute offset in 'x' or 'y') + * from the coordinate passed into the runtime shader. + * + * This allows Skia to provide sampleable values for the image filter without worrying about + * boundary conditions. + * + * This requires a GPU backend or SkSL to be compiled in. + */ + static sk_sp RuntimeShader(const SkRuntimeShaderBuilder& builder, + SkScalar sampleRadius, + std::string_view childShaderName, + sk_sp input); + + /** + * Create a filter that fills the output with the per-pixel evaluation of the SkShader produced + * by the SkRuntimeShaderBuilder. The shader is defined in the image filter's local coordinate + * system, so it will automatically be affected by SkCanvas' transform. + * + * This requires a GPU backend or SkSL to be compiled in. + * + * @param builder The builder used to produce the runtime shader, that will in turn + * fill the result image + * @param childShaderNames The names of the child shaders defined in the builder that will be + * bound to the input params (or the source image if the input param + * is null). If any name is null, or appears more than once, factory + * fails and returns nullptr. + * @param inputs The image filters that will be provided as input to the runtime + * shader. If any are null, the implicit source image is used instead. + * @param inputCount How many entries are present in 'childShaderNames' and 'inputs'. + */ + static sk_sp RuntimeShader(const SkRuntimeShaderBuilder& builder, + std::string_view childShaderNames[], + const sk_sp inputs[], + int inputCount) { + return RuntimeShader(builder, /*maxSampleRadius=*/0.f, childShaderNames, + inputs, inputCount); + } + + /** + * As above, but 'maxSampleRadius' defines the sampling limit on coordinates provided to all + * child shaders. Like the single-child variant with a sample radius, this can be used to + * inform Skia that the runtime shader guarantees that all dynamic children (defined in + * childShaderNames) will be evaluated with coordinates at most 'maxSampleRadius' away from the + * coordinate provided to the runtime shader itself. + * + * This requires a GPU backend or SkSL to be compiled in. + */ + static sk_sp RuntimeShader(const SkRuntimeShaderBuilder& builder, + SkScalar maxSampleRadius, + std::string_view childShaderNames[], + const sk_sp inputs[], + int inputCount); + + enum class Dither : bool { + kNo = false, + kYes = true + }; + + /** + * Create a filter that fills the output with the per-pixel evaluation of the SkShader. The + * shader is defined in the image filter's local coordinate system, so will automatically + * be affected by SkCanvas' transform. + * + * Like Image() and Picture(), this is a leaf filter that can be used to introduce inputs to + * a complex filter graph, but should generally be combined with a filter that as at least + * one null input to use the implicit source image. + * + * Returns an image filter that evaluates to transparent black if 'shader' is null. + * + * @param shader The shader that fills the result image + */ + static sk_sp Shader(sk_sp shader, const CropRect& cropRect = {}) { + return Shader(std::move(shader), Dither::kNo, cropRect); + } + static sk_sp Shader(sk_sp shader, Dither dither, + const CropRect& cropRect = {}); + + /** + * Create a tile image filter. + * @param src Defines the pixels to tile + * @param dst Defines the pixel region that the tiles will be drawn to + * @param input The input that will be tiled, if null the source bitmap is used instead. + */ + static sk_sp Tile(const SkRect& src, const SkRect& dst, + sk_sp input); + + // Morphology filter effects + + /** + * Create a filter that dilates each input pixel's channel values to the max value within the + * given radii along the x and y axes. + * @param radiusX The distance to dilate along the x axis to either side of each pixel. + * @param radiusY The distance to dilate along the y axis to either side of each pixel. + * @param input The image filter that is dilated, using source bitmap if this is null. + * @param cropRect Optional rectangle that crops the input and output. + */ + static sk_sp Dilate(SkScalar radiusX, SkScalar radiusY, + sk_sp input, + const CropRect& cropRect = {}); + + /** + * Create a filter that erodes each input pixel's channel values to the minimum channel value + * within the given radii along the x and y axes. + * @param radiusX The distance to erode along the x axis to either side of each pixel. + * @param radiusY The distance to erode along the y axis to either side of each pixel. + * @param input The image filter that is eroded, using source bitmap if this is null. + * @param cropRect Optional rectangle that crops the input and output. + */ + static sk_sp Erode(SkScalar radiusX, SkScalar radiusY, + sk_sp input, + const CropRect& cropRect = {}); + + // Lighting filter effects + + /** + * Create a filter that calculates the diffuse illumination from a distant light source, + * interpreting the alpha channel of the input as the height profile of the surface (to + * approximate normal vectors). + * @param direction The direction to the distance light. + * @param lightColor The color of the diffuse light source. + * @param surfaceScale Scale factor to transform from alpha values to physical height. + * @param kd Diffuse reflectance coefficient. + * @param input The input filter that defines surface normals (as alpha), or uses the + * source bitmap when null. + * @param cropRect Optional rectangle that crops the input and output. + */ + static sk_sp DistantLitDiffuse(const SkPoint3& direction, SkColor lightColor, + SkScalar surfaceScale, SkScalar kd, + sk_sp input, + const CropRect& cropRect = {}); + /** + * Create a filter that calculates the diffuse illumination from a point light source, using + * alpha channel of the input as the height profile of the surface (to approximate normal + * vectors). + * @param location The location of the point light. + * @param lightColor The color of the diffuse light source. + * @param surfaceScale Scale factor to transform from alpha values to physical height. + * @param kd Diffuse reflectance coefficient. + * @param input The input filter that defines surface normals (as alpha), or uses the + * source bitmap when null. + * @param cropRect Optional rectangle that crops the input and output. + */ + static sk_sp PointLitDiffuse(const SkPoint3& location, SkColor lightColor, + SkScalar surfaceScale, SkScalar kd, + sk_sp input, + const CropRect& cropRect = {}); + /** + * Create a filter that calculates the diffuse illumination from a spot light source, using + * alpha channel of the input as the height profile of the surface (to approximate normal + * vectors). The spot light is restricted to be within 'cutoffAngle' of the vector between + * the location and target. + * @param location The location of the spot light. + * @param target The location that the spot light is point towards + * @param falloffExponent Exponential falloff parameter for illumination outside of cutoffAngle + * @param cutoffAngle Maximum angle from lighting direction that receives full light + * @param lightColor The color of the diffuse light source. + * @param surfaceScale Scale factor to transform from alpha values to physical height. + * @param kd Diffuse reflectance coefficient. + * @param input The input filter that defines surface normals (as alpha), or uses the + * source bitmap when null. + * @param cropRect Optional rectangle that crops the input and output. + */ + static sk_sp SpotLitDiffuse(const SkPoint3& location, const SkPoint3& target, + SkScalar falloffExponent, SkScalar cutoffAngle, + SkColor lightColor, SkScalar surfaceScale, + SkScalar kd, sk_sp input, + const CropRect& cropRect = {}); + + /** + * Create a filter that calculates the specular illumination from a distant light source, + * interpreting the alpha channel of the input as the height profile of the surface (to + * approximate normal vectors). + * @param direction The direction to the distance light. + * @param lightColor The color of the specular light source. + * @param surfaceScale Scale factor to transform from alpha values to physical height. + * @param ks Specular reflectance coefficient. + * @param shininess The specular exponent determining how shiny the surface is. + * @param input The input filter that defines surface normals (as alpha), or uses the + * source bitmap when null. + * @param cropRect Optional rectangle that crops the input and output. + */ + static sk_sp DistantLitSpecular(const SkPoint3& direction, SkColor lightColor, + SkScalar surfaceScale, SkScalar ks, + SkScalar shininess, sk_sp input, + const CropRect& cropRect = {}); + /** + * Create a filter that calculates the specular illumination from a point light source, using + * alpha channel of the input as the height profile of the surface (to approximate normal + * vectors). + * @param location The location of the point light. + * @param lightColor The color of the specular light source. + * @param surfaceScale Scale factor to transform from alpha values to physical height. + * @param ks Specular reflectance coefficient. + * @param shininess The specular exponent determining how shiny the surface is. + * @param input The input filter that defines surface normals (as alpha), or uses the + * source bitmap when null. + * @param cropRect Optional rectangle that crops the input and output. + */ + static sk_sp PointLitSpecular(const SkPoint3& location, SkColor lightColor, + SkScalar surfaceScale, SkScalar ks, + SkScalar shininess, sk_sp input, + const CropRect& cropRect = {}); + /** + * Create a filter that calculates the specular illumination from a spot light source, using + * alpha channel of the input as the height profile of the surface (to approximate normal + * vectors). The spot light is restricted to be within 'cutoffAngle' of the vector between + * the location and target. + * @param location The location of the spot light. + * @param target The location that the spot light is point towards + * @param falloffExponent Exponential falloff parameter for illumination outside of cutoffAngle + * @param cutoffAngle Maximum angle from lighting direction that receives full light + * @param lightColor The color of the specular light source. + * @param surfaceScale Scale factor to transform from alpha values to physical height. + * @param ks Specular reflectance coefficient. + * @param shininess The specular exponent determining how shiny the surface is. + * @param input The input filter that defines surface normals (as alpha), or uses the + * source bitmap when null. + * @param cropRect Optional rectangle that crops the input and output. + */ + static sk_sp SpotLitSpecular(const SkPoint3& location, const SkPoint3& target, + SkScalar falloffExponent, SkScalar cutoffAngle, + SkColor lightColor, SkScalar surfaceScale, + SkScalar ks, SkScalar shininess, + sk_sp input, + const CropRect& cropRect = {}); + +private: + SkImageFilters() = delete; +}; + +#endif // SkImageFilters_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkLumaColorFilter.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkLumaColorFilter.h new file mode 100644 index 0000000000..41a9a45f3f --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkLumaColorFilter.h @@ -0,0 +1,37 @@ +/* + * 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 SkLumaColorFilter_DEFINED +#define SkLumaColorFilter_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" + +class SkColorFilter; + +/** + * SkLumaColorFilter multiplies the luma of its input into the alpha channel, + * and sets the red, green, and blue channels to zero. + * + * SkLumaColorFilter(r,g,b,a) = {0,0,0, a * luma(r,g,b)} + * + * This is similar to a luminanceToAlpha feColorMatrix, + * but note how this filter folds in the previous alpha, + * something an feColorMatrix cannot do. + * + * feColorMatrix(luminanceToAlpha; r,g,b,a) = {0,0,0, luma(r,g,b)} + * + * (Despite its name, an feColorMatrix using luminanceToAlpha does + * actually compute luma, a dot-product of gamma-encoded color channels, + * not luminance, a dot-product of linear color channels. So at least + * SkLumaColorFilter and feColorMatrix+luminanceToAlpha agree there.) + */ +struct SK_API SkLumaColorFilter { + static sk_sp Make(); +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkOverdrawColorFilter.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkOverdrawColorFilter.h new file mode 100644 index 0000000000..5f1642483a --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkOverdrawColorFilter.h @@ -0,0 +1,32 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "include/core/SkColor.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" + +class SkColorFilter; + +#ifndef SkOverdrawColorFilter_DEFINED +#define SkOverdrawColorFilter_DEFINED + +/** + * Uses the value in the src alpha channel to set the dst pixel. + * 0 -> colors[0] + * 1 -> colors[1] + * ... + * 5 (or larger) -> colors[5] + * + */ +class SK_API SkOverdrawColorFilter { +public: + static constexpr int kNumColors = 6; + + static sk_sp MakeWithSkColors(const SkColor[kNumColors]); +}; + +#endif // SkOverdrawColorFilter_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkPerlinNoiseShader.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkPerlinNoiseShader.h new file mode 100644 index 0000000000..7ef2f1fc50 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkPerlinNoiseShader.h @@ -0,0 +1,53 @@ +/* + * 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 SkPerlinNoiseShader_DEFINED +#define SkPerlinNoiseShader_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" +#include "include/core/SkShader.h" // IWYU pragma: keep +#include "include/private/base/SkAPI.h" + +struct SkISize; + +/** \class SkPerlinNoiseShader + + SkPerlinNoiseShader creates an image using the Perlin turbulence function. + + It can produce tileable noise if asked to stitch tiles and provided a tile size. + In order to fill a large area with repeating noise, set the stitchTiles flag to + true, and render exactly a single tile of noise. Without this flag, the result + will contain visible seams between tiles. + + The algorithm used is described here : + http://www.w3.org/TR/SVG/filters.html#feTurbulenceElement +*/ +namespace SkShaders { +/** + * This will construct Perlin noise of the given type (Fractal Noise or Turbulence). + * + * Both base frequencies (X and Y) have a usual range of (0..1) and must be non-negative. + * + * The number of octaves provided should be fairly small, with a limit of 255 enforced. + * Each octave doubles the frequency, so 10 octaves would produce noise from + * baseFrequency * 1, * 2, * 4, ..., * 512, which quickly yields insignificantly small + * periods and resembles regular unstructured noise rather than Perlin noise. + * + * If tileSize isn't NULL or an empty size, the tileSize parameter will be used to modify + * the frequencies so that the noise will be tileable for the given tile size. If tileSize + * is NULL or an empty size, the frequencies will be used as is without modification. + */ +SK_API sk_sp MakeFractalNoise(SkScalar baseFrequencyX, SkScalar baseFrequencyY, + int numOctaves, SkScalar seed, + const SkISize* tileSize = nullptr); +SK_API sk_sp MakeTurbulence(SkScalar baseFrequencyX, SkScalar baseFrequencyY, + int numOctaves, SkScalar seed, + const SkISize* tileSize = nullptr); +} // namespace SkShaders + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkRuntimeEffect.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkRuntimeEffect.h new file mode 100644 index 0000000000..d26e64bb40 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkRuntimeEffect.h @@ -0,0 +1,517 @@ +/* + * 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 SkRuntimeEffect_DEFINED +#define SkRuntimeEffect_DEFINED + +#include "include/core/SkBlender.h" // IWYU pragma: keep +#include "include/core/SkColorFilter.h" // IWYU pragma: keep +#include "include/core/SkData.h" +#include "include/core/SkFlattenable.h" +#include "include/core/SkMatrix.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkShader.h" +#include "include/core/SkSpan.h" +#include "include/core/SkString.h" +#include "include/core/SkTypes.h" +#include "include/private/SkSLSampleUsage.h" +#include "include/private/base/SkOnce.h" +#include "include/private/base/SkTemplates.h" +#include "include/private/base/SkTo.h" +#include "include/private/base/SkTypeTraits.h" +#include "include/sksl/SkSLDebugTrace.h" +#include "include/sksl/SkSLVersion.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct SkIPoint; + +namespace SkSL { +class DebugTracePriv; +class FunctionDefinition; +struct Program; +enum class ProgramKind : int8_t; +struct ProgramSettings; +} // namespace SkSL + +namespace SkSL::RP { +class Program; +} + +/* + * SkRuntimeEffect supports creating custom SkShader and SkColorFilter objects using Skia's SkSL + * shading language. + * + * NOTE: This API is experimental and subject to change. + */ +class SK_API SkRuntimeEffect : public SkRefCnt { +public: + // Reflected description of a uniform variable in the effect's SkSL + struct SK_API Uniform { + enum class Type { + kFloat, + kFloat2, + kFloat3, + kFloat4, + kFloat2x2, + kFloat3x3, + kFloat4x4, + kInt, + kInt2, + kInt3, + kInt4, + }; + + enum Flags { + // Uniform is declared as an array. 'count' contains array length. + kArray_Flag = 0x1, + + // Uniform is declared with layout(color). Colors should be supplied as unpremultiplied, + // extended-range (unclamped) sRGB (ie SkColor4f). The uniform will be automatically + // transformed to unpremultiplied extended-range working-space colors. + kColor_Flag = 0x2, + + // When used with SkMeshSpecification, indicates that the uniform is present in the + // vertex shader. Not used with SkRuntimeEffect. + kVertex_Flag = 0x4, + + // When used with SkMeshSpecification, indicates that the uniform is present in the + // fragment shader. Not used with SkRuntimeEffect. + kFragment_Flag = 0x8, + + // This flag indicates that the SkSL uniform uses a medium-precision type + // (i.e., `half` instead of `float`). + kHalfPrecision_Flag = 0x10, + }; + + std::string_view name; + size_t offset; + Type type; + int count; + uint32_t flags; + + bool isArray() const { return SkToBool(this->flags & kArray_Flag); } + bool isColor() const { return SkToBool(this->flags & kColor_Flag); } + size_t sizeInBytes() const; + }; + + // Reflected description of a uniform child (shader or colorFilter) in the effect's SkSL + enum class ChildType { + kShader, + kColorFilter, + kBlender, + }; + + struct Child { + std::string_view name; + ChildType type; + int index; + }; + + class Options { + public: + // For testing purposes, disables optimization and inlining. (Normally, Runtime Effects + // don't run the inliner directly, but they still get an inlining pass once they are + // painted.) + bool forceUnoptimized = false; + + private: + friend class SkRuntimeEffect; + friend class SkRuntimeEffectPriv; + + // This flag allows Runtime Effects to access Skia implementation details like sk_FragCoord + // and functions with private identifiers (e.g. $rgb_to_hsl). + bool allowPrivateAccess = false; + // When not 0, this field allows Skia to assign a stable key to a known runtime effect + uint32_t fStableKey = 0; + + // TODO(skia:11209) - Replace this with a promised SkCapabilities? + // This flag lifts the ES2 restrictions on Runtime Effects that are gated by the + // `strictES2Mode` check. Be aware that the software renderer and pipeline-stage effect are + // still largely ES3-unaware and can still fail or crash if post-ES2 features are used. + // This is only intended for use by tests and certain internally created effects. + SkSL::Version maxVersionAllowed = SkSL::Version::k100; + }; + + // If the effect is compiled successfully, `effect` will be non-null. + // Otherwise, `errorText` will contain the reason for failure. + struct Result { + sk_sp effect; + SkString errorText; + }; + + // MakeForColorFilter and MakeForShader verify that the SkSL code is valid for those stages of + // the Skia pipeline. In all of the signatures described below, color parameters and return + // values are flexible. They are listed as being 'vec4', but they can also be 'half4' or + // 'float4'. ('vec4' is an alias for 'float4'). + + // We can't use a default argument for `options` due to a bug in Clang. + // https://bugs.llvm.org/show_bug.cgi?id=36684 + + // Color filter SkSL requires an entry point that looks like: + // vec4 main(vec4 inColor) { ... } + static Result MakeForColorFilter(SkString sksl, const Options&); + static Result MakeForColorFilter(SkString sksl) { + return MakeForColorFilter(std::move(sksl), Options{}); + } + + // Shader SkSL requires an entry point that looks like: + // vec4 main(vec2 inCoords) { ... } + static Result MakeForShader(SkString sksl, const Options&); + static Result MakeForShader(SkString sksl) { + return MakeForShader(std::move(sksl), Options{}); + } + + // Blend SkSL requires an entry point that looks like: + // vec4 main(vec4 srcColor, vec4 dstColor) { ... } + static Result MakeForBlender(SkString sksl, const Options&); + static Result MakeForBlender(SkString sksl) { + return MakeForBlender(std::move(sksl), Options{}); + } + + // Object that allows passing a SkShader, SkColorFilter or SkBlender as a child + class SK_API ChildPtr { + public: + ChildPtr() = default; + ChildPtr(sk_sp s) : fChild(std::move(s)) {} + ChildPtr(sk_sp cf) : fChild(std::move(cf)) {} + ChildPtr(sk_sp b) : fChild(std::move(b)) {} + + // Asserts that the flattenable is either null, or one of the legal derived types + ChildPtr(sk_sp f); + + std::optional type() const; + + SkShader* shader() const; + SkColorFilter* colorFilter() const; + SkBlender* blender() const; + SkFlattenable* flattenable() const { return fChild.get(); } + + using sk_is_trivially_relocatable = std::true_type; + + private: + sk_sp fChild; + + static_assert(::sk_is_trivially_relocatable::value); + }; + + sk_sp makeShader(sk_sp uniforms, + sk_sp children[], + size_t childCount, + const SkMatrix* localMatrix = nullptr) const; + sk_sp makeShader(sk_sp uniforms, + SkSpan children, + const SkMatrix* localMatrix = nullptr) const; + + sk_sp makeColorFilter(sk_sp uniforms) const; + sk_sp makeColorFilter(sk_sp uniforms, + sk_sp children[], + size_t childCount) const; + sk_sp makeColorFilter(sk_sp uniforms, + SkSpan children) const; + + sk_sp makeBlender(sk_sp uniforms, + SkSpan children = {}) const; + + /** + * Creates a new Runtime Effect patterned after an already-existing one. The new shader behaves + * like the original, but also creates a debug trace of its execution at the requested + * coordinate. After painting with this shader, the associated DebugTrace object will contain a + * shader execution trace. Call `writeTrace` on the debug trace object to generate a full trace + * suitable for a debugger, or call `dump` to emit a human-readable trace. + * + * Debug traces are only supported on a raster (non-GPU) canvas. + + * Debug traces are currently only supported on shaders. Color filter and blender tracing is a + * work-in-progress. + */ + struct TracedShader { + sk_sp shader; + sk_sp debugTrace; + }; + static TracedShader MakeTraced(sk_sp shader, const SkIPoint& traceCoord); + + // Returns the SkSL source of the runtime effect shader. + const std::string& source() const; + + // Combined size of all 'uniform' variables. When calling makeColorFilter or makeShader, + // provide an SkData of this size, containing values for all of those variables. + size_t uniformSize() const; + + SkSpan uniforms() const { return SkSpan(fUniforms); } + SkSpan children() const { return SkSpan(fChildren); } + + // Returns pointer to the named uniform variable's description, or nullptr if not found + const Uniform* findUniform(std::string_view name) const; + + // Returns pointer to the named child's description, or nullptr if not found + const Child* findChild(std::string_view name) const; + + // Allows the runtime effect type to be identified. + bool allowShader() const { return (fFlags & kAllowShader_Flag); } + bool allowColorFilter() const { return (fFlags & kAllowColorFilter_Flag); } + bool allowBlender() const { return (fFlags & kAllowBlender_Flag); } + + static void RegisterFlattenables(); + ~SkRuntimeEffect() override; + +private: + enum Flags { + kUsesSampleCoords_Flag = 0x001, + kAllowColorFilter_Flag = 0x002, + kAllowShader_Flag = 0x004, + kAllowBlender_Flag = 0x008, + kSamplesOutsideMain_Flag = 0x010, + kUsesColorTransform_Flag = 0x020, + kAlwaysOpaque_Flag = 0x040, + kAlphaUnchanged_Flag = 0x080, + kDisableOptimization_Flag = 0x100, + }; + + SkRuntimeEffect(std::unique_ptr baseProgram, + const Options& options, + const SkSL::FunctionDefinition& main, + std::vector&& uniforms, + std::vector&& children, + std::vector&& sampleUsages, + uint32_t flags); + + sk_sp makeUnoptimizedClone(); + + static Result MakeFromSource(SkString sksl, const Options& options, SkSL::ProgramKind kind); + + static Result MakeInternal(std::unique_ptr program, + const Options& options, + SkSL::ProgramKind kind); + + static SkSL::ProgramSettings MakeSettings(const Options& options); + + uint32_t hash() const { return fHash; } + bool usesSampleCoords() const { return (fFlags & kUsesSampleCoords_Flag); } + bool samplesOutsideMain() const { return (fFlags & kSamplesOutsideMain_Flag); } + bool usesColorTransform() const { return (fFlags & kUsesColorTransform_Flag); } + bool alwaysOpaque() const { return (fFlags & kAlwaysOpaque_Flag); } + bool isAlphaUnchanged() const { return (fFlags & kAlphaUnchanged_Flag); } + + const SkSL::RP::Program* getRPProgram(SkSL::DebugTracePriv* debugTrace) const; + + friend class GrSkSLFP; // usesColorTransform + friend class SkRuntimeShader; // fBaseProgram, fMain, fSampleUsages, getRPProgram() + friend class SkRuntimeBlender; // + friend class SkRuntimeColorFilter; // + + friend class SkRuntimeEffectPriv; + + uint32_t fHash; + uint32_t fStableKey; + + std::unique_ptr fBaseProgram; + std::unique_ptr fRPProgram; + mutable SkOnce fCompileRPProgramOnce; + const SkSL::FunctionDefinition& fMain; + std::vector fUniforms; + std::vector fChildren; + std::vector fSampleUsages; + + uint32_t fFlags; // Flags +}; + +/** Base class for SkRuntimeShaderBuilder, defined below. */ +class SkRuntimeEffectBuilder { +public: + struct BuilderUniform { + // Copy 'val' to this variable. No type conversion is performed - 'val' must be same + // size as expected by the effect. Information about the variable can be queried by + // looking at fVar. If the size is incorrect, no copy will be performed, and debug + // builds will abort. If this is the result of querying a missing variable, fVar will + // be nullptr, and assigning will also do nothing (and abort in debug builds). + template + std::enable_if_t::value, BuilderUniform&> operator=( + const T& val) { + if (!fVar) { + SkDEBUGFAIL("Assigning to missing variable"); + } else if (sizeof(val) != fVar->sizeInBytes()) { + SkDEBUGFAIL("Incorrect value size"); + } else { + memcpy(SkTAddOffset(fOwner->writableUniformData(), fVar->offset), + &val, sizeof(val)); + } + return *this; + } + + BuilderUniform& operator=(const SkMatrix& val) { + if (!fVar) { + SkDEBUGFAIL("Assigning to missing variable"); + } else if (fVar->sizeInBytes() != 9 * sizeof(float)) { + SkDEBUGFAIL("Incorrect value size"); + } else { + float* data = SkTAddOffset(fOwner->writableUniformData(), + (ptrdiff_t)fVar->offset); + data[0] = val.get(0); data[1] = val.get(3); data[2] = val.get(6); + data[3] = val.get(1); data[4] = val.get(4); data[5] = val.get(7); + data[6] = val.get(2); data[7] = val.get(5); data[8] = val.get(8); + } + return *this; + } + + template + bool set(const T val[], const int count) { + static_assert(std::is_trivially_copyable::value, "Value must be trivial copyable"); + if (!fVar) { + SkDEBUGFAIL("Assigning to missing variable"); + return false; + } else if (sizeof(T) * count != fVar->sizeInBytes()) { + SkDEBUGFAIL("Incorrect value size"); + return false; + } else { + memcpy(SkTAddOffset(fOwner->writableUniformData(), fVar->offset), + val, sizeof(T) * count); + } + return true; + } + + SkRuntimeEffectBuilder* fOwner; + const SkRuntimeEffect::Uniform* fVar; // nullptr if the variable was not found + }; + + struct BuilderChild { + template BuilderChild& operator=(sk_sp val) { + if (!fChild) { + SkDEBUGFAIL("Assigning to missing child"); + } else { + fOwner->fChildren[(size_t)fChild->index] = std::move(val); + } + return *this; + } + + BuilderChild& operator=(std::nullptr_t) { + if (!fChild) { + SkDEBUGFAIL("Assigning to missing child"); + } else { + fOwner->fChildren[(size_t)fChild->index] = SkRuntimeEffect::ChildPtr{}; + } + return *this; + } + + SkRuntimeEffectBuilder* fOwner; + const SkRuntimeEffect::Child* fChild; // nullptr if the child was not found + }; + + const SkRuntimeEffect* effect() const { return fEffect.get(); } + + BuilderUniform uniform(std::string_view name) { return { this, fEffect->findUniform(name) }; } + BuilderChild child(std::string_view name) { return { this, fEffect->findChild(name) }; } + + // Get access to the collated uniforms and children (in the order expected by APIs like + // makeShader on the effect): + sk_sp uniforms() const { return fUniforms; } + SkSpan children() const { return fChildren; } + +protected: + SkRuntimeEffectBuilder() = delete; + explicit SkRuntimeEffectBuilder(sk_sp effect) + : fEffect(std::move(effect)) + , fUniforms(SkData::MakeZeroInitialized(fEffect->uniformSize())) + , fChildren(fEffect->children().size()) {} + explicit SkRuntimeEffectBuilder(sk_sp effect, sk_sp uniforms) + : fEffect(std::move(effect)) + , fUniforms(std::move(uniforms)) + , fChildren(fEffect->children().size()) {} + + SkRuntimeEffectBuilder(SkRuntimeEffectBuilder&&) = default; + SkRuntimeEffectBuilder(const SkRuntimeEffectBuilder&) = default; + + SkRuntimeEffectBuilder& operator=(SkRuntimeEffectBuilder&&) = delete; + SkRuntimeEffectBuilder& operator=(const SkRuntimeEffectBuilder&) = delete; + +private: + void* writableUniformData() { + if (!fUniforms->unique()) { + fUniforms = SkData::MakeWithCopy(fUniforms->data(), fUniforms->size()); + } + return fUniforms->writable_data(); + } + + sk_sp fEffect; + sk_sp fUniforms; + std::vector fChildren; +}; + +/** + * SkRuntimeShaderBuilder is a utility to simplify creating SkShader objects from SkRuntimeEffects. + * + * NOTE: Like SkRuntimeEffect, this API is experimental and subject to change! + * + * Given an SkRuntimeEffect, the SkRuntimeShaderBuilder manages creating an input data block and + * provides named access to the 'uniform' variables in that block, as well as named access + * to a list of child shader slots. Usage: + * + * sk_sp effect = ...; + * SkRuntimeShaderBuilder builder(effect); + * builder.uniform("some_uniform_float") = 3.14f; + * builder.uniform("some_uniform_matrix") = SkM44::Rotate(...); + * builder.child("some_child_effect") = mySkImage->makeShader(...); + * ... + * sk_sp shader = builder.makeShader(nullptr, false); + * + * Note that SkRuntimeShaderBuilder is built entirely on the public API of SkRuntimeEffect, + * so can be used as-is or serve as inspiration for other interfaces or binding techniques. + */ +class SK_API SkRuntimeShaderBuilder : public SkRuntimeEffectBuilder { +public: + explicit SkRuntimeShaderBuilder(sk_sp); + // This is currently required by Android Framework but may go away if that dependency + // can be removed. + SkRuntimeShaderBuilder(const SkRuntimeShaderBuilder&) = default; + ~SkRuntimeShaderBuilder(); + + sk_sp makeShader(const SkMatrix* localMatrix = nullptr) const; + +private: + explicit SkRuntimeShaderBuilder(sk_sp effect, sk_sp uniforms) + : SkRuntimeEffectBuilder(std::move(effect), std::move(uniforms)) {} + + friend class SkRuntimeImageFilter; +}; + +/** + * SkRuntimeColorFilterBuilder makes it easy to setup and assign uniforms to runtime color filters. + */ +class SK_API SkRuntimeColorFilterBuilder : public SkRuntimeEffectBuilder { +public: + explicit SkRuntimeColorFilterBuilder(sk_sp); + ~SkRuntimeColorFilterBuilder(); + + SkRuntimeColorFilterBuilder(const SkRuntimeColorFilterBuilder&) = delete; + SkRuntimeColorFilterBuilder& operator=(const SkRuntimeColorFilterBuilder&) = delete; + + sk_sp makeColorFilter() const; +}; + +/** + * SkRuntimeBlendBuilder is a utility to simplify creation and uniform setup of runtime blenders. + */ +class SK_API SkRuntimeBlendBuilder : public SkRuntimeEffectBuilder { +public: + explicit SkRuntimeBlendBuilder(sk_sp); + ~SkRuntimeBlendBuilder(); + + SkRuntimeBlendBuilder(const SkRuntimeBlendBuilder&) = delete; + SkRuntimeBlendBuilder& operator=(const SkRuntimeBlendBuilder&) = delete; + + sk_sp makeBlender() const; +}; + +#endif // SkRuntimeEffect_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkShaderMaskFilter.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkShaderMaskFilter.h new file mode 100644 index 0000000000..b0c269e869 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkShaderMaskFilter.h @@ -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 SkShaderMaskFilter_DEFINED +#define SkShaderMaskFilter_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" + +class SkMaskFilter; +class SkShader; + +// (DEPRECATED) This factory function is deprecated. ShaderMaskFilters will be deleted entirely +// in an upcoming Skia release. +class SK_API SkShaderMaskFilter { +public: + static sk_sp Make(sk_sp shader); + +private: + static void RegisterFlattenables(); + friend class SkFlattenable; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkTableMaskFilter.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkTableMaskFilter.h new file mode 100644 index 0000000000..937037afa8 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkTableMaskFilter.h @@ -0,0 +1,43 @@ +/* + * 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 SkTableMaskFilter_DEFINED +#define SkTableMaskFilter_DEFINED + +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" + +#include + +class SkMaskFilter; + +/** \class SkTableMaskFilter + + Applies a table lookup on each of the alpha values in the mask. + Helper methods create some common tables (e.g. gamma, clipping) + */ +// (DEPRECATED) These factory functions are deprecated. The TableMaskFilter will be +// removed entirely in an upcoming release of Skia. +class SK_API SkTableMaskFilter { +public: + /** Utility that sets the gamma table + */ + static void MakeGammaTable(uint8_t table[256], SkScalar gamma); + + /** Utility that creates a clipping table: clamps values below min to 0 + and above max to 255, and rescales the remaining into 0..255 + */ + static void MakeClipTable(uint8_t table[256], uint8_t min, uint8_t max); + + static SkMaskFilter* Create(const uint8_t table[256]); + static SkMaskFilter* CreateGamma(SkScalar gamma); + static SkMaskFilter* CreateClip(uint8_t min, uint8_t max); + + SkTableMaskFilter() = delete; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkTrimPathEffect.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkTrimPathEffect.h new file mode 100644 index 0000000000..3e6fb7c342 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/effects/SkTrimPathEffect.h @@ -0,0 +1,45 @@ +/* + * 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 SkTrimPathEffect_DEFINED +#define SkTrimPathEffect_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" + +class SkPathEffect; + +class SK_API SkTrimPathEffect { +public: + enum class Mode { + kNormal, // return the subset path [start,stop] + kInverted, // return the complement/subset paths [0,start] + [stop,1] + }; + + /** + * Take start and stop "t" values (values between 0...1), and return a path that is that + * subset of the original path. + * + * e.g. + * Make(0.5, 1.0) --> return the 2nd half of the path + * Make(0.33333, 0.66667) --> return the middle third of the path + * + * The trim values apply to the entire path, so if it contains several contours, all of them + * are including in the calculation. + * + * startT and stopT must be 0..1 inclusive. If they are outside of that interval, they will + * be pinned to the nearest legal value. If either is NaN, null will be returned. + * + * Note: for Mode::kNormal, this will return one (logical) segment (even if it is spread + * across multiple contours). For Mode::kInverted, this will return 2 logical + * segments: stopT..1 and 0...startT, in this order. + */ + static sk_sp Make(SkScalar startT, SkScalar stopT, Mode = Mode::kNormal); +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/encode/SkEncoder.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/encode/SkEncoder.h new file mode 100644 index 0000000000..8f76e8016c --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/encode/SkEncoder.h @@ -0,0 +1,63 @@ +/* + * 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 SkEncoder_DEFINED +#define SkEncoder_DEFINED + +#include "include/core/SkPixmap.h" +#include "include/private/base/SkAPI.h" +#include "include/private/base/SkNoncopyable.h" +#include "include/private/base/SkTemplates.h" + +#include +#include + +class SK_API SkEncoder : SkNoncopyable { +public: + /** + * A single frame to be encoded into an animated image. + * + * If a frame does not fit in the canvas size, this is an error. + * TODO(skia:13705): Add offsets when we have support for an encoder that supports using + * offsets. + */ + struct SK_API Frame { + /** + * Pixmap of the frame. + */ + SkPixmap pixmap; + /** + * Duration of the frame in millseconds. + */ + int duration; + }; + + /** + * Encode |numRows| rows of input. If the caller requests more rows than are remaining + * in the src, this will encode all of the remaining rows. |numRows| must be greater + * than zero. + */ + bool encodeRows(int numRows); + + virtual ~SkEncoder() {} + +protected: + + virtual bool onEncodeRows(int numRows) = 0; + + SkEncoder(const SkPixmap& src, size_t storageBytes) + : fSrc(src) + , fCurrRow(0) + , fStorage(storageBytes) + {} + + const SkPixmap& fSrc; + int fCurrRow; + skia_private::AutoTMalloc fStorage; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/encode/SkICC.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/encode/SkICC.h new file mode 100644 index 0000000000..b14836b2ab --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/encode/SkICC.h @@ -0,0 +1,36 @@ +/* + * 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 SkICC_DEFINED +#define SkICC_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/private/base/SkAPI.h" + +#include + +class SkData; +struct skcms_ICCProfile; +struct skcms_Matrix3x3; +struct skcms_TransferFunction; + +SK_API sk_sp SkWriteICCProfile(const skcms_TransferFunction&, + const skcms_Matrix3x3& toXYZD50); + +SK_API sk_sp SkWriteICCProfile(const skcms_ICCProfile*, const char* description); + +// Utility function for populating the grid_16 member of skcms_A2B and skcms_B2A +// structures. This converts a point in XYZD50 to its representation in grid_16_lab. +// It will write 6 bytes. The behavior of this function matches how skcms will decode +// values, but might not match the specification, see https://crbug.com/skia/13807. +SK_API void SkICCFloatXYZD50ToGrid16Lab(const float* float_xyz, uint8_t* grid16_lab); + +// Utility function for popluating the table_16 member of skcms_Curve structure. +// This converts a float to its representation in table_16. It will write 2 bytes. +SK_API void SkICCFloatToTable16(const float f, uint8_t* table_16); + +#endif//SkICC_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/encode/SkJpegEncoder.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/encode/SkJpegEncoder.h new file mode 100644 index 0000000000..f7e8effa7f --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/encode/SkJpegEncoder.h @@ -0,0 +1,128 @@ +/* + * 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 SkJpegEncoder_DEFINED +#define SkJpegEncoder_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/private/base/SkAPI.h" + +#include + +class SkColorSpace; +class SkData; +class SkEncoder; +class SkPixmap; +class SkWStream; +class SkImage; +class GrDirectContext; +class SkYUVAPixmaps; +struct skcms_ICCProfile; + +namespace SkJpegEncoder { + +enum class AlphaOption { + kIgnore, + kBlendOnBlack, +}; + +enum class Downsample { + /** + * Reduction by a factor of two in both the horizontal and vertical directions. + */ + k420, + + /** + * Reduction by a factor of two in the horizontal direction. + */ + k422, + + /** + * No downsampling. + */ + k444, +}; + +struct Options { + /** + * |fQuality| must be in [0, 100] where 0 corresponds to the lowest quality. + */ + int fQuality = 100; + + /** + * Choose the downsampling factor for the U and V components. This is only + * meaningful if the |src| is not kGray, since kGray will not be encoded as YUV. + * This is ignored in favor of |src|'s subsampling when |src| is an SkYUVAPixmaps. + * + * Our default value matches the libjpeg-turbo default. + */ + Downsample fDownsample = Downsample::k420; + + /** + * Jpegs must be opaque. This instructs the encoder on how to handle input + * images with alpha. + * + * The default is to ignore the alpha channel and treat the image as opaque. + * Another option is to blend the pixels onto a black background before encoding. + * In the second case, the encoder supports linear or legacy blending. + */ + AlphaOption fAlphaOption = AlphaOption::kIgnore; + + /** + * Optional XMP metadata. + */ + const SkData* xmpMetadata = nullptr; + + /** + * An optional ICC profile to override the default behavior. + * + * The default behavior is to generate an ICC profile using a primary matrix and + * analytic transfer function. If the color space of |src| cannot be represented + * in this way (e.g, it is HLG or PQ), then no profile will be embedded. + */ + const skcms_ICCProfile* fICCProfile = nullptr; + const char* fICCProfileDescription = nullptr; +}; + +/** + * Encode the |src| pixels to the |dst| stream. + * |options| may be used to control the encoding behavior. + * + * Returns true on success. Returns false on an invalid or unsupported |src|. + */ +SK_API bool Encode(SkWStream* dst, const SkPixmap& src, const Options& options); +SK_API bool Encode(SkWStream* dst, + const SkYUVAPixmaps& src, + const SkColorSpace* srcColorSpace, + const Options& options); + +/** +* Encode the provided image and return the resulting bytes. If the image was created as +* a texture-backed image on a GPU context, that |ctx| must be provided so the pixels +* can be read before being encoded. For raster-backed images, |ctx| can be nullptr. +* |options| may be used to control the encoding behavior. +* +* Returns nullptr if the pixels could not be read or encoding otherwise fails. +*/ +SK_API sk_sp Encode(GrDirectContext* ctx, const SkImage* img, const Options& options); + +/** + * Create a jpeg encoder that will encode the |src| pixels to the |dst| stream. + * |options| may be used to control the encoding behavior. + * + * |dst| is unowned but must remain valid for the lifetime of the object. + * + * This returns nullptr on an invalid or unsupported |src|. + */ +SK_API std::unique_ptr Make(SkWStream* dst, const SkPixmap& src, const Options& options); +SK_API std::unique_ptr Make(SkWStream* dst, + const SkYUVAPixmaps& src, + const SkColorSpace* srcColorSpace, + const Options& options); +} // namespace SkJpegEncoder + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/encode/SkPngEncoder.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/encode/SkPngEncoder.h new file mode 100644 index 0000000000..b26befa323 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/encode/SkPngEncoder.h @@ -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 SkPngEncoder_DEFINED +#define SkPngEncoder_DEFINED + +#include "include/core/SkDataTable.h" +#include "include/core/SkRefCnt.h" +#include "include/private/base/SkAPI.h" + +// TODO(kjlubick) update clients to directly include this +#include "include/encode/SkEncoder.h" // IWYU pragma: keep + +#include + +class GrDirectContext; +class SkData; +class SkImage; +class SkPixmap; +class SkWStream; +struct skcms_ICCProfile; + +namespace SkPngEncoder { + +enum class FilterFlag : int { + kZero = 0x00, + kNone = 0x08, + kSub = 0x10, + kUp = 0x20, + kAvg = 0x40, + kPaeth = 0x80, + kAll = kNone | kSub | kUp | kAvg | kPaeth, +}; + +inline FilterFlag operator|(FilterFlag x, FilterFlag y) { return (FilterFlag)((int)x | (int)y); } + +struct Options { + /** + * Selects which filtering strategies to use. + * + * If a single filter is chosen, libpng will use that filter for every row. + * + * If multiple filters are chosen, libpng will use a heuristic to guess which filter + * will encode smallest, then apply that filter. This happens on a per row basis, + * different rows can use different filters. + * + * Using a single filter (or less filters) is typically faster. Trying all of the + * filters may help minimize the output file size. + * + * Our default value matches libpng's default. + */ + FilterFlag fFilterFlags = FilterFlag::kAll; + + /** + * Must be in [0, 9] where 9 corresponds to maximal compression. This value is passed + * directly to zlib. 0 is a special case to skip zlib entirely, creating dramatically + * larger pngs. + * + * Our default value matches libpng's default. + */ + int fZLibLevel = 6; + + /** + * Represents comments in the tEXt ancillary chunk of the png. + * The 2i-th entry is the keyword for the i-th comment, + * and the (2i + 1)-th entry is the text for the i-th comment. + */ + sk_sp fComments; + + /** + * An optional ICC profile to override the default behavior. + * + * The default behavior is to generate an ICC profile using a primary matrix and + * analytic transfer function. If the color space of |src| cannot be represented + * in this way (e.g, it is HLG or PQ), then no profile will be embedded. + */ + const skcms_ICCProfile* fICCProfile = nullptr; + const char* fICCProfileDescription = nullptr; +}; + +/** + * Encode the |src| pixels to the |dst| stream. + * |options| may be used to control the encoding behavior. + * + * Returns true on success. Returns false on an invalid or unsupported |src|. + */ +SK_API bool Encode(SkWStream* dst, const SkPixmap& src, const Options& options); + +/** +* Encode the provided image and return the resulting bytes. If the image was created as +* a texture-backed image on a GPU context, that |ctx| must be provided so the pixels +* can be read before being encoded. For raster-backed images, |ctx| can be nullptr. +* |options| may be used to control the encoding behavior. +* +* Returns nullptr if the pixels could not be read or encoding otherwise fails. +*/ +SK_API sk_sp Encode(GrDirectContext* ctx, const SkImage* img, const Options& options); + +/** + * Create a png encoder that will encode the |src| pixels to the |dst| stream. + * |options| may be used to control the encoding behavior. + * + * The primary use of this is incremental encoding of the pixels. + * + * |dst| is unowned but must remain valid for the lifetime of the object. + * + * This returns nullptr on an invalid or unsupported |src|. + */ +SK_API std::unique_ptr Make(SkWStream* dst, const SkPixmap& src, const Options& options); + +} // namespace SkPngEncoder + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/encode/SkWebpEncoder.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/encode/SkWebpEncoder.h new file mode 100644 index 0000000000..fe11044e73 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/encode/SkWebpEncoder.h @@ -0,0 +1,92 @@ +/* + * 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 SkWebpEncoder_DEFINED +#define SkWebpEncoder_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkSpan.h" // IWYU pragma: keep +#include "include/encode/SkEncoder.h" +#include "include/private/base/SkAPI.h" + +class SkPixmap; +class SkWStream; +class SkData; +class GrDirectContext; +class SkImage; +struct skcms_ICCProfile; + +namespace SkWebpEncoder { + +enum class Compression { + kLossy, + kLossless, +}; + +struct SK_API Options { + /** + * |fCompression| determines whether we will use webp lossy or lossless compression. + * + * |fQuality| must be in [0.0f, 100.0f]. + * If |fCompression| is kLossy, |fQuality| corresponds to the visual quality of the + * encoding. Decreasing the quality will result in a smaller encoded image. + * If |fCompression| is kLossless, |fQuality| corresponds to the amount of effort + * put into the encoding. Lower values will compress faster into larger files, + * while larger values will compress slower into smaller files. + * + * This scheme is designed to match the libwebp API. + */ + Compression fCompression = Compression::kLossy; + float fQuality = 100.0f; + + /** + * An optional ICC profile to override the default behavior. + * + * The default behavior is to generate an ICC profile using a primary matrix and + * analytic transfer function. If the color space of |src| cannot be represented + * in this way (e.g, it is HLG or PQ), then no profile will be embedded. + */ + const skcms_ICCProfile* fICCProfile = nullptr; + const char* fICCProfileDescription = nullptr; +}; + +/** + * Encode the |src| pixels to the |dst| stream. + * |options| may be used to control the encoding behavior. + * + * Returns true on success. Returns false on an invalid or unsupported |src|. + */ +SK_API bool Encode(SkWStream* dst, const SkPixmap& src, const Options& options); + +/** +* Encode the provided image and return the resulting bytes. If the image was created as +* a texture-backed image on a GPU context, that |ctx| must be provided so the pixels +* can be read before being encoded. For raster-backed images, |ctx| can be nullptr. +* |options| may be used to control the encoding behavior. +* +* Returns nullptr if the pixels could not be read or encoding otherwise fails. +*/ +SK_API sk_sp Encode(GrDirectContext* ctx, const SkImage* img, const Options& options); + +/** + * Encode the |src| frames to the |dst| stream. + * |options| may be used to control the encoding behavior. + * + * The size of the first frame will be used as the canvas size. If any other frame does + * not match the canvas size, this is an error. + * + * Returns true on success. Returns false on an invalid or unsupported |src|. + * + * Note: libwebp API also supports set background color, loop limit and customize + * lossy/lossless for each frame. These could be added later as needed. + */ +SK_API bool EncodeAnimated(SkWStream* dst, + SkSpan src, + const Options& options); +} // namespace SkWebpEncoder + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/pathops/SkPathOps.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/pathops/SkPathOps.h new file mode 100644 index 0000000000..47d2b3118f --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/pathops/SkPathOps.h @@ -0,0 +1,113 @@ +/* + * 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 SkPathOps_DEFINED +#define SkPathOps_DEFINED + +#include "include/core/SkPath.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkTArray.h" +#include "include/private/base/SkTDArray.h" + +struct SkRect; + + +// FIXME: move everything below into the SkPath class +/** + * The logical operations that can be performed when combining two paths. + */ +enum SkPathOp { + kDifference_SkPathOp, //!< subtract the op path from the first path + kIntersect_SkPathOp, //!< intersect the two paths + kUnion_SkPathOp, //!< union (inclusive-or) the two paths + kXOR_SkPathOp, //!< exclusive-or the two paths + kReverseDifference_SkPathOp, //!< subtract the first path from the op path +}; + +/** Set this path to the result of applying the Op to this path and the + specified path: this = (this op operand). + The resulting path will be constructed from non-overlapping contours. + The curve order is reduced where possible so that cubics may be turned + into quadratics, and quadratics maybe turned into lines. + + Returns true if operation was able to produce a result; + otherwise, result is unmodified. + + @param one The first operand (for difference, the minuend) + @param two The second operand (for difference, the subtrahend) + @param op The operator to apply. + @param result The product of the operands. The result may be one of the + inputs. + @return True if the operation succeeded. + */ +bool SK_API Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result); + +/** Set this path to a set of non-overlapping contours that describe the + same area as the original path. + The curve order is reduced where possible so that cubics may + be turned into quadratics, and quadratics maybe turned into lines. + + Returns true if operation was able to produce a result; + otherwise, result is unmodified. + + @param path The path to simplify. + @param result The simplified path. The result may be the input. + @return True if simplification succeeded. + */ +bool SK_API Simplify(const SkPath& path, SkPath* result); + +/** Set the resulting rectangle to the tight bounds of the path. + + @param path The path measured. + @param result The tight bounds of the path. + @return True if the bounds could be computed. + */ +bool SK_API TightBounds(const SkPath& path, SkRect* result); + +/** Set the result with fill type winding to area equivalent to path. + Returns true if successful. Does not detect if path contains contours which + contain self-crossings or cross other contours; in these cases, may return + true even though result does not fill same area as path. + + Returns true if operation was able to produce a result; + otherwise, result is unmodified. The result may be the input. + + @param path The path typically with fill type set to even odd. + @param result The equivalent path with fill type set to winding. + @return True if winding path was set. + */ +bool SK_API AsWinding(const SkPath& path, SkPath* result); + +/** Perform a series of path operations, optimized for unioning many paths together. + */ +class SK_API SkOpBuilder { +public: + /** Add one or more paths and their operand. The builder is empty before the first + path is added, so the result of a single add is (emptyPath OP path). + + @param path The second operand. + @param _operator The operator to apply to the existing and supplied paths. + */ + void add(const SkPath& path, SkPathOp _operator); + + /** Computes the sum of all paths and operands, and resets the builder to its + initial state. + + @param result The product of the operands. + @return True if the operation succeeded. + */ + bool resolve(SkPath* result); + +private: + skia_private::TArray fPathRefs; + SkTDArray fOps; + + static bool FixWinding(SkPath* path); + static void ReversePath(SkPath* path); + void reset(); +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkCFObject.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkCFObject.h new file mode 100644 index 0000000000..4e56d06d06 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkCFObject.h @@ -0,0 +1,180 @@ +/* + * Copyright 2019 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkCFObject_DEFINED +#define SkCFObject_DEFINED + +#ifdef __APPLE__ + +#include "include/core/SkTypes.h" + +#include // std::nullptr_t + +#import + +/** + * Wrapper class for managing lifetime of CoreFoundation objects. It will call + * CFRetain and CFRelease appropriately on creation, assignment, and deletion. + * Based on sk_sp<>. + */ +template static inline T SkCFSafeRetain(T obj) { + if (obj) { + CFRetain(obj); + } + return obj; +} + +template static inline void SkCFSafeRelease(T obj) { + if (obj) { + CFRelease(obj); + } +} + +template class sk_cfp { +public: + using element_type = T; + + constexpr sk_cfp() {} + constexpr sk_cfp(std::nullptr_t) {} + + /** + * Shares the underlying object by calling CFRetain(), so that both the argument and the newly + * created sk_cfp both have a reference to it. + */ + sk_cfp(const sk_cfp& that) : fObject(SkCFSafeRetain(that.get())) {} + + /** + * Move the underlying object from the argument to the newly created sk_cfp. Afterwards only + * the new sk_cfp will have a reference to the object, and the argument will point to null. + * No call to CFRetain() or CFRelease() will be made. + */ + sk_cfp(sk_cfp&& that) : fObject(that.release()) {} + + /** + * Adopt the bare object into the newly created sk_cfp. + * No call to CFRetain() or CFRelease() will be made. + */ + explicit sk_cfp(T obj) { + fObject = obj; + } + + /** + * Calls CFRelease() on the underlying object pointer. + */ + ~sk_cfp() { + SkCFSafeRelease(fObject); + SkDEBUGCODE(fObject = nil); + } + + sk_cfp& operator=(std::nullptr_t) { this->reset(); return *this; } + + /** + * Shares the underlying object referenced by the argument by calling CFRetain() on it. If this + * sk_cfp previously had a reference to an object (i.e. not null) it will call CFRelease() + * on that object. + */ + sk_cfp& operator=(const sk_cfp& that) { + if (this != &that) { + this->reset(SkCFSafeRetain(that.get())); + } + return *this; + } + + /** + * Move the underlying object from the argument to the sk_cfp. If the sk_cfp + * previously held a reference to another object, CFRelease() will be called on that object. + * No call to CFRetain() will be made. + */ + sk_cfp& operator=(sk_cfp&& that) { + this->reset(that.release()); + return *this; + } + + explicit operator bool() const { return this->get() != nil; } + + T get() const { return fObject; } + T operator*() const { + SkASSERT(fObject); + return fObject; + } + + /** + * Adopt the new object, and call CFRelease() on any previously held object (if not null). + * No call to CFRetain() will be made. + */ + void reset(T object = nil) { + // Need to unref after assigning, see + // http://wg21.cmeerw.net/lwg/issue998 + // http://wg21.cmeerw.net/lwg/issue2262 + T oldObject = fObject; + fObject = object; + SkCFSafeRelease(oldObject); + } + + /** + * Shares the new object by calling CFRetain() on it. If this sk_cfp previously had a + * reference to an object (i.e. not null) it will call CFRelease() on that object. + */ + void retain(T object) { + if (fObject != object) { + this->reset(SkCFSafeRetain(object)); + } + } + + /** + * Return the original object, and set the internal object to nullptr. + * The caller must assume ownership of the object, and manage its reference count directly. + * No call to CFRelease() will be made. + */ + [[nodiscard]] T release() { + T obj = fObject; + fObject = nil; + return obj; + } + +private: + T fObject = nil; +}; + +template inline bool operator==(const sk_cfp& a, + const sk_cfp& b) { + return a.get() == b.get(); +} +template inline bool operator==(const sk_cfp& a, + std::nullptr_t) { + return !a; +} +template inline bool operator==(std::nullptr_t, + const sk_cfp& b) { + return !b; +} + +template inline bool operator!=(const sk_cfp& a, + const sk_cfp& b) { + return a.get() != b.get(); +} +template inline bool operator!=(const sk_cfp& a, + std::nullptr_t) { + return static_cast(a); +} +template inline bool operator!=(std::nullptr_t, + const sk_cfp& b) { + return static_cast(b); +} + +/* + * Returns a sk_cfp wrapping the provided object AND calls retain on it (if not null). + * + * This is different than the semantics of the constructor for sk_cfp, which just wraps the + * object, effectively "adopting" it. + */ +template sk_cfp sk_ret_cfp(T obj) { + return sk_cfp(SkCFSafeRetain(obj)); +} + +#endif // __APPLE__ +#endif // SkCFObject_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkFontConfigInterface.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkFontConfigInterface.h new file mode 100644 index 0000000000..f8fdca53f9 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkFontConfigInterface.h @@ -0,0 +1,112 @@ +/* + * 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 SkFontConfigInterface_DEFINED +#define SkFontConfigInterface_DEFINED + +#include "include/core/SkFontStyle.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkStream.h" +#include "include/core/SkTypeface.h" + +class SkFontMgr; + +/** + * \class SkFontConfigInterface + * + * A simple interface for remotable font management. + * The global instance can be found with RefGlobal(). + */ +class SK_API SkFontConfigInterface : public SkRefCnt { +public: + + /** + * Returns the global SkFontConfigInterface instance. If it is not + * nullptr, calls ref() on it. The caller must balance this with a call to + * unref(). The default SkFontConfigInterface is the result of calling + * GetSingletonDirectInterface. + */ + static sk_sp RefGlobal(); + + /** + * Replace the current global instance with the specified one. + */ + static void SetGlobal(sk_sp fc); + + /** + * This should be treated as private to the impl of SkFontConfigInterface. + * Callers should not change or expect any particular values. It is meant + * to be a union of possible storage types to aid the impl. + */ + struct FontIdentity { + FontIdentity() : fID(0), fTTCIndex(0) {} + + bool operator==(const FontIdentity& other) const { + return fID == other.fID && + fTTCIndex == other.fTTCIndex && + fString == other.fString; + } + bool operator!=(const FontIdentity& other) const { + return !(*this == other); + } + + uint32_t fID; + int32_t fTTCIndex; + SkString fString; + SkFontStyle fStyle; + + // If buffer is NULL, just return the number of bytes that would have + // been written. Will pad contents to a multiple of 4. + size_t writeToMemory(void* buffer = nullptr) const; + + // Recreate from a flattened buffer, returning the number of bytes read. + size_t readFromMemory(const void* buffer, size_t length); + }; + + /** + * Given a familyName and style, find the best match. + * + * If a match is found, return true and set its outFontIdentifier. + * If outFamilyName is not null, assign the found familyName to it + * (which may differ from the requested familyName). + * If outStyle is not null, assign the found style to it + * (which may differ from the requested style). + * + * If a match is not found, return false, and ignore all out parameters. + */ + virtual bool matchFamilyName(const char familyName[], + SkFontStyle requested, + FontIdentity* outFontIdentifier, + SkString* outFamilyName, + SkFontStyle* outStyle) = 0; + + /** + * Given a FontRef, open a stream to access its data, or return null + * if the FontRef's data is not available. The caller is responsible for + * deleting the stream when it is done accessing the data. + */ + virtual SkStreamAsset* openStream(const FontIdentity&) = 0; + + /** + * Return an SkTypeface for the given FontIdentity. + * + * The default implementation simply returns a new typeface built using data obtained from + * openStream() using the provided SkFontMgr, but derived classes may implement more + * complex caching schemes. + */ + virtual sk_sp makeTypeface(const FontIdentity& identity, sk_sp mgr); + + /** + * Return a singleton instance of a direct subclass that calls into + * libfontconfig. This does not affect the refcnt of the returned instance. + */ + static SkFontConfigInterface* GetSingletonDirectInterface(); + + using INHERITED = SkRefCnt; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkFontMgr_FontConfigInterface.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkFontMgr_FontConfigInterface.h new file mode 100644 index 0000000000..05771257d2 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkFontMgr_FontConfigInterface.h @@ -0,0 +1,20 @@ +/* + * 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 SkFontMgr_FontConfigInterface_DEFINED +#define SkFontMgr_FontConfigInterface_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" + +class SkFontMgr; +class SkFontConfigInterface; + +/** Creates a SkFontMgr which wraps a SkFontConfigInterface. */ +SK_API sk_sp SkFontMgr_New_FCI(sk_sp fci); + +#endif // #ifndef SkFontMgr_FontConfigInterface_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkFontMgr_Fontations.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkFontMgr_Fontations.h new file mode 100644 index 0000000000..c5b546c367 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkFontMgr_Fontations.h @@ -0,0 +1,20 @@ +/* + * Copyright 2024 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkFontMgr_fontations_DEFINED +#define SkFontMgr_fontations_DEFINED + +#include "include/core/SkRefCnt.h" + +class SkFontMgr; + +/** Create a font manager instantiating fonts using the Rust Fontations backend. + * This font manager does not support matching fonts, only instantiation. + */ +SK_API sk_sp SkFontMgr_New_Fontations_Empty(); + +#endif // #ifndef SkFontMgr_fontations_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkFontMgr_android.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkFontMgr_android.h new file mode 100644 index 0000000000..cb3bea29a2 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkFontMgr_android.h @@ -0,0 +1,50 @@ +/* + * 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 SkFontMgr_android_DEFINED +#define SkFontMgr_android_DEFINED + +#include "include/core/SkRefCnt.h" + +class SkFontMgr; +class SkFontScanner; + +struct SkFontMgr_Android_CustomFonts { + /** When specifying custom fonts, indicates how to use system fonts. */ + enum SystemFontUse { + kOnlyCustom, /** Use only custom fonts. NDK compliant. */ + kPreferCustom, /** Use custom fonts before system fonts. */ + kPreferSystem /** Use system fonts before custom fonts. */ + }; + /** Whether or not to use system fonts. */ + SystemFontUse fSystemFontUse; + + /** Base path to resolve relative font file names. If a directory, should end with '/'. */ + const char* fBasePath; + + /** Optional custom configuration file to use. */ + const char* fFontsXml; + + /** Optional custom configuration file for fonts which provide fallback. + * In the new style (version > 21) fontsXml format is used, this should be NULL. + */ + const char* fFallbackFontsXml; + + /** Optional custom flag. If set to true the SkFontMgr will acquire all requisite + * system IO resources on initialization. + */ + bool fIsolated; +}; + +/** Create a font manager for Android. If 'custom' is NULL, use only system fonts. */ + +// Deprecated +SK_API sk_sp SkFontMgr_New_Android(const SkFontMgr_Android_CustomFonts* custom); + +SK_API sk_sp SkFontMgr_New_Android(const SkFontMgr_Android_CustomFonts* custom, + std::unique_ptr scanner); +#endif // SkFontMgr_android_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkFontMgr_data.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkFontMgr_data.h new file mode 100644 index 0000000000..6a22365af4 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkFontMgr_data.h @@ -0,0 +1,22 @@ +/* + * Copyright 2023 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkFontMgr_data_DEFINED +#define SkFontMgr_data_DEFINED + +#include "include/core/SkData.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkSpan.h" +#include "include/core/SkTypes.h" + +class SkFontMgr; + +/** Create a custom font manager which wraps a collection of SkData-stored fonts. + * This font manager uses FreeType for rendering. + */ +SK_API sk_sp SkFontMgr_New_Custom_Data(SkSpan>); + +#endif // SkFontMgr_data_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkFontMgr_directory.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkFontMgr_directory.h new file mode 100644 index 0000000000..b1a60fb4da --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkFontMgr_directory.h @@ -0,0 +1,21 @@ +/* + * 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 SkFontMgr_directory_DEFINED +#define SkFontMgr_directory_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" + +class SkFontMgr; + +/** Create a custom font manager which scans a given directory for font files. + * This font manager uses FreeType for rendering. + */ +SK_API sk_sp SkFontMgr_New_Custom_Directory(const char* dir); + +#endif // SkFontMgr_directory_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkFontMgr_empty.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkFontMgr_empty.h new file mode 100644 index 0000000000..e5756421d0 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkFontMgr_empty.h @@ -0,0 +1,21 @@ +/* + * 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 SkFontMgr_empty_DEFINED +#define SkFontMgr_empty_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" + +class SkFontMgr; + +/** Create a custom font manager that contains no built-in fonts. + * This font manager uses FreeType for rendering. + */ +SK_API sk_sp SkFontMgr_New_Custom_Empty(); + +#endif // SkFontMgr_empty_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkFontMgr_fontconfig.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkFontMgr_fontconfig.h new file mode 100644 index 0000000000..4b2bb2d297 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkFontMgr_fontconfig.h @@ -0,0 +1,22 @@ +/* + * 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 SkFontMgr_fontconfig_DEFINED +#define SkFontMgr_fontconfig_DEFINED + +#include "include/core/SkRefCnt.h" +#include + +class SkFontMgr; + +/** Create a font manager around a FontConfig instance. + * If 'fc' is NULL, will use a new default config. + * Takes ownership of 'fc' and will call FcConfigDestroy on it. + */ +SK_API sk_sp SkFontMgr_New_FontConfig(FcConfig* fc); + +#endif // #ifndef SkFontMgr_fontconfig_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkFontMgr_fuchsia.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkFontMgr_fuchsia.h new file mode 100644 index 0000000000..d20530af72 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkFontMgr_fuchsia.h @@ -0,0 +1,19 @@ +/* + * 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 SkFontMgr_fuchsia_DEFINED +#define SkFontMgr_fuchsia_DEFINED + +#include + +#include "include/core/SkRefCnt.h" + +class SkFontMgr; + +SK_API sk_sp SkFontMgr_New_Fuchsia(fuchsia::fonts::ProviderSyncPtr provider); + +#endif // SkFontMgr_fuchsia_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkFontMgr_mac_ct.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkFontMgr_mac_ct.h new file mode 100644 index 0000000000..45cba65b5d --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkFontMgr_mac_ct.h @@ -0,0 +1,27 @@ +/* + * 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 SkFontMgr_mac_ct_DEFINED +#define SkFontMgr_mac_ct_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" + +#ifdef SK_BUILD_FOR_MAC +#import +#endif + +#ifdef SK_BUILD_FOR_IOS +#include +#endif + +class SkFontMgr; + +/** Create a font manager for CoreText. If the collection is nullptr the system default will be used. */ +SK_API extern sk_sp SkFontMgr_New_CoreText(CTFontCollectionRef); + +#endif // SkFontMgr_mac_ct_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkImageGeneratorCG.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkImageGeneratorCG.h new file mode 100644 index 0000000000..6fa775db49 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkImageGeneratorCG.h @@ -0,0 +1,28 @@ +/* + * 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 SkImageGeneratorCG_DEFINED +#define SkImageGeneratorCG_DEFINED + +// This is needed as clients may override the target platform +// using SkUserConfig +#include "include/private/base/SkLoadUserConfig.h" + +#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) + +#include "include/core/SkData.h" +#include "include/core/SkImageGenerator.h" +#include "include/core/SkRefCnt.h" +#include "include/private/base/SkAPI.h" + +#include + +namespace SkImageGeneratorCG { +SK_API std::unique_ptr MakeFromEncodedCG(sk_sp); +} // namespace SkImageGeneratorCG + +#endif // defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) +#endif // SkImageGeneratorCG_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkImageGeneratorNDK.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkImageGeneratorNDK.h new file mode 100644 index 0000000000..739a586f0d --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkImageGeneratorNDK.h @@ -0,0 +1,40 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkImageGeneratorNDK_DEFINED +#define SkImageGeneratorNDK_DEFINED + +#include "include/core/SkTypes.h" +#ifdef SK_ENABLE_NDK_IMAGES + +#include "include/core/SkData.h" +#include "include/core/SkImageGenerator.h" + +#include + +namespace SkImageGeneratorNDK { +/** + * Create a generator that uses the Android NDK's APIs for decoding images. + * + * Only supported on devices where __ANDROID_API__ >= 30. + * + * As with SkCodec, the SkColorSpace passed to getPixels() determines the + * type of color space transformations to apply. A null SkColorSpace means to + * apply none. + * + * A note on scaling: Calling getPixels() on the resulting SkImageGenerator + * with dimensions that do not match getInfo() requests a scale. For WebP + * files, dimensions smaller than those of getInfo are supported. For Jpeg + * files, dimensions of 1/2, 1/4, and 1/8 are supported. TODO: Provide an + * API like SkCodecImageGenerator::getScaledDimensions() to report which + * dimensions are supported? + */ +SK_API std::unique_ptr MakeFromEncodedNDK(sk_sp); +} + +#endif // SK_ENABLE_NDK_IMAGES +#endif // SkImageGeneratorNDK_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkImageGeneratorWIC.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkImageGeneratorWIC.h new file mode 100644 index 0000000000..5ea3b83e24 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkImageGeneratorWIC.h @@ -0,0 +1,41 @@ +/* + * 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 SkImageGeneratorWIC_DEFINED +#define SkImageGeneratorWIC_DEFINED + +#include "include/private/base/SkFeatures.h" + +#if defined(SK_BUILD_FOR_WIN) + +#include "include/core/SkData.h" +#include "include/core/SkImageGenerator.h" +#include "include/core/SkRefCnt.h" +#include "include/private/base/SkAPI.h" + +#include + +/* + * Any Windows program that uses COM must initialize the COM library by calling + * the CoInitializeEx function. In addition, each thread that uses a COM + * interface must make a separate call to this function. + * + * For every successful call to CoInitializeEx, the thread must call + * CoUninitialize before it exits. + * + * SkImageGeneratorWIC requires the COM library and leaves it to the client to + * initialize COM for their application. + * + * For more information on initializing COM, please see: + * https://msdn.microsoft.com/en-us/library/windows/desktop/ff485844.aspx + */ +namespace SkImageGeneratorWIC { +SK_API std::unique_ptr MakeFromEncodedWIC(sk_sp); +} + +#endif // SK_BUILD_FOR_WIN +#endif // SkImageGeneratorWIC_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkTypeface_fontations.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkTypeface_fontations.h new file mode 100644 index 0000000000..cd6531ab64 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkTypeface_fontations.h @@ -0,0 +1,21 @@ +/* + * Copyright 2023 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkTypeface_fontations_DEFINED +#define SkTypeface_fontations_DEFINED + +#include "include/core/SkFontArguments.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypeface.h" +#include "include/core/SkTypes.h" + +#include + +SK_API sk_sp SkTypeface_Make_Fontations(std::unique_ptr fontData, + const SkFontArguments& args); + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkTypeface_mac.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkTypeface_mac.h new file mode 100644 index 0000000000..ec68e05492 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkTypeface_mac.h @@ -0,0 +1,44 @@ +/* + * 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 SkTypeface_mac_DEFINED +#define SkTypeface_mac_DEFINED + +#include "include/core/SkTypeface.h" + +#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) + +#include + +#ifdef SK_BUILD_FOR_MAC +#import +#endif + +#ifdef SK_BUILD_FOR_IOS +#include +#endif + +/** + * Like the other Typeface make methods, this returns a new reference to the + * corresponding typeface for the specified CTFontRef. + */ +SK_API extern sk_sp SkMakeTypefaceFromCTFont(CTFontRef); + +/** + * Returns the platform-specific CTFontRef handle for a + * given SkTypeface. Note that the returned CTFontRef gets + * released when the source SkTypeface is destroyed. + * + * This method is deprecated. It may only be used by Blink Mac + * legacy code in special cases related to text-shaping + * with AAT fonts, clipboard handling and font fallback. + * See https://code.google.com/p/skia/issues/detail?id=3408 + */ +SK_API extern CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face); + +#endif // defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) +#endif // SkTypeface_mac_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkTypeface_win.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkTypeface_win.h new file mode 100644 index 0000000000..45711ba231 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/ports/SkTypeface_win.h @@ -0,0 +1,63 @@ +/* + * 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 SkTypeface_win_DEFINED +#define SkTypeface_win_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypeface.h" +#include "include/core/SkTypes.h" + +#ifdef SK_BUILD_FOR_WIN + +#ifdef UNICODE +typedef struct tagLOGFONTW LOGFONTW; +typedef LOGFONTW LOGFONT; +#else +typedef struct tagLOGFONTA LOGFONTA; +typedef LOGFONTA LOGFONT; +#endif // UNICODE + +/** + * Like the other Typeface create methods, this returns a new reference to the + * corresponding typeface for the specified logfont. The caller is responsible + * for calling unref() when it is finished. + */ +SK_API sk_sp SkCreateTypefaceFromLOGFONT(const LOGFONT&); + +/** + * Copy the LOGFONT associated with this typeface into the lf parameter. Note + * that the lfHeight will need to be set afterwards, since the typeface does + * not track this (the paint does). + * typeface may be NULL, in which case we return the logfont for the default font. + */ +SK_API void SkLOGFONTFromTypeface(const SkTypeface* typeface, LOGFONT* lf); + +/** + * Set an optional callback to ensure that the data behind a LOGFONT is loaded. + * This will get called if Skia tries to access the data but hits a failure. + * Normally this is null, and is only required if the font data needs to be + * remotely (re)loaded. + */ +SK_API void SkTypeface_SetEnsureLOGFONTAccessibleProc(void (*)(const LOGFONT&)); + +// Experimental! +// +class SkFontMgr; +struct IDWriteFactory; +struct IDWriteFontCollection; +struct IDWriteFontFallback; + +SK_API sk_sp SkFontMgr_New_GDI(); +SK_API sk_sp SkFontMgr_New_DirectWrite(IDWriteFactory* factory = nullptr, + IDWriteFontCollection* collection = nullptr); +SK_API sk_sp SkFontMgr_New_DirectWrite(IDWriteFactory* factory, + IDWriteFontCollection* collection, + IDWriteFontFallback* fallback); + +#endif // SK_BUILD_FOR_WIN +#endif // SkTypeface_win_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/OWNERS b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/OWNERS new file mode 100644 index 0000000000..7cf12a2a7f --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/OWNERS @@ -0,0 +1,4 @@ +# include/ has a restricted set of reviewers (to limit changes to public API) +# Files in this directory follow the same rules as the rest of Skia, though: + +file:../../OWNERS diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkColorData.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkColorData.h new file mode 100644 index 0000000000..0f6a3e9aa5 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkColorData.h @@ -0,0 +1,385 @@ +/* + * 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 SkColorData_DEFINED +#define SkColorData_DEFINED + +#include "include/core/SkColor.h" +#include "include/core/SkColorPriv.h" +#include "include/private/base/SkTo.h" + +//////////////////////////////////////////////////////////////////////////////////////////// +// Convert a 16bit pixel to a 32bit pixel + +#define SK_R16_BITS 5 +#define SK_G16_BITS 6 +#define SK_B16_BITS 5 + +#define SK_R16_SHIFT (SK_B16_BITS + SK_G16_BITS) +#define SK_G16_SHIFT (SK_B16_BITS) +#define SK_B16_SHIFT 0 + +#define SK_R16_MASK ((1 << SK_R16_BITS) - 1) +#define SK_G16_MASK ((1 << SK_G16_BITS) - 1) +#define SK_B16_MASK ((1 << SK_B16_BITS) - 1) + +#define SkGetPackedR16(color) (((unsigned)(color) >> SK_R16_SHIFT) & SK_R16_MASK) +#define SkGetPackedG16(color) (((unsigned)(color) >> SK_G16_SHIFT) & SK_G16_MASK) +#define SkGetPackedB16(color) (((unsigned)(color) >> SK_B16_SHIFT) & SK_B16_MASK) + +static inline unsigned SkR16ToR32(unsigned r) { + return (r << (8 - SK_R16_BITS)) | (r >> (2 * SK_R16_BITS - 8)); +} + +static inline unsigned SkG16ToG32(unsigned g) { + return (g << (8 - SK_G16_BITS)) | (g >> (2 * SK_G16_BITS - 8)); +} + +static inline unsigned SkB16ToB32(unsigned b) { + return (b << (8 - SK_B16_BITS)) | (b >> (2 * SK_B16_BITS - 8)); +} + +#define SkPacked16ToR32(c) SkR16ToR32(SkGetPackedR16(c)) +#define SkPacked16ToG32(c) SkG16ToG32(SkGetPackedG16(c)) +#define SkPacked16ToB32(c) SkB16ToB32(SkGetPackedB16(c)) + +////////////////////////////////////////////////////////////////////////////// + +#define SkASSERT_IS_BYTE(x) SkASSERT(0 == ((x) & ~0xFFu)) + +// Reverse the bytes coorsponding to RED and BLUE in a packed pixels. Note the +// pair of them are in the same 2 slots in both RGBA and BGRA, thus there is +// no need to pass in the colortype to this function. +static inline uint32_t SkSwizzle_RB(uint32_t c) { + static const uint32_t kRBMask = (0xFF << SK_R32_SHIFT) | (0xFF << SK_B32_SHIFT); + + unsigned c0 = (c >> SK_R32_SHIFT) & 0xFF; + unsigned c1 = (c >> SK_B32_SHIFT) & 0xFF; + return (c & ~kRBMask) | (c0 << SK_B32_SHIFT) | (c1 << SK_R32_SHIFT); +} + +static inline uint32_t SkPackARGB_as_RGBA(U8CPU a, U8CPU r, U8CPU g, U8CPU b) { + SkASSERT_IS_BYTE(a); + SkASSERT_IS_BYTE(r); + SkASSERT_IS_BYTE(g); + SkASSERT_IS_BYTE(b); + return (a << SK_RGBA_A32_SHIFT) | (r << SK_RGBA_R32_SHIFT) | + (g << SK_RGBA_G32_SHIFT) | (b << SK_RGBA_B32_SHIFT); +} + +static inline uint32_t SkPackARGB_as_BGRA(U8CPU a, U8CPU r, U8CPU g, U8CPU b) { + SkASSERT_IS_BYTE(a); + SkASSERT_IS_BYTE(r); + SkASSERT_IS_BYTE(g); + SkASSERT_IS_BYTE(b); + return (a << SK_BGRA_A32_SHIFT) | (r << SK_BGRA_R32_SHIFT) | + (g << SK_BGRA_G32_SHIFT) | (b << SK_BGRA_B32_SHIFT); +} + +static inline SkPMColor SkSwizzle_RGBA_to_PMColor(uint32_t c) { +#ifdef SK_PMCOLOR_IS_RGBA + return c; +#else + return SkSwizzle_RB(c); +#endif +} + +static inline SkPMColor SkSwizzle_BGRA_to_PMColor(uint32_t c) { +#ifdef SK_PMCOLOR_IS_BGRA + return c; +#else + return SkSwizzle_RB(c); +#endif +} + +////////////////////////////////////////////////////////////////////////////// + +///@{ +/** See ITU-R Recommendation BT.709 at http://www.itu.int/rec/R-REC-BT.709/ .*/ +#define SK_ITU_BT709_LUM_COEFF_R (0.2126f) +#define SK_ITU_BT709_LUM_COEFF_G (0.7152f) +#define SK_ITU_BT709_LUM_COEFF_B (0.0722f) +///@} + +///@{ +/** A float value which specifies this channel's contribution to luminance. */ +#define SK_LUM_COEFF_R SK_ITU_BT709_LUM_COEFF_R +#define SK_LUM_COEFF_G SK_ITU_BT709_LUM_COEFF_G +#define SK_LUM_COEFF_B SK_ITU_BT709_LUM_COEFF_B +///@} + +/** Computes the luminance from the given r, g, and b in accordance with + SK_LUM_COEFF_X. For correct results, r, g, and b should be in linear space. +*/ +static inline U8CPU SkComputeLuminance(U8CPU r, U8CPU g, U8CPU b) { + //The following is + //r * SK_LUM_COEFF_R + g * SK_LUM_COEFF_G + b * SK_LUM_COEFF_B + //with SK_LUM_COEFF_X in 1.8 fixed point (rounding adjusted to sum to 256). + return (r * 54 + g * 183 + b * 19) >> 8; +} + +/** Calculates 256 - (value * alpha256) / 255 in range [0,256], + * for [0,255] value and [0,256] alpha256. + */ +static inline U16CPU SkAlphaMulInv256(U16CPU value, U16CPU alpha256) { + unsigned prod = 0xFFFF - value * alpha256; + return (prod + (prod >> 8)) >> 8; +} + +// The caller may want negative values, so keep all params signed (int) +// so we don't accidentally slip into unsigned math and lose the sign +// extension when we shift (in SkAlphaMul) +static inline int SkAlphaBlend(int src, int dst, int scale256) { + SkASSERT((unsigned)scale256 <= 256); + return dst + SkAlphaMul(src - dst, scale256); +} + +static inline uint16_t SkPackRGB16(unsigned r, unsigned g, unsigned b) { + SkASSERT(r <= SK_R16_MASK); + SkASSERT(g <= SK_G16_MASK); + SkASSERT(b <= SK_B16_MASK); + + return SkToU16((r << SK_R16_SHIFT) | (g << SK_G16_SHIFT) | (b << SK_B16_SHIFT)); +} + +#define SK_R16_MASK_IN_PLACE (SK_R16_MASK << SK_R16_SHIFT) +#define SK_G16_MASK_IN_PLACE (SK_G16_MASK << SK_G16_SHIFT) +#define SK_B16_MASK_IN_PLACE (SK_B16_MASK << SK_B16_SHIFT) + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Abstract 4-byte interpolation, implemented on top of SkPMColor + * utility functions. Third parameter controls blending of the first two: + * (src, dst, 0) returns dst + * (src, dst, 0xFF) returns src + * scale is [0..256], unlike SkFourByteInterp which takes [0..255] + */ +static inline SkPMColor SkFourByteInterp256(SkPMColor src, SkPMColor dst, int scale) { + unsigned a = SkTo(SkAlphaBlend(SkGetPackedA32(src), SkGetPackedA32(dst), scale)); + unsigned r = SkTo(SkAlphaBlend(SkGetPackedR32(src), SkGetPackedR32(dst), scale)); + unsigned g = SkTo(SkAlphaBlend(SkGetPackedG32(src), SkGetPackedG32(dst), scale)); + unsigned b = SkTo(SkAlphaBlend(SkGetPackedB32(src), SkGetPackedB32(dst), scale)); + + return SkPackARGB32(a, r, g, b); +} + +/** + * Abstract 4-byte interpolation, implemented on top of SkPMColor + * utility functions. Third parameter controls blending of the first two: + * (src, dst, 0) returns dst + * (src, dst, 0xFF) returns src + */ +static inline SkPMColor SkFourByteInterp(SkPMColor src, SkPMColor dst, U8CPU srcWeight) { + int scale = (int)SkAlpha255To256(srcWeight); + return SkFourByteInterp256(src, dst, scale); +} + +/** + * 0xAARRGGBB -> 0x00AA00GG, 0x00RR00BB + */ +static inline void SkSplay(uint32_t color, uint32_t* ag, uint32_t* rb) { + const uint32_t mask = 0x00FF00FF; + *ag = (color >> 8) & mask; + *rb = color & mask; +} + +/** + * 0xAARRGGBB -> 0x00AA00GG00RR00BB + * (note, ARGB -> AGRB) + */ +static inline uint64_t SkSplay(uint32_t color) { + const uint32_t mask = 0x00FF00FF; + uint64_t agrb = (color >> 8) & mask; // 0x0000000000AA00GG + agrb <<= 32; // 0x00AA00GG00000000 + agrb |= color & mask; // 0x00AA00GG00RR00BB + return agrb; +} + +/** + * 0xAAxxGGxx, 0xRRxxBBxx-> 0xAARRGGBB + */ +static inline uint32_t SkUnsplay(uint32_t ag, uint32_t rb) { + const uint32_t mask = 0xFF00FF00; + return (ag & mask) | ((rb & mask) >> 8); +} + +/** + * 0xAAxxGGxxRRxxBBxx -> 0xAARRGGBB + * (note, AGRB -> ARGB) + */ +static inline uint32_t SkUnsplay(uint64_t agrb) { + const uint32_t mask = 0xFF00FF00; + return SkPMColor( + ((agrb & mask) >> 8) | // 0x00RR00BB + ((agrb >> 32) & mask)); // 0xAARRGGBB +} + +static inline SkPMColor SkFastFourByteInterp256_32(SkPMColor src, SkPMColor dst, unsigned scale) { + SkASSERT(scale <= 256); + + // Two 8-bit blends per two 32-bit registers, with space to make sure the math doesn't collide. + uint32_t src_ag, src_rb, dst_ag, dst_rb; + SkSplay(src, &src_ag, &src_rb); + SkSplay(dst, &dst_ag, &dst_rb); + + const uint32_t ret_ag = src_ag * scale + (256 - scale) * dst_ag; + const uint32_t ret_rb = src_rb * scale + (256 - scale) * dst_rb; + + return SkUnsplay(ret_ag, ret_rb); +} + +static inline SkPMColor SkFastFourByteInterp256_64(SkPMColor src, SkPMColor dst, unsigned scale) { + SkASSERT(scale <= 256); + // Four 8-bit blends in one 64-bit register, with space to make sure the math doesn't collide. + return SkUnsplay(SkSplay(src) * scale + (256-scale) * SkSplay(dst)); +} + +// TODO(mtklein): Replace slow versions with fast versions, using scale + (scale>>7) everywhere. + +/** + * Same as SkFourByteInterp256, but faster. + */ +static inline SkPMColor SkFastFourByteInterp256(SkPMColor src, SkPMColor dst, unsigned scale) { + // On a 64-bit machine, _64 is about 10% faster than _32, but ~40% slower on a 32-bit machine. + if (sizeof(void*) == 4) { + return SkFastFourByteInterp256_32(src, dst, scale); + } else { + return SkFastFourByteInterp256_64(src, dst, scale); + } +} + +/** + * Nearly the same as SkFourByteInterp, but faster and a touch more accurate, due to better + * srcWeight scaling to [0, 256]. + */ +static inline SkPMColor SkFastFourByteInterp(SkPMColor src, SkPMColor dst, U8CPU srcWeight) { + SkASSERT(srcWeight <= 255); + // scale = srcWeight + (srcWeight >> 7) is more accurate than + // scale = srcWeight + 1, but 7% slower + return SkFastFourByteInterp256(src, dst, srcWeight + (srcWeight >> 7)); +} + +/** + * Interpolates between colors src and dst using [0,256] scale. + */ +static inline SkPMColor SkPMLerp(SkPMColor src, SkPMColor dst, unsigned scale) { + return SkFastFourByteInterp256(src, dst, scale); +} + +static inline SkPMColor SkBlendARGB32(SkPMColor src, SkPMColor dst, U8CPU aa) { + SkASSERT((unsigned)aa <= 255); + + unsigned src_scale = SkAlpha255To256(aa); + unsigned dst_scale = SkAlphaMulInv256(SkGetPackedA32(src), src_scale); + + const uint32_t mask = 0xFF00FF; + + uint32_t src_rb = (src & mask) * src_scale; + uint32_t src_ag = ((src >> 8) & mask) * src_scale; + + uint32_t dst_rb = (dst & mask) * dst_scale; + uint32_t dst_ag = ((dst >> 8) & mask) * dst_scale; + + return (((src_rb + dst_rb) >> 8) & mask) | ((src_ag + dst_ag) & ~mask); +} + +//////////////////////////////////////////////////////////////////////////////////////////// +// Convert a 32bit pixel to a 16bit pixel (no dither) + +#define SkR32ToR16_MACRO(r) ((unsigned)(r) >> (SK_R32_BITS - SK_R16_BITS)) +#define SkG32ToG16_MACRO(g) ((unsigned)(g) >> (SK_G32_BITS - SK_G16_BITS)) +#define SkB32ToB16_MACRO(b) ((unsigned)(b) >> (SK_B32_BITS - SK_B16_BITS)) + +#ifdef SK_DEBUG + static inline unsigned SkR32ToR16(unsigned r) { + SkR32Assert(r); + return SkR32ToR16_MACRO(r); + } + static inline unsigned SkG32ToG16(unsigned g) { + SkG32Assert(g); + return SkG32ToG16_MACRO(g); + } + static inline unsigned SkB32ToB16(unsigned b) { + SkB32Assert(b); + return SkB32ToB16_MACRO(b); + } +#else + #define SkR32ToR16(r) SkR32ToR16_MACRO(r) + #define SkG32ToG16(g) SkG32ToG16_MACRO(g) + #define SkB32ToB16(b) SkB32ToB16_MACRO(b) +#endif + +static inline U16CPU SkPixel32ToPixel16(SkPMColor c) { + unsigned r = ((c >> (SK_R32_SHIFT + (8 - SK_R16_BITS))) & SK_R16_MASK) << SK_R16_SHIFT; + unsigned g = ((c >> (SK_G32_SHIFT + (8 - SK_G16_BITS))) & SK_G16_MASK) << SK_G16_SHIFT; + unsigned b = ((c >> (SK_B32_SHIFT + (8 - SK_B16_BITS))) & SK_B16_MASK) << SK_B16_SHIFT; + return r | g | b; +} + +static inline U16CPU SkPack888ToRGB16(U8CPU r, U8CPU g, U8CPU b) { + return (SkR32ToR16(r) << SK_R16_SHIFT) | + (SkG32ToG16(g) << SK_G16_SHIFT) | + (SkB32ToB16(b) << SK_B16_SHIFT); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static inline SkColor SkPixel16ToColor(U16CPU src) { + SkASSERT(src == SkToU16(src)); + + unsigned r = SkPacked16ToR32(src); + unsigned g = SkPacked16ToG32(src); + unsigned b = SkPacked16ToB32(src); + + SkASSERT((r >> (8 - SK_R16_BITS)) == SkGetPackedR16(src)); + SkASSERT((g >> (8 - SK_G16_BITS)) == SkGetPackedG16(src)); + SkASSERT((b >> (8 - SK_B16_BITS)) == SkGetPackedB16(src)); + + return SkColorSetRGB(r, g, b); +} + +/////////////////////////////////////////////////////////////////////////////// + +typedef uint16_t SkPMColor16; + +// Put in OpenGL order (r g b a) +#define SK_A4444_SHIFT 0 +#define SK_R4444_SHIFT 12 +#define SK_G4444_SHIFT 8 +#define SK_B4444_SHIFT 4 + +static inline U8CPU SkReplicateNibble(unsigned nib) { + SkASSERT(nib <= 0xF); + return (nib << 4) | nib; +} + +#define SkGetPackedA4444(c) (((unsigned)(c) >> SK_A4444_SHIFT) & 0xF) +#define SkGetPackedR4444(c) (((unsigned)(c) >> SK_R4444_SHIFT) & 0xF) +#define SkGetPackedG4444(c) (((unsigned)(c) >> SK_G4444_SHIFT) & 0xF) +#define SkGetPackedB4444(c) (((unsigned)(c) >> SK_B4444_SHIFT) & 0xF) + +#define SkPacked4444ToA32(c) SkReplicateNibble(SkGetPackedA4444(c)) + +static inline SkPMColor SkPixel4444ToPixel32(U16CPU c) { + uint32_t d = (SkGetPackedA4444(c) << SK_A32_SHIFT) | + (SkGetPackedR4444(c) << SK_R32_SHIFT) | + (SkGetPackedG4444(c) << SK_G32_SHIFT) | + (SkGetPackedB4444(c) << SK_B32_SHIFT); + return d | (d << 4); +} + +using SkPMColor4f = SkRGBA4f; + +constexpr SkPMColor4f SK_PMColor4fTRANSPARENT = { 0, 0, 0, 0 }; +constexpr SkPMColor4f SK_PMColor4fBLACK = { 0, 0, 0, 1 }; +constexpr SkPMColor4f SK_PMColor4fWHITE = { 1, 1, 1, 1 }; +constexpr SkPMColor4f SK_PMColor4fILLEGAL = { SK_FloatNegativeInfinity, + SK_FloatNegativeInfinity, + SK_FloatNegativeInfinity, + SK_FloatNegativeInfinity }; +#endif // SkColorData_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkEncodedInfo.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkEncodedInfo.h new file mode 100644 index 0000000000..f1cbc5050c --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkEncodedInfo.h @@ -0,0 +1,283 @@ +/* + * 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 SkEncodedInfo_DEFINED +#define SkEncodedInfo_DEFINED + +#include "include/core/SkAlphaType.h" +#include "include/core/SkColorSpace.h" +#include "include/core/SkColorType.h" +#include "include/core/SkData.h" +#include "include/core/SkImageInfo.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkTo.h" +#include "modules/skcms/skcms.h" + +#include +#include +#include + +struct SkEncodedInfo { +public: + class ICCProfile { + public: + static std::unique_ptr Make(sk_sp); + static std::unique_ptr Make(const skcms_ICCProfile&); + + const skcms_ICCProfile* profile() const { return &fProfile; } + sk_sp data() const { return fData; } + private: + ICCProfile(const skcms_ICCProfile&, sk_sp = nullptr); + + skcms_ICCProfile fProfile; + sk_sp fData; + }; + + enum Alpha { + kOpaque_Alpha, + kUnpremul_Alpha, + + // Each pixel is either fully opaque or fully transparent. + // There is no difference between requesting kPremul or kUnpremul. + kBinary_Alpha, + }; + + /* + * We strive to make the number of components per pixel obvious through + * our naming conventions. + * Ex: kRGB has 3 components. kRGBA has 4 components. + * + * This sometimes results in redundant Alpha and Color information. + * Ex: kRGB images must also be kOpaque. + */ + enum Color { + // PNG, WBMP + kGray_Color, + + // PNG + kGrayAlpha_Color, + + // PNG with Skia-specific sBIT + // Like kGrayAlpha, except this expects to be treated as + // kAlpha_8_SkColorType, which ignores the gray component. If + // decoded to full color (e.g. kN32), the gray component is respected + // (so it can share code with kGrayAlpha). + kXAlpha_Color, + + // PNG + // 565 images may be encoded to PNG by specifying the number of + // significant bits for each channel. This is a strange 565 + // representation because the image is still encoded with 8 bits per + // component. + k565_Color, + + // PNG, GIF, BMP + kPalette_Color, + + // PNG, RAW + kRGB_Color, + kRGBA_Color, + + // BMP + kBGR_Color, + kBGRX_Color, + kBGRA_Color, + + // JPEG, WEBP + kYUV_Color, + + // WEBP + kYUVA_Color, + + // JPEG + // Photoshop actually writes inverted CMYK data into JPEGs, where zero + // represents 100% ink coverage. For this reason, we treat CMYK JPEGs + // as having inverted CMYK. libjpeg-turbo warns that this may break + // other applications, but the CMYK JPEGs we see on the web expect to + // be treated as inverted CMYK. + kInvertedCMYK_Color, + kYCCK_Color, + }; + + static SkEncodedInfo Make(int width, int height, Color color, Alpha alpha, + int bitsPerComponent) { + return Make(width, height, color, alpha, bitsPerComponent, nullptr); + } + + static SkEncodedInfo Make(int width, int height, Color color, + Alpha alpha, int bitsPerComponent, std::unique_ptr profile) { + return Make(width, height, color, alpha, /*bitsPerComponent*/ bitsPerComponent, + std::move(profile), /*colorDepth*/ bitsPerComponent); + } + + static SkEncodedInfo Make(int width, int height, Color color, + Alpha alpha, int bitsPerComponent, std::unique_ptr profile, + int colorDepth) { + SkASSERT(1 == bitsPerComponent || + 2 == bitsPerComponent || + 4 == bitsPerComponent || + 8 == bitsPerComponent || + 16 == bitsPerComponent); + + switch (color) { + case kGray_Color: + SkASSERT(kOpaque_Alpha == alpha); + break; + case kGrayAlpha_Color: + SkASSERT(kOpaque_Alpha != alpha); + break; + case kPalette_Color: + SkASSERT(16 != bitsPerComponent); + break; + case kRGB_Color: + case kBGR_Color: + case kBGRX_Color: + SkASSERT(kOpaque_Alpha == alpha); + SkASSERT(bitsPerComponent >= 8); + break; + case kYUV_Color: + case kInvertedCMYK_Color: + case kYCCK_Color: + SkASSERT(kOpaque_Alpha == alpha); + SkASSERT(8 == bitsPerComponent); + break; + case kRGBA_Color: + SkASSERT(bitsPerComponent >= 8); + break; + case kBGRA_Color: + case kYUVA_Color: + SkASSERT(8 == bitsPerComponent); + break; + case kXAlpha_Color: + SkASSERT(kUnpremul_Alpha == alpha); + SkASSERT(8 == bitsPerComponent); + break; + case k565_Color: + SkASSERT(kOpaque_Alpha == alpha); + SkASSERT(8 == bitsPerComponent); + break; + default: + SkASSERT(false); + break; + } + + return SkEncodedInfo(width, + height, + color, + alpha, + SkToU8(bitsPerComponent), + SkToU8(colorDepth), + std::move(profile)); + } + + /* + * Returns a recommended SkImageInfo. + * + * TODO: Leave this up to the client. + */ + SkImageInfo makeImageInfo() const { + auto ct = kGray_Color == fColor ? kGray_8_SkColorType : + kXAlpha_Color == fColor ? kAlpha_8_SkColorType : + k565_Color == fColor ? kRGB_565_SkColorType : + kN32_SkColorType ; + auto alpha = kOpaque_Alpha == fAlpha ? kOpaque_SkAlphaType + : kUnpremul_SkAlphaType; + sk_sp cs = fProfile ? SkColorSpace::Make(*fProfile->profile()) + : nullptr; + if (!cs) { + cs = SkColorSpace::MakeSRGB(); + } + return SkImageInfo::Make(fWidth, fHeight, ct, alpha, std::move(cs)); + } + + int width() const { return fWidth; } + int height() const { return fHeight; } + Color color() const { return fColor; } + Alpha alpha() const { return fAlpha; } + bool opaque() const { return fAlpha == kOpaque_Alpha; } + const skcms_ICCProfile* profile() const { + if (!fProfile) return nullptr; + return fProfile->profile(); + } + sk_sp profileData() const { + if (!fProfile) return nullptr; + return fProfile->data(); + } + + uint8_t bitsPerComponent() const { return fBitsPerComponent; } + + uint8_t bitsPerPixel() const { + switch (fColor) { + case kGray_Color: + return fBitsPerComponent; + case kXAlpha_Color: + case kGrayAlpha_Color: + return 2 * fBitsPerComponent; + case kPalette_Color: + return fBitsPerComponent; + case kRGB_Color: + case kBGR_Color: + case kYUV_Color: + case k565_Color: + return 3 * fBitsPerComponent; + case kRGBA_Color: + case kBGRA_Color: + case kBGRX_Color: + case kYUVA_Color: + case kInvertedCMYK_Color: + case kYCCK_Color: + return 4 * fBitsPerComponent; + default: + SkASSERT(false); + return 0; + } + } + + SkEncodedInfo(const SkEncodedInfo& orig) = delete; + SkEncodedInfo& operator=(const SkEncodedInfo&) = delete; + + SkEncodedInfo(SkEncodedInfo&& orig) = default; + SkEncodedInfo& operator=(SkEncodedInfo&&) = default; + + // Explicit copy method, to avoid accidental copying. + SkEncodedInfo copy() const { + auto copy = SkEncodedInfo::Make( + fWidth, fHeight, fColor, fAlpha, fBitsPerComponent, nullptr, fColorDepth); + if (fProfile) { + copy.fProfile = std::make_unique(*fProfile); + } + return copy; + } + + // Return number of bits of R/G/B channel + uint8_t getColorDepth() const { + return fColorDepth; + } + +private: + SkEncodedInfo(int width, int height, Color color, Alpha alpha, + uint8_t bitsPerComponent, uint8_t colorDepth, std::unique_ptr profile) + : fWidth(width) + , fHeight(height) + , fColor(color) + , fAlpha(alpha) + , fBitsPerComponent(bitsPerComponent) + , fColorDepth(colorDepth) + , fProfile(std::move(profile)) + {} + + int fWidth; + int fHeight; + Color fColor; + Alpha fAlpha; + uint8_t fBitsPerComponent; + uint8_t fColorDepth; + std::unique_ptr fProfile; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkExif.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkExif.h new file mode 100644 index 0000000000..41abad3432 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkExif.h @@ -0,0 +1,55 @@ +/* + * Copyright 2023 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkExif_DEFINED +#define SkExif_DEFINED + +#include "include/codec/SkEncodedOrigin.h" +#include "include/private/base/SkAPI.h" + +#include +#include + +class SkData; + +namespace SkExif { + +// Tag values that are parsed by Parse and stored in Metadata. +static constexpr uint16_t kOriginTag = 0x112; +static constexpr uint16_t kResolutionUnitTag = 0x0128; +static constexpr uint16_t kXResolutionTag = 0x011a; +static constexpr uint16_t kYResolutionTag = 0x011b; +static constexpr uint16_t kPixelXDimensionTag = 0xa002; +static constexpr uint16_t kPixelYDimensionTag = 0xa003; + +struct Metadata { + // The image orientation. + std::optional fOrigin; + + // The HDR headroom property. + // https://developer.apple.com/documentation/appkit/images_and_pdf/applying_apple_hdr_effect_to_your_photos + std::optional fHdrHeadroom; + + // Resolution. + std::optional fResolutionUnit; + std::optional fXResolution; + std::optional fYResolution; + + // Size in pixels. + std::optional fPixelXDimension; + std::optional fPixelYDimension; +}; + +/* + * Parse the metadata specified in |data| and write them to |metadata|. Stop only at an + * unrecoverable error (allow truncated input). + */ +void SK_API Parse(Metadata& metadata, const SkData* data); + +} // namespace SkExif + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkGainmapInfo.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkGainmapInfo.h new file mode 100644 index 0000000000..033c9333cb --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkGainmapInfo.h @@ -0,0 +1,140 @@ +/* + * Copyright 2023 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkGainmapInfo_DEFINED +#define SkGainmapInfo_DEFINED + +#include "include/core/SkColor.h" +#include "include/core/SkColorSpace.h" +#include "include/core/SkRefCnt.h" +class SkData; + +/** + * Gainmap rendering parameters. Suppose our display has HDR to SDR ratio of H and we wish to + * display an image with gainmap on this display. Let B be the pixel value from the base image + * in a color space that has the primaries of the base image and a linear transfer function. Let + * G be the pixel value from the gainmap. Let D be the output pixel in the same color space as B. + * The value of D is computed as follows: + * + * First, let W be a weight parameter determing how much the gainmap will be applied. + * W = clamp((log(H) - log(fDisplayRatioSdr)) / + * (log(fDisplayRatioHdr) - log(fDisplayRatioSdr), 0, 1) + * + * Next, let L be the gainmap value in log space. We compute this from the value G that was + * sampled from the texture as follows: + * L = mix(log(fGainmapRatioMin), log(fGainmapRatioMax), pow(G, fGainmapGamma)) + * + * Finally, apply the gainmap to compute D, the displayed pixel. If the base image is SDR then + * compute: + * D = (B + fEpsilonSdr) * exp(L * W) - fEpsilonHdr + * If the base image is HDR then compute: + * D = (B + fEpsilonHdr) * exp(L * (W - 1)) - fEpsilonSdr + * + * In the above math, log() is a natural logarithm and exp() is natural exponentiation. Note, + * however, that the base used for the log() and exp() functions does not affect the results of + * the computation (it cancels out, as long as the same base is used throughout). + * + * This product includes Gain Map technology under license by Adobe. + */ +struct SkGainmapInfo { + /** + * Parameters for converting the gainmap from its image encoding to log space. These are + * specified per color channel. The alpha value is unused. + */ + SkColor4f fGainmapRatioMin = {1.f, 1.f, 1.f, 1.0}; + SkColor4f fGainmapRatioMax = {2.f, 2.f, 2.f, 1.0}; + SkColor4f fGainmapGamma = {1.f, 1.f, 1.f, 1.f}; + + /** + * Parameters sometimes used in gainmap computation to avoid numerical instability. + */ + SkColor4f fEpsilonSdr = {0.f, 0.f, 0.f, 1.0}; + SkColor4f fEpsilonHdr = {0.f, 0.f, 0.f, 1.0}; + + /** + * If the output display's HDR to SDR ratio is less or equal than fDisplayRatioSdr then the SDR + * rendition is displayed. If the output display's HDR to SDR ratio is greater or equal than + * fDisplayRatioHdr then the HDR rendition is displayed. If the output display's HDR to SDR + * ratio is between these values then an interpolation between the two is displayed using the + * math above. + */ + float fDisplayRatioSdr = 1.f; + float fDisplayRatioHdr = 2.f; + + /** + * Whether the base image is the SDR image or the HDR image. + */ + enum class BaseImageType { + kSDR, + kHDR, + }; + BaseImageType fBaseImageType = BaseImageType::kSDR; + + /** + * The type of the gainmap image. If the type is kApple, then the gainmap image was originally + * encoded according to the specification at [0], and can be converted to the kDefault type by + * applying the transformation described at [1]. + * [0] https://developer.apple.com/documentation/appkit/images_and_pdf/ + * applying_apple_hdr_effect_to_your_photos + * [1] https://docs.google.com/document/d/1iUpYAThVV_FuDdeiO3t0vnlfoA1ryq0WfGS9FuydwKc + */ + enum class Type { + kDefault, + kApple, + }; + Type fType = Type::kDefault; + + /** + * If specified, color space to apply the gainmap in, otherwise the base image's color space + * is used. Only the color primaries are used, the transfer function is irrelevant. + */ + sk_sp fGainmapMathColorSpace = nullptr; + + /** + * Return true if this can be encoded as an UltraHDR v1 image. + */ + bool isUltraHDRv1Compatible() const; + + /** + * If |data| contains an ISO 21496-1 version that is supported, return true. Otherwise return + * false. + */ + static bool ParseVersion(const SkData* data); + + /** + * If |data| constains ISO 21496-1 metadata then parse that metadata then use it to populate + * |info| and return true, otherwise return false. If |data| indicates that that the base image + * color space primaries should be used for gainmap application then set + * |fGainmapMathColorSpace| to nullptr, otherwise set |fGainmapMathColorSpace| to sRGB (the + * default, to be overwritten by the image decoder). + */ + static bool Parse(const SkData* data, SkGainmapInfo& info); + + /** + * Serialize an ISO 21496-1 version 0 blob containing only the version structure. + */ + static sk_sp SerializeVersion(); + + /** + * Serialize an ISO 21496-1 version 0 blob containing this' gainmap parameters. + */ + sk_sp serialize() const; + + inline bool operator==(const SkGainmapInfo& other) const { + return fGainmapRatioMin == other.fGainmapRatioMin && + fGainmapRatioMax == other.fGainmapRatioMax && fGainmapGamma == other.fGainmapGamma && + fEpsilonSdr == other.fEpsilonSdr && fEpsilonHdr == other.fEpsilonHdr && + fDisplayRatioSdr == other.fDisplayRatioSdr && + fDisplayRatioHdr == other.fDisplayRatioHdr && + fBaseImageType == other.fBaseImageType && fType == other.fType && + SkColorSpace::Equals(fGainmapMathColorSpace.get(), + other.fGainmapMathColorSpace.get()); + } + inline bool operator!=(const SkGainmapInfo& other) const { return !(*this == other); } +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkGainmapShader.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkGainmapShader.h new file mode 100644 index 0000000000..bc531124c7 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkGainmapShader.h @@ -0,0 +1,54 @@ +/* + * Copyright 2023 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkGainmapShader_DEFINED +#define SkGainmapShader_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/private/base/SkAPI.h" + +class SkColorSpace; +class SkShader; +class SkImage; +struct SkGainmapInfo; +struct SkRect; +struct SkSamplingOptions; + +/** + * A gainmap shader will apply a gainmap to an base image using the math described alongside the + * definition of SkGainmapInfo. + */ +class SK_API SkGainmapShader { +public: + /** + * Make a gainmap shader. + * + * When sampling the base image baseImage, the rectangle baseRect will be sampled to map to + * the rectangle dstRect. Sampling will be done according to baseSamplingOptions. + * + * When sampling the gainmap image gainmapImage, the rectangle gainmapRect will be sampled to + * map to the rectangle dstRect. Sampling will be done according to gainmapSamplingOptions. + * + * The gainmap will be applied according to the HDR to SDR ratio specified in dstHdrRatio. + * + * This shader must know the color space of the canvas that it will be rendered to. This color + * space must be specified in dstColorSpace. + * TODO(ccameron): Remove the need for dstColorSpace. + */ + static sk_sp Make(const sk_sp& baseImage, + const SkRect& baseRect, + const SkSamplingOptions& baseSamplingOptions, + const sk_sp& gainmapImage, + const SkRect& gainmapRect, + const SkSamplingOptions& gainmapSamplingOptions, + const SkGainmapInfo& gainmapInfo, + const SkRect& dstRect, + float dstHdrRatio, + sk_sp dstColorSpace); +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkIDChangeListener.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkIDChangeListener.h new file mode 100644 index 0000000000..8ebb6ca18e --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkIDChangeListener.h @@ -0,0 +1,76 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkIDChangeListener_DEFINED +#define SkIDChangeListener_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/private/base/SkMutex.h" +#include "include/private/base/SkTArray.h" +#include "include/private/base/SkThreadAnnotations.h" + +#include + +/** + * Used to be notified when a gen/unique ID is invalidated, typically to preemptively purge + * associated items from a cache that are no longer reachable. The listener can + * be marked for deregistration if the cached item is remove before the listener is + * triggered. This prevents unbounded listener growth when cache items are routinely + * removed before the gen ID/unique ID is invalidated. + */ +class SkIDChangeListener : public SkRefCnt { +public: + SkIDChangeListener(); + + ~SkIDChangeListener() override; + + virtual void changed() = 0; + + /** + * Mark the listener is no longer needed. It should be removed and changed() should not be + * called. + */ + void markShouldDeregister() { fShouldDeregister.store(true, std::memory_order_relaxed); } + + /** Indicates whether markShouldDeregister was called. */ + bool shouldDeregister() { return fShouldDeregister.load(std::memory_order_acquire); } + + /** Manages a list of SkIDChangeListeners. */ + class List { + public: + List(); + + ~List(); + + /** + * Add a new listener to the list. It must not already be deregistered. Also clears out + * previously deregistered listeners. + */ + void add(sk_sp listener) SK_EXCLUDES(fMutex); + + /** + * The number of registered listeners (including deregisterd listeners that are yet-to-be + * removed. + */ + int count() const SK_EXCLUDES(fMutex); + + /** Calls changed() on all listeners that haven't been deregistered and resets the list. */ + void changed() SK_EXCLUDES(fMutex); + + /** Resets without calling changed() on the listeners. */ + void reset() SK_EXCLUDES(fMutex); + + private: + mutable SkMutex fMutex; + skia_private::STArray<1, sk_sp> fListeners SK_GUARDED_BY(fMutex); + }; + +private: + std::atomic fShouldDeregister; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkJpegGainmapEncoder.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkJpegGainmapEncoder.h new file mode 100644 index 0000000000..0b4d4babc8 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkJpegGainmapEncoder.h @@ -0,0 +1,48 @@ +/* + * Copyright 2023 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkJpegGainmapEncoder_DEFINED +#define SkJpegGainmapEncoder_DEFINED + +#include "include/encode/SkJpegEncoder.h" + +class SkPixmap; +class SkWStream; +struct SkGainmapInfo; + +class SK_API SkJpegGainmapEncoder { +public: + /** + * Encode an UltraHDR image to |dst|. + * + * The base image is specified by |base|, and |baseOptions| controls the encoding behavior for + * the base image. + * + * The gainmap image is specified by |gainmap|, and |gainmapOptions| controls the encoding + * behavior for the gainmap image. + * + * The rendering behavior of the gainmap image is provided in |gainmapInfo|. + * + * If |baseOptions| or |gainmapOptions| specify XMP metadata, then that metadata will be + * overwritten. + * + * Returns true on success. Returns false on an invalid or unsupported |src|. + */ + static bool EncodeHDRGM(SkWStream* dst, + const SkPixmap& base, + const SkJpegEncoder::Options& baseOptions, + const SkPixmap& gainmap, + const SkJpegEncoder::Options& gainmapOptions, + const SkGainmapInfo& gainmapInfo); + + /** + * Write a Multi Picture Format containing the |imageCount| images specified by |images|. + */ + static bool MakeMPF(SkWStream* dst, const SkData** images, size_t imageCount); +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkJpegMetadataDecoder.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkJpegMetadataDecoder.h new file mode 100644 index 0000000000..c9e0b3406d --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkJpegMetadataDecoder.h @@ -0,0 +1,86 @@ +/* + * 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 SkJpegMetadataDecoder_DEFINED +#define SkJpegMetadataDecoder_DEFINED + +#include "include/core/SkData.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" + +#include +#include + +struct SkGainmapInfo; + +/** + * An interface that can be used to extract metadata from an encoded JPEG file. + */ +class SK_API SkJpegMetadataDecoder { +public: + SkJpegMetadataDecoder() {} + virtual ~SkJpegMetadataDecoder() {} + + SkJpegMetadataDecoder(const SkJpegMetadataDecoder&) = delete; + SkJpegMetadataDecoder& operator=(const SkJpegMetadataDecoder&) = delete; + + /** + * A segment from a JPEG file. This is usually populated from a jpeg_marker_struct. + */ + struct SK_API Segment { + Segment(uint8_t marker, sk_sp data) : fMarker(marker), fData(std::move(data)) {} + + // The segment's marker. + uint8_t fMarker = 0; + + // The segment's parameters (not including the marker and parameter length). + sk_sp fData; + }; + + /** + * Create metadata for the specified segments from a JPEG file's header (defined as all segments + * before the first StartOfScan). This may return nullptr. + */ + static std::unique_ptr Make(std::vector headerSegments); + + /** + * Return the Exif data attached to the image (if any) and nullptr otherwise. If |copyData| is + * false, then the returned SkData may directly reference the data provided when this object was + * created. + */ + virtual sk_sp getExifMetadata(bool copyData) const = 0; + + /** + * Return the ICC profile of the image if any, and nullptr otherwise. If |copyData| is false, + * then the returned SkData may directly reference the data provided when this object was + * created. + */ + virtual sk_sp getICCProfileData(bool copyData) const = 0; + + /** + * Return the ISO 21496-1 metadata, if any, and nullptr otherwise. If |copyData| is false, + * then the returned SkData may directly reference the data provided when this object was + * created. + */ + virtual sk_sp getISOGainmapMetadata(bool copyData) const = 0; + + /** + * Return true if there is a possibility that this image contains a gainmap image. + */ + virtual bool mightHaveGainmapImage() const = 0; + + /** + * Given a JPEG encoded image |baseImageData|, return in |outGainmapImageData| the JPEG encoded + * gainmap image and return in |outGainmapInfo| its gainmap rendering parameters. Return true if + * both output variables were successfully populated, otherwise return false. + */ + virtual bool findGainmapImage(sk_sp baseImageData, + sk_sp& outGainmapImagedata, + SkGainmapInfo& outGainmapInfo) = 0; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkPathRef.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkPathRef.h new file mode 100644 index 0000000000..6b2d8eccee --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkPathRef.h @@ -0,0 +1,582 @@ +/* + * 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 SkPathRef_DEFINED +#define SkPathRef_DEFINED + +#include "include/core/SkArc.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/SkIDChangeListener.h" +#include "include/private/base/SkDebug.h" +#include "include/private/base/SkTArray.h" +#include "include/private/base/SkTo.h" + +#include +#include +#include +#include +#include + +class SkMatrix; +class SkRRect; + +// These are computed from a stream of verbs +struct SkPathVerbAnalysis { + bool valid; + int points, weights; + unsigned segmentMask; +}; +SkPathVerbAnalysis sk_path_analyze_verbs(const uint8_t verbs[], int count); + + +/** + * Holds the path verbs and points. It is versioned by a generation ID. None of its public methods + * modify the contents. To modify or append to the verbs/points wrap the SkPathRef in an + * SkPathRef::Editor object. Installing the editor resets the generation ID. It also performs + * copy-on-write if the SkPathRef is shared by multiple SkPaths. The caller passes the Editor's + * constructor a pointer to a sk_sp, which may be updated to point to a new SkPathRef + * after the editor's constructor returns. + * + * The points and verbs are stored in a single allocation. The points are at the begining of the + * allocation while the verbs are stored at end of the allocation, in reverse order. Thus the points + * and verbs both grow into the middle of the allocation until the meet. To access verb i in the + * verb array use ref.verbs()[~i] (because verbs() returns a pointer just beyond the first + * logical verb or the last verb in memory). + */ + +class SK_API SkPathRef final : public SkNVRefCnt { +public: + // See https://bugs.chromium.org/p/skia/issues/detail?id=13817 for how these sizes were + // determined. + using PointsArray = skia_private::STArray<4, SkPoint>; + using VerbsArray = skia_private::STArray<4, uint8_t>; + using ConicWeightsArray = skia_private::STArray<2, SkScalar>; + + enum class PathType : uint8_t { + kGeneral, + kOval, + kOpenOval, // An unclosed oval, as is generated by canvas2d ellipse or arc + kRRect, + kArc, + }; + + SkPathRef(PointsArray points, VerbsArray verbs, ConicWeightsArray weights, + unsigned segmentMask) + : fPoints(std::move(points)) + , fVerbs(std::move(verbs)) + , fConicWeights(std::move(weights)) + { + fBoundsIsDirty = true; // this also invalidates fIsFinite + fGenerationID = 0; // recompute + fSegmentMask = segmentMask; + fType = PathType::kGeneral; + // The next two values don't matter unless fType is kOval or kRRect + fRRectOrOvalIsCCW = false; + fRRectOrOvalStartIdx = 0xAC; + fArcOval.setEmpty(); + fArcStartAngle = fArcSweepAngle = 0.0f; + fArcType = SkArc::Type::kArc; + SkDEBUGCODE(fEditorsAttached.store(0);) + + this->computeBounds(); // do this now, before we worry about multiple owners/threads + SkDEBUGCODE(this->validate();) + } + + class Editor { + public: + Editor(sk_sp* pathRef, + int incReserveVerbs = 0, + int incReservePoints = 0, + int incReserveConics = 0); + + ~Editor() { SkDEBUGCODE(fPathRef->fEditorsAttached--;) } + + /** + * Returns the array of points. + */ + SkPoint* writablePoints() { return fPathRef->getWritablePoints(); } + const SkPoint* points() const { return fPathRef->points(); } + + /** + * Gets the ith point. Shortcut for this->points() + i + */ + SkPoint* atPoint(int i) { return fPathRef->getWritablePoints() + i; } + const SkPoint* atPoint(int i) const { return &fPathRef->fPoints[i]; } + + /** + * Adds the verb and allocates space for the number of points indicated by the verb. The + * return value is a pointer to where the points for the verb should be written. + * 'weight' is only used if 'verb' is kConic_Verb + */ + SkPoint* growForVerb(int /*SkPath::Verb*/ verb, SkScalar weight = 0) { + SkDEBUGCODE(fPathRef->validate();) + return fPathRef->growForVerb(verb, weight); + } + + /** + * Allocates space for multiple instances of a particular verb and the + * requisite points & weights. + * The return pointer points at the first new point (indexed normally []). + * If 'verb' is kConic_Verb, 'weights' will return a pointer to the + * space for the conic weights (indexed normally). + */ + SkPoint* growForRepeatedVerb(int /*SkPath::Verb*/ verb, + int numVbs, + SkScalar** weights = nullptr) { + return fPathRef->growForRepeatedVerb(verb, numVbs, weights); + } + + /** + * Concatenates all verbs from 'path' onto the pathRef's verbs array. Increases the point + * count by the number of points in 'path', and the conic weight count by the number of + * conics in 'path'. + * + * Returns pointers to the uninitialized points and conic weights data. + */ + std::tuple growForVerbsInPath(const SkPathRef& path) { + return fPathRef->growForVerbsInPath(path); + } + + /** + * Resets the path ref to a new verb and point count. The new verbs and points are + * uninitialized. + */ + void resetToSize(int newVerbCnt, int newPointCnt, int newConicCount) { + fPathRef->resetToSize(newVerbCnt, newPointCnt, newConicCount); + } + + /** + * Gets the path ref that is wrapped in the Editor. + */ + SkPathRef* pathRef() { return fPathRef; } + + void setIsOval(bool isCCW, unsigned start, bool isClosed) { + fPathRef->setIsOval(isCCW, start, isClosed); + } + + void setIsRRect(bool isCCW, unsigned start) { + fPathRef->setIsRRect(isCCW, start); + } + + void setIsArc(const SkArc& arc) { + fPathRef->setIsArc(arc); + } + + void setBounds(const SkRect& rect) { fPathRef->setBounds(rect); } + + private: + SkPathRef* fPathRef; + }; + + class SK_API Iter { + public: + Iter(); + Iter(const SkPathRef&); + + void setPathRef(const SkPathRef&); + + /** Return the next verb in this iteration of the path. When all + segments have been visited, return kDone_Verb. + + If any point in the path is non-finite, return kDone_Verb immediately. + + @param pts The points representing the current verb and/or segment + This must not be NULL. + @return The verb for the current segment + */ + uint8_t next(SkPoint pts[4]); + uint8_t peek() const; + + SkScalar conicWeight() const { return *fConicWeights; } + + private: + const SkPoint* fPts; + const uint8_t* fVerbs; + const uint8_t* fVerbStop; + const SkScalar* fConicWeights; + }; + +public: + /** + * Gets a path ref with no verbs or points. + */ + static SkPathRef* CreateEmpty(); + + /** + * Returns true if all of the points in this path are finite, meaning there + * are no infinities and no NaNs. + */ + bool isFinite() const { + if (fBoundsIsDirty) { + this->computeBounds(); + } + return SkToBool(fIsFinite); + } + + /** + * Returns a mask, where each bit corresponding to a SegmentMask is + * set if the path contains 1 or more segments of that type. + * Returns 0 for an empty path (no segments). + */ + uint32_t getSegmentMasks() const { return fSegmentMask; } + + /** Returns true if the path is an oval. + * + * @param rect returns the bounding rect of this oval. It's a circle + * if the height and width are the same. + * @param isCCW is the oval CCW (or CW if false). + * @param start indicates where the contour starts on the oval (see + * SkPath::addOval for intepretation of the index). + * + * @return true if this path is an oval. + * Tracking whether a path is an oval is considered an + * optimization for performance and so some paths that are in + * fact ovals can report false. + */ + bool isOval(SkRect* rect, bool* isCCW, unsigned* start) const { + if (fType == PathType::kOval) { + if (rect) { + *rect = this->getBounds(); + } + if (isCCW) { + *isCCW = SkToBool(fRRectOrOvalIsCCW); + } + if (start) { + *start = fRRectOrOvalStartIdx; + } + } + + return fType == PathType::kOval; + } + + bool isRRect(SkRRect* rrect, bool* isCCW, unsigned* start) const; + + bool isArc(SkArc* arc) const { + if (fType == PathType::kArc) { + if (arc) { + *arc = SkArc::Make(fArcOval, fArcStartAngle, fArcSweepAngle, fArcType); + } + } + + return fType == PathType::kArc; + } + + bool hasComputedBounds() const { + return !fBoundsIsDirty; + } + + /** Returns the bounds of the path's points. If the path contains 0 or 1 + points, the bounds is set to (0,0,0,0), and isEmpty() will return true. + Note: this bounds may be larger than the actual shape, since curves + do not extend as far as their control points. + */ + const SkRect& getBounds() const { + if (fBoundsIsDirty) { + this->computeBounds(); + } + return fBounds; + } + + SkRRect getRRect() const; + + /** + * Transforms a path ref by a matrix, allocating a new one only if necessary. + */ + static void CreateTransformedCopy(sk_sp* dst, + const SkPathRef& src, + const SkMatrix& matrix); + + // static SkPathRef* CreateFromBuffer(SkRBuffer* buffer); + + /** + * Rollsback a path ref to zero verbs and points with the assumption that the path ref will be + * repopulated with approximately the same number of verbs and points. A new path ref is created + * only if necessary. + */ + static void Rewind(sk_sp* pathRef); + + ~SkPathRef(); + int countPoints() const { return fPoints.size(); } + int countVerbs() const { return fVerbs.size(); } + int countWeights() const { return fConicWeights.size(); } + + size_t approximateBytesUsed() const; + + /** + * Returns a pointer one beyond the first logical verb (last verb in memory order). + */ + const uint8_t* verbsBegin() const { return fVerbs.begin(); } + + /** + * Returns a const pointer to the first verb in memory (which is the last logical verb). + */ + const uint8_t* verbsEnd() const { return fVerbs.end(); } + + /** + * Returns a const pointer to the first point. + */ + const SkPoint* points() const { return fPoints.begin(); } + + /** + * Shortcut for this->points() + this->countPoints() + */ + const SkPoint* pointsEnd() const { return this->points() + this->countPoints(); } + + const SkScalar* conicWeights() const { return fConicWeights.begin(); } + const SkScalar* conicWeightsEnd() const { return fConicWeights.end(); } + + /** + * Convenience methods for getting to a verb or point by index. + */ + uint8_t atVerb(int index) const { return fVerbs[index]; } + const SkPoint& atPoint(int index) const { return fPoints[index]; } + + bool operator== (const SkPathRef& ref) const; + + void interpolate(const SkPathRef& ending, SkScalar weight, SkPathRef* out) const; + + /** + * Gets an ID that uniquely identifies the contents of the path ref. If two path refs have the + * same ID then they have the same verbs and points. However, two path refs may have the same + * contents but different genIDs. + * skbug.com/1762 for background on why fillType is necessary (for now). + */ + uint32_t genID(uint8_t fillType) const; + + void addGenIDChangeListener(sk_sp); // Threadsafe. + int genIDChangeListenerCount(); // Threadsafe + + bool dataMatchesVerbs() const; + bool isValid() const; + SkDEBUGCODE(void validate() const { SkASSERT(this->isValid()); } ) + + /** + * Resets this SkPathRef to a clean state. + */ + void reset(); + + bool isInitialEmptyPathRef() const { + return fGenerationID == kEmptyGenID; + } + +private: + enum SerializationOffsets { + kLegacyRRectOrOvalStartIdx_SerializationShift = 28, // requires 3 bits, ignored. + kLegacyRRectOrOvalIsCCW_SerializationShift = 27, // requires 1 bit, ignored. + kLegacyIsRRect_SerializationShift = 26, // requires 1 bit, ignored. + kIsFinite_SerializationShift = 25, // requires 1 bit + kLegacyIsOval_SerializationShift = 24, // requires 1 bit, ignored. + kSegmentMask_SerializationShift = 0 // requires 4 bits (deprecated) + }; + + SkPathRef(int numVerbs = 0, int numPoints = 0, int numConics = 0) { + fBoundsIsDirty = true; // this also invalidates fIsFinite + fGenerationID = kEmptyGenID; + fSegmentMask = 0; + fType = PathType::kGeneral; + // The next two values don't matter unless fType is kOval or kRRect + fRRectOrOvalIsCCW = false; + fRRectOrOvalStartIdx = 0xAC; + fArcOval.setEmpty(); + fArcStartAngle = fArcSweepAngle = 0.0f; + fArcType = SkArc::Type::kArc; + if (numPoints > 0) { + fPoints.reserve_exact(numPoints); + } + if (numVerbs > 0) { + fVerbs.reserve_exact(numVerbs); + } + if (numConics > 0) { + fConicWeights.reserve_exact(numConics); + } + SkDEBUGCODE(fEditorsAttached.store(0);) + SkDEBUGCODE(this->validate();) + } + + void copy(const SkPathRef& ref, int additionalReserveVerbs, int additionalReservePoints, int additionalReserveConics); + + // Return true if the computed bounds are finite. + static bool ComputePtBounds(SkRect* bounds, const SkPathRef& ref) { + return bounds->setBoundsCheck(ref.points(), ref.countPoints()); + } + + // called, if dirty, by getBounds() + void computeBounds() const { + SkDEBUGCODE(this->validate();) + // TODO: remove fBoundsIsDirty and fIsFinite, + // using an inverted rect instead of fBoundsIsDirty and always recalculating fIsFinite. + SkASSERT(fBoundsIsDirty); + + fIsFinite = ComputePtBounds(&fBounds, *this); + fBoundsIsDirty = false; + } + + void setBounds(const SkRect& rect) { + SkASSERT(rect.fLeft <= rect.fRight && rect.fTop <= rect.fBottom); + fBounds = rect; + fBoundsIsDirty = false; + fIsFinite = fBounds.isFinite(); + } + + /** Makes additional room but does not change the counts or change the genID */ + void incReserve(int additionalVerbs, int additionalPoints, int additionalConics) { + SkDEBUGCODE(this->validate();) + // Use reserve() so that if there is not enough space, the array will grow with some + // additional space. This ensures repeated calls to grow won't always allocate. + if (additionalPoints > 0) { + fPoints.reserve(fPoints.size() + additionalPoints); + } + if (additionalVerbs > 0) { + fVerbs.reserve(fVerbs.size() + additionalVerbs); + } + if (additionalConics > 0) { + fConicWeights.reserve(fConicWeights.size() + additionalConics); + } + SkDEBUGCODE(this->validate();) + } + + /** + * Resets all state except that of the verbs, points, and conic-weights. + * Intended to be called from other functions that reset state. + */ + void commonReset() { + SkDEBUGCODE(this->validate();) + this->callGenIDChangeListeners(); + fBoundsIsDirty = true; // this also invalidates fIsFinite + fGenerationID = 0; + + fSegmentMask = 0; + fType = PathType::kGeneral; + } + + /** Resets the path ref with verbCount verbs and pointCount points, all uninitialized. Also + * allocates space for reserveVerb additional verbs and reservePoints additional points.*/ + void resetToSize(int verbCount, int pointCount, int conicCount, + int reserveVerbs = 0, int reservePoints = 0, + int reserveConics = 0) { + this->commonReset(); + // Use reserve_exact() so the arrays are sized to exactly fit the data. + fPoints.reserve_exact(pointCount + reservePoints); + fPoints.resize_back(pointCount); + + fVerbs.reserve_exact(verbCount + reserveVerbs); + fVerbs.resize_back(verbCount); + + fConicWeights.reserve_exact(conicCount + reserveConics); + fConicWeights.resize_back(conicCount); + SkDEBUGCODE(this->validate();) + } + + /** + * Increases the verb count by numVbs and point count by the required amount. + * The new points are uninitialized. All the new verbs are set to the specified + * verb. If 'verb' is kConic_Verb, 'weights' will return a pointer to the + * uninitialized conic weights. + */ + SkPoint* growForRepeatedVerb(int /*SkPath::Verb*/ verb, int numVbs, SkScalar** weights); + + /** + * Increases the verb count 1, records the new verb, and creates room for the requisite number + * of additional points. A pointer to the first point is returned. Any new points are + * uninitialized. + */ + SkPoint* growForVerb(int /*SkPath::Verb*/ verb, SkScalar weight); + + /** + * Concatenates all verbs from 'path' onto our own verbs array. Increases the point count by the + * number of points in 'path', and the conic weight count by the number of conics in 'path'. + * + * Returns pointers to the uninitialized points and conic weights data. + */ + std::tuple growForVerbsInPath(const SkPathRef& path); + + /** + * Private, non-const-ptr version of the public function verbsMemBegin(). + */ + uint8_t* verbsBeginWritable() { return fVerbs.begin(); } + + /** + * Called the first time someone calls CreateEmpty to actually create the singleton. + */ + friend SkPathRef* sk_create_empty_pathref(); + + void setIsOval(bool isCCW, unsigned start, bool isClosed) { + fType = isClosed ? PathType::kOval : PathType::kOpenOval; + fRRectOrOvalIsCCW = isCCW; + fRRectOrOvalStartIdx = SkToU8(start); + } + + void setIsRRect(bool isCCW, unsigned start) { + fType = PathType::kRRect; + fRRectOrOvalIsCCW = isCCW; + fRRectOrOvalStartIdx = SkToU8(start); + } + + void setIsArc(const SkArc& arc) { + fType = PathType::kArc; + fArcOval = arc.fOval; + fArcStartAngle = arc.fStartAngle; + fArcSweepAngle = arc.fSweepAngle; + fArcType = arc.fType; + } + + // called only by the editor. Note that this is not a const function. + SkPoint* getWritablePoints() { + SkDEBUGCODE(this->validate();) + fType = PathType::kGeneral; + return fPoints.begin(); + } + + const SkPoint* getPoints() const { + SkDEBUGCODE(this->validate();) + return fPoints.begin(); + } + + void callGenIDChangeListeners(); + + mutable SkRect fBounds; + + enum { + kEmptyGenID = 1, // GenID reserved for path ref with zero points and zero verbs. + }; + mutable uint32_t fGenerationID; + SkIDChangeListener::List fGenIDChangeListeners; + + PointsArray fPoints; + VerbsArray fVerbs; + ConicWeightsArray fConicWeights; + + SkDEBUGCODE(std::atomic fEditorsAttached;) // assert only one editor in use at any time. + + mutable uint8_t fBoundsIsDirty; + mutable bool fIsFinite; // only meaningful if bounds are valid + + PathType fType; + // Both the circle and rrect special cases have a notion of direction and starting point + // The next two variables store that information for either. + bool fRRectOrOvalIsCCW; + uint8_t fRRectOrOvalStartIdx; + uint8_t fSegmentMask; + // If the path is an arc, these four variables store that information. + // We should just store an SkArc, but alignment would cost us 8 more bytes. + SkArc::Type fArcType; + SkRect fArcOval; + SkScalar fArcStartAngle; + SkScalar fArcSweepAngle; + + friend class PathRefTest_Private; + friend class ForceIsRRect_Private; // unit test isRRect + friend class SkPath; + friend class SkPathBuilder; + friend class SkPathPriv; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkSLSampleUsage.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkSLSampleUsage.h new file mode 100644 index 0000000000..39d9e25818 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkSLSampleUsage.h @@ -0,0 +1,85 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSLSampleUsage_DEFINED +#define SkSLSampleUsage_DEFINED + +#include "include/core/SkTypes.h" + +namespace SkSL { + +/** + * Represents all of the ways that a fragment processor is sampled by its parent. + */ +class SampleUsage { +public: + enum class Kind { + // Child is never sampled + kNone, + // Child is only sampled at the same coordinates as the parent + kPassThrough, + // Child is sampled with a matrix whose value is uniform + kUniformMatrix, + // Child is sampled with sk_FragCoord.xy + kFragCoord, + // Child is sampled using explicit coordinates + kExplicit, + }; + + // Make a SampleUsage that corresponds to no sampling of the child at all + SampleUsage() = default; + + SampleUsage(Kind kind, bool hasPerspective) : fKind(kind), fHasPerspective(hasPerspective) { + if (kind != Kind::kUniformMatrix) { + SkASSERT(!fHasPerspective); + } + } + + // Child is sampled with a matrix whose value is uniform. The name is fixed. + static SampleUsage UniformMatrix(bool hasPerspective) { + return SampleUsage(Kind::kUniformMatrix, hasPerspective); + } + + static SampleUsage Explicit() { + return SampleUsage(Kind::kExplicit, false); + } + + static SampleUsage PassThrough() { + return SampleUsage(Kind::kPassThrough, false); + } + + static SampleUsage FragCoord() { return SampleUsage(Kind::kFragCoord, false); } + + bool operator==(const SampleUsage& that) const { + return fKind == that.fKind && fHasPerspective == that.fHasPerspective; + } + + bool operator!=(const SampleUsage& that) const { return !(*this == that); } + + // Arbitrary name used by all uniform sampling matrices + static const char* MatrixUniformName() { return "matrix"; } + + SampleUsage merge(const SampleUsage& other); + + Kind kind() const { return fKind; } + + bool hasPerspective() const { return fHasPerspective; } + + bool isSampled() const { return fKind != Kind::kNone; } + bool isPassThrough() const { return fKind == Kind::kPassThrough; } + bool isExplicit() const { return fKind == Kind::kExplicit; } + bool isUniformMatrix() const { return fKind == Kind::kUniformMatrix; } + bool isFragCoord() const { return fKind == Kind::kFragCoord; } + +private: + Kind fKind = Kind::kNone; + bool fHasPerspective = false; // Only valid if fKind is kUniformMatrix +}; + +} // namespace SkSL + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkWeakRefCnt.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkWeakRefCnt.h new file mode 100644 index 0000000000..4f949a4843 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkWeakRefCnt.h @@ -0,0 +1,173 @@ +/* + * 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 SkWeakRefCnt_DEFINED +#define SkWeakRefCnt_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" + +#include +#include + +/** \class SkWeakRefCnt + + SkWeakRefCnt is the base class for objects that may be shared by multiple + objects. When an existing strong owner wants to share a reference, it calls + ref(). When a strong owner wants to release its reference, it calls + unref(). When the shared object's strong reference count goes to zero as + the result of an unref() call, its (virtual) weak_dispose method 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. + + In addition to strong ownership, an owner may instead obtain a weak + reference by calling weak_ref(). A call to weak_ref() must be balanced by a + call to weak_unref(). To obtain a strong reference from a weak reference, + call try_ref(). If try_ref() returns true, the owner's pointer is now also + a strong reference on which unref() must be called. Note that this does not + affect the original weak reference, weak_unref() must still be called. When + the weak reference count goes to zero, the object is deleted. While the + weak reference count is positive and the strong reference count is zero the + object still exists, but will be in the disposed state. It is up to the + object to define what this means. + + Note that a strong reference implicitly implies a weak reference. As a + result, it is allowable for the owner of a strong ref to call try_ref(). + This will have the same effect as calling ref(), but may be more expensive. + + Example: + + SkWeakRefCnt myRef = strongRef.weak_ref(); + ... // strongRef.unref() may or may not be called + if (myRef.try_ref()) { + ... // use myRef + myRef.unref(); + } else { + // myRef is in the disposed state + } + myRef.weak_unref(); +*/ +class SK_API SkWeakRefCnt : public SkRefCnt { +public: + /** Default construct, initializing the reference counts to 1. + The strong references collectively hold one weak reference. When the + strong reference count goes to zero, the collectively held weak + reference is released. + */ + SkWeakRefCnt() : SkRefCnt(), fWeakCnt(1) {} + + /** Destruct, asserting that the weak reference count is 1. + */ + ~SkWeakRefCnt() override { +#ifdef SK_DEBUG + SkASSERT(getWeakCnt() == 1); + fWeakCnt.store(0, std::memory_order_relaxed); +#endif + } + +#ifdef SK_DEBUG + /** Return the weak reference count. */ + int32_t getWeakCnt() const { + return fWeakCnt.load(std::memory_order_relaxed); + } +#endif + +private: + /** If fRefCnt is 0, returns 0. + * Otherwise increments fRefCnt, acquires, and returns the old value. + */ + int32_t atomic_conditional_acquire_strong_ref() const { + int32_t prev = fRefCnt.load(std::memory_order_relaxed); + do { + if (0 == prev) { + break; + } + } while(!fRefCnt.compare_exchange_weak(prev, prev+1, std::memory_order_acquire, + std::memory_order_relaxed)); + return prev; + } + +public: + /** Creates a strong reference from a weak reference, if possible. The + caller must already be an owner. If try_ref() returns true the owner + is in posession of an additional strong reference. Both the original + reference and new reference must be properly unreferenced. If try_ref() + returns false, no strong reference could be created and the owner's + reference is in the same state as before the call. + */ + [[nodiscard]] bool try_ref() const { + if (atomic_conditional_acquire_strong_ref() != 0) { + // Acquire barrier (L/SL), if not provided above. + // Prevents subsequent code from happening before the increment. + return true; + } + return false; + } + + /** Increment the weak reference count. Must be balanced by a call to + weak_unref(). + */ + void weak_ref() const { + SkASSERT(getRefCnt() > 0); + SkASSERT(getWeakCnt() > 0); + // No barrier required. + (void)fWeakCnt.fetch_add(+1, std::memory_order_relaxed); + } + + /** Decrement the weak reference count. If the weak reference count is 1 + before the decrement, then call delete on 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 weak_unref() const { + SkASSERT(getWeakCnt() > 0); + // A release here acts in place of all releases we "should" have been doing in ref(). + if (1 == fWeakCnt.fetch_add(-1, std::memory_order_acq_rel)) { + // Like try_ref(), the acquire is only needed on success, to make sure + // code in internal_dispose() doesn't happen before the decrement. +#ifdef SK_DEBUG + // so our destructor won't complain + fWeakCnt.store(1, std::memory_order_relaxed); +#endif + this->INHERITED::internal_dispose(); + } + } + + /** Returns true if there are no strong references to the object. When this + is the case all future calls to try_ref() will return false. + */ + bool weak_expired() const { + return fRefCnt.load(std::memory_order_relaxed) == 0; + } + +protected: + /** Called when the strong reference count goes to zero. This allows the + object to free any resources it may be holding. Weak references may + still exist and their level of allowed access to the object is defined + by the object's class. + */ + virtual void weak_dispose() const { + } + +private: + /** Called when the strong reference count goes to zero. Calls weak_dispose + on the object and releases the implicit weak reference held + collectively by the strong references. + */ + void internal_dispose() const override { + weak_dispose(); + weak_unref(); + } + + /* Invariant: fWeakCnt = #weak + (fRefCnt > 0 ? 1 : 0) */ + mutable std::atomic fWeakCnt; + + using INHERITED = SkRefCnt; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkXmp.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkXmp.h new file mode 100644 index 0000000000..58ae2338d6 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/SkXmp.h @@ -0,0 +1,62 @@ +/* + * Copyright 2023 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkXmp_DEFINED +#define SkXmp_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/private/base/SkAPI.h" + +class SkData; +struct SkGainmapInfo; + +#include +#include + +/* + * An interface to extract information from XMP metadata. + */ +class SK_API SkXmp { +public: + SkXmp() = default; + virtual ~SkXmp() = default; + // Make noncopyable + SkXmp(const SkXmp&) = delete; + SkXmp& operator= (const SkXmp&) = delete; + + // Create from XMP data. + static std::unique_ptr Make(sk_sp xmpData); + // Create from standard XMP + extended XMP data, see XMP Specification Part 3: Storage in files, + // Section 1.1.3.1: Extended XMP in JPEG + static std::unique_ptr Make(sk_sp xmpStandard, sk_sp xmpExtended); + + // Extract HDRGM gainmap parameters. + // TODO(b/338342146): Remove this once all callers are removed. + bool getGainmapInfoHDRGM(SkGainmapInfo* info) const { return getGainmapInfoAdobe(info); } + + // Extract gainmap parameters from http://ns.adobe.com/hdr-gain-map/1.0/. + virtual bool getGainmapInfoAdobe(SkGainmapInfo* info) const = 0; + + // If the image specifies http://ns.apple.com/pixeldatainfo/1.0/ AuxiliaryImageType of + // urn:com:apple:photo:2020:aux:hdrgainmap, and includes a http://ns.apple.com/HDRGainMap/1.0/ + // HDRGainMapVersion, then populate |info| with gainmap parameters that will approximate the + // math specified at [0] and return true. + // [0] https://developer.apple.com/documentation/appkit/images_and_pdf/ + // applying_apple_hdr_effect_to_your_photos + virtual bool getGainmapInfoApple(float exifHdrHeadroom, SkGainmapInfo* info) const = 0; + + // If this includes GContainer metadata and the GContainer contains an item with semantic + // GainMap and Mime of image/jpeg, then return true, and populate |offset| and |size| with + // that item's offset (from the end of the primary JPEG image's EndOfImage), and the size of + // the gainmap. + virtual bool getContainerGainmapLocation(size_t* offset, size_t* size) const = 0; + + // Return the GUID of an Extended XMP if present, or null otherwise. + virtual const char* getExtendedXmpGuid() const = 0; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/README.md b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/README.md new file mode 100644 index 0000000000..7f4f17b228 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/README.md @@ -0,0 +1,4 @@ +Files in "base" are used by many parts of Skia, but are not part of the public Skia API. +See also src/base for other files that are part of base, but not needed by the public API. + +Files here should not depend on anything other than system headers or other files in base. \ No newline at end of file diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SingleOwner.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SingleOwner.h new file mode 100644 index 0000000000..473981e1fb --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SingleOwner.h @@ -0,0 +1,75 @@ +/* + * 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 skgpu_SingleOwner_DEFINED +#define skgpu_SingleOwner_DEFINED + +#include "include/private/base/SkDebug.h" // IWYU pragma: keep + +#if defined(SK_DEBUG) +#include "include/private/base/SkAssert.h" +#include "include/private/base/SkMutex.h" +#include "include/private/base/SkThreadAnnotations.h" +#include "include/private/base/SkThreadID.h" + +#endif + +namespace skgpu { + +#if defined(SK_DEBUG) + +#define SKGPU_ASSERT_SINGLE_OWNER(obj) \ + skgpu::SingleOwner::AutoEnforce debug_SingleOwner(obj, __FILE__, __LINE__); + +// This is a debug tool to verify an object is only being used from one thread at a time. +class SingleOwner { +public: + SingleOwner() : fOwner(kIllegalThreadID), fReentranceCount(0) {} + + struct AutoEnforce { + AutoEnforce(SingleOwner* so, const char* file, int line) + : fFile(file), fLine(line), fSO(so) { + fSO->enter(file, line); + } + ~AutoEnforce() { fSO->exit(fFile, fLine); } + + const char* fFile; + int fLine; + SingleOwner* fSO; + }; + +private: + void enter(const char* file, int line) { + SkAutoMutexExclusive lock(fMutex); + SkThreadID self = SkGetThreadID(); + SkASSERTF(fOwner == self || fOwner == kIllegalThreadID, "%s:%d Single owner failure.", + file, line); + fReentranceCount++; + fOwner = self; + } + + void exit(const char* file, int line) { + SkAutoMutexExclusive lock(fMutex); + SkASSERTF(fOwner == SkGetThreadID(), "%s:%d Single owner failure.", file, line); + fReentranceCount--; + if (fReentranceCount == 0) { + fOwner = kIllegalThreadID; + } + } + + SkMutex fMutex; + SkThreadID fOwner SK_GUARDED_BY(fMutex); + int fReentranceCount SK_GUARDED_BY(fMutex); +}; +#else +#define SKGPU_ASSERT_SINGLE_OWNER(obj) +class SingleOwner {}; // Provide a no-op implementation so we can pass pointers to constructors +#endif + +} // namespace skgpu + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkAPI.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkAPI.h new file mode 100644 index 0000000000..4028f95d87 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkAPI.h @@ -0,0 +1,52 @@ +/* + * 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 SkAPI_DEFINED +#define SkAPI_DEFINED + +#include "include/private/base/SkLoadUserConfig.h" // IWYU pragma: keep + +// If SKIA_IMPLEMENTATION is defined as 1, that signals we are building Skia and should +// export our symbols. If it is not set (or set to 0), then Skia is being used by a client +// and we should not export our symbols. +#if !defined(SKIA_IMPLEMENTATION) + #define SKIA_IMPLEMENTATION 0 +#endif + +// If we are compiling Skia is being as a DLL, we need to be sure to export all of our public +// APIs to that DLL. If a client is using Skia which was compiled as a DLL, we need to instruct +// the linker to use the symbols from that DLL. This is the goal of the SK_API define. +#if !defined(SK_API) + #if defined(SKIA_DLL) + #if defined(_MSC_VER) + #if SKIA_IMPLEMENTATION + #define SK_API __declspec(dllexport) + #else + #define SK_API __declspec(dllimport) + #endif + #else + #define SK_API __attribute__((visibility("default"))) + #endif + #else + #define SK_API + #endif +#endif + +// SK_SPI is functionally identical to SK_API, but used within src to clarify that it's less stable +#if !defined(SK_SPI) + #define SK_SPI SK_API +#endif + +// See https://clang.llvm.org/docs/AttributeReference.html#availability +// The API_AVAILABLE macro comes from on MacOS +#if defined(SK_ENABLE_API_AVAILABLE) +# define SK_API_AVAILABLE API_AVAILABLE +#else +# define SK_API_AVAILABLE(...) +#endif + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkASAN.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkASAN.h new file mode 100644 index 0000000000..095f71608d --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkASAN.h @@ -0,0 +1,56 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkASAN_DEFINED +#define SkASAN_DEFINED + +#include + +#ifdef __SANITIZE_ADDRESS__ + #define SK_SANITIZE_ADDRESS 1 +#endif +#if !defined(SK_SANITIZE_ADDRESS) && defined(__has_feature) + #if __has_feature(address_sanitizer) + #define SK_SANITIZE_ADDRESS 1 + #endif +#endif + +// Typically declared in LLVM's asan_interface.h. +#ifdef SK_SANITIZE_ADDRESS +extern "C" { + void __asan_poison_memory_region(void const volatile *addr, size_t size); + void __asan_unpoison_memory_region(void const volatile *addr, size_t size); + int __asan_address_is_poisoned(void const volatile *addr); +} +#endif + +// Code that implements bespoke allocation arenas can poison the entire arena on creation, then +// unpoison chunks of arena memory as they are parceled out. Consider leaving gaps between blocks +// to detect buffer overrun. +static inline void sk_asan_poison_memory_region([[maybe_unused]] void const volatile* addr, + [[maybe_unused]] size_t size) { +#ifdef SK_SANITIZE_ADDRESS + __asan_poison_memory_region(addr, size); +#endif +} + +static inline void sk_asan_unpoison_memory_region([[maybe_unused]] void const volatile* addr, + [[maybe_unused]] size_t size) { +#ifdef SK_SANITIZE_ADDRESS + __asan_unpoison_memory_region(addr, size); +#endif +} + +static inline int sk_asan_address_is_poisoned([[maybe_unused]] void const volatile* addr) { +#ifdef SK_SANITIZE_ADDRESS + return __asan_address_is_poisoned(addr); +#else + return 0; +#endif +} + +#endif // SkASAN_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkAlign.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkAlign.h new file mode 100644 index 0000000000..2b2138ddd4 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkAlign.h @@ -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 SkAlign_DEFINED +#define SkAlign_DEFINED + +#include "include/private/base/SkAssert.h" + +#include + +template static constexpr T SkAlign2(T x) { return (x + 1) >> 1 << 1; } +template static constexpr T SkAlign4(T x) { return (x + 3) >> 2 << 2; } +template static constexpr T SkAlign8(T x) { return (x + 7) >> 3 << 3; } + +template static constexpr bool SkIsAlign2(T x) { return 0 == (x & 1); } +template static constexpr bool SkIsAlign4(T x) { return 0 == (x & 3); } +template static constexpr bool SkIsAlign8(T x) { return 0 == (x & 7); } + +template static constexpr T SkAlignPtr(T x) { + return sizeof(void*) == 8 ? SkAlign8(x) : SkAlign4(x); +} +template static constexpr bool SkIsAlignPtr(T x) { + return sizeof(void*) == 8 ? SkIsAlign8(x) : SkIsAlign4(x); +} + +/** + * align up to a power of 2 + */ +static inline constexpr size_t SkAlignTo(size_t x, size_t alignment) { + // The same as alignment && SkIsPow2(value), w/o a dependency cycle. + SkASSERT(alignment && (alignment & (alignment - 1)) == 0); + return (x + alignment - 1) & ~(alignment - 1); +} + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkAlignedStorage.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkAlignedStorage.h new file mode 100644 index 0000000000..532ad03978 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkAlignedStorage.h @@ -0,0 +1,32 @@ +// 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 SkAlignedStorage_DEFINED +#define SkAlignedStorage_DEFINED + +#include +#include + +template class SkAlignedSTStorage { +public: + SkAlignedSTStorage() {} + SkAlignedSTStorage(SkAlignedSTStorage&&) = delete; + SkAlignedSTStorage(const SkAlignedSTStorage&) = delete; + SkAlignedSTStorage& operator=(SkAlignedSTStorage&&) = delete; + SkAlignedSTStorage& operator=(const SkAlignedSTStorage&) = delete; + + // Returns void* because this object does not initialize the + // memory. Use placement new for types that require a constructor. + void* get() { return fStorage; } + const void* get() const { return fStorage; } + + // Act as a container of bytes because the storage is uninitialized. + std::byte* data() { return fStorage; } + const std::byte* data() const { return fStorage; } + size_t size() const { return std::size(fStorage); } + +private: + alignas(T) std::byte fStorage[sizeof(T) * N]; +}; + +#endif // SkAlignedStorage_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkAnySubclass.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkAnySubclass.h new file mode 100644 index 0000000000..2b666cbdb1 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkAnySubclass.h @@ -0,0 +1,73 @@ +/* + * 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 SkAnySubclass_DEFINED +#define SkAnySubclass_DEFINED + +#include "include/private/base/SkAssert.h" + +#include +#include +#include // IWYU pragma: keep +#include + +/** + * Stores any subclass `T` of `Base`, where sizeof(T) <= `Size`, without using the heap. + * Doesn't need advance knowledge of T, so it's particularly suited to platform or backend + * implementations of a generic interface, where the set of possible subclasses is finite and + * known, but can't be made available at compile-time. + */ +template +class SkAnySubclass { +public: + SkAnySubclass() = default; + ~SkAnySubclass() { + this->reset(); + } + + SkAnySubclass(const SkAnySubclass&) = delete; + SkAnySubclass& operator=(const SkAnySubclass&) = delete; + SkAnySubclass(SkAnySubclass&&) = delete; + SkAnySubclass& operator=(SkAnySubclass&&) = delete; + + template + void emplace(Args&&... args) { + static_assert(std::is_base_of_v); + static_assert(sizeof(T) <= Size); + // We're going to clean up our stored object by calling ~Base: + static_assert(std::has_virtual_destructor_v || std::is_trivially_destructible_v); + SkASSERT(!fValid); + new (fData) T(std::forward(args)...); + fValid = true; + } + + void reset() { + if (fValid) { + this->get()->~Base(); + } + fValid = false; + } + + const Base* get() const { + SkASSERT(fValid); + return std::launder(reinterpret_cast(fData)); + } + + Base* get() { + SkASSERT(fValid); + return std::launder(reinterpret_cast(fData)); + } + + Base* operator->() { return this->get(); } + const Base* operator->() const { return this->get(); } + +private: + alignas(8) std::byte fData[Size]; + bool fValid = false; +}; + +#endif // SkAnySubclass_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkAssert.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkAssert.h new file mode 100644 index 0000000000..67b31213dd --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkAssert.h @@ -0,0 +1,202 @@ +/* + * 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 SkAssert_DEFINED +#define SkAssert_DEFINED + +#include "include/private/base/SkAPI.h" +#include "include/private/base/SkAttributes.h" +#include "include/private/base/SkDebug.h" // IWYU pragma: keep + +#include +#include + +#if defined(__clang__) && defined(__has_attribute) + #if __has_attribute(likely) + #define SK_LIKELY [[likely]] + #define SK_UNLIKELY [[unlikely]] + #else + #define SK_LIKELY + #define SK_UNLIKELY + #endif +#else + #define SK_LIKELY + #define SK_UNLIKELY +#endif + +// c++23 will give us [[assume]] -- until then we're stuck with various other options: +#if defined(__clang__) + #define SK_ASSUME(cond) __builtin_assume(cond) +#elif defined(__GNUC__) + #if __GNUC__ >= 13 + #define SK_ASSUME(cond) __attribute__((assume(cond))) + #else + // NOTE: This implementation could actually evaluate `cond`, which is not desirable. + #define SK_ASSUME(cond) ((cond) ? (void)0 : __builtin_unreachable()) + #endif +#elif defined(_MSC_VER) + #define SK_ASSUME(cond) __assume(cond) +#else + #define SK_ASSUME(cond) ((void)0) +#endif + +/** Called internally if we hit an unrecoverable error. + The platform implementation must not return, but should either throw + an exception or otherwise exit. +*/ +[[noreturn]] SK_API extern void sk_abort_no_print(void); + +#if defined(SK_BUILD_FOR_GOOGLE3) + void SkDebugfForDumpStackTrace(const char* data, void* unused); + namespace base { + void DumpStackTrace(int skip_count, void w(const char*, void*), void* arg); + } +# define SK_DUMP_GOOGLE3_STACK() ::base::DumpStackTrace(0, SkDebugfForDumpStackTrace, nullptr) +#else +# define SK_DUMP_GOOGLE3_STACK() +#endif + +#if !defined(SK_ABORT) +# if defined(SK_BUILD_FOR_WIN) + // This style lets Visual Studio follow errors back to the source file. +# define SK_DUMP_LINE_FORMAT "%s(%d)" +# else +# define SK_DUMP_LINE_FORMAT "%s:%d" +# endif +# define SK_ABORT(message, ...) \ + do { \ + SkDebugf(SK_DUMP_LINE_FORMAT ": fatal error: \"" message "\"\n", \ + __FILE__, __LINE__, ##__VA_ARGS__); \ + SK_DUMP_GOOGLE3_STACK(); \ + sk_abort_no_print(); \ + } while (false) +#endif + +// SkASSERT, SkASSERTF and SkASSERT_RELEASE can be used as standalone assertion expressions, e.g. +// uint32_t foo(int x) { +// SkASSERT(x > 4); +// return x - 4; +// } +// and are also written to be compatible with constexpr functions: +// constexpr uint32_t foo(int x) { +// return SkASSERT(x > 4), +// x - 4; +// } +#if defined(__clang__) +#define SkASSERT_RELEASE(cond) \ + static_cast( __builtin_expect(static_cast(cond), 1) \ + ? static_cast(0) \ + : []{ SK_ABORT("check(%s)", #cond); }() ) + +#define SkASSERTF_RELEASE(cond, fmt, ...) \ + static_cast( __builtin_expect(static_cast(cond), 1) \ + ? static_cast(0) \ + : [&]{ SK_ABORT("assertf(%s): " fmt, #cond, ##__VA_ARGS__); }() ) +#else +#define SkASSERT_RELEASE(cond) \ + static_cast( (cond) ? static_cast(0) : []{ SK_ABORT("check(%s)", #cond); }() ) + +#define SkASSERTF_RELEASE(cond, fmt, ...) \ + static_cast( (cond) \ + ? static_cast(0) \ + : [&]{ SK_ABORT("assertf(%s): " fmt, #cond, ##__VA_ARGS__); }() ) +#endif + +#if defined(SK_DEBUG) + #define SkASSERT(cond) SkASSERT_RELEASE(cond) + #define SkASSERTF(cond, fmt, ...) SkASSERTF_RELEASE(cond, fmt, ##__VA_ARGS__) + #define SkDEBUGFAIL(message) SK_ABORT("%s", message) + #define SkDEBUGFAILF(fmt, ...) SK_ABORT(fmt, ##__VA_ARGS__) + #define SkAssertResult(cond) SkASSERT(cond) +#else + #define SkASSERT(cond) static_cast(0) + #define SkASSERTF(cond, fmt, ...) static_cast(0) + #define SkDEBUGFAIL(message) + #define SkDEBUGFAILF(fmt, ...) + + // unlike SkASSERT, this macro executes its condition in the non-debug build. + // The if is present so that this can be used with functions marked [[nodiscard]]. + #define SkAssertResult(cond) if (cond) {} do {} while(false) +#endif + +#if !defined(SkUNREACHABLE) +# if defined(_MSC_VER) && !defined(__clang__) +# include +# define FAST_FAIL_INVALID_ARG 5 +// See https://developercommunity.visualstudio.com/content/problem/1128631/code-flow-doesnt-see-noreturn-with-extern-c.html +// for why this is wrapped. Hopefully removable after msvc++ 19.27 is no longer supported. +[[noreturn]] static inline void sk_fast_fail() { __fastfail(FAST_FAIL_INVALID_ARG); } +# define SkUNREACHABLE sk_fast_fail() +# else +# define SkUNREACHABLE __builtin_trap() +# endif +#endif + +[[noreturn]] SK_API inline void sk_print_index_out_of_bounds(size_t i, size_t size) { + SK_ABORT("Index (%zu) out of bounds for size %zu.\n", i, size); +} + +template SK_API inline T sk_collection_check_bounds(T i, T size) { + if (0 <= i && i < size) SK_LIKELY { + return i; + } + + SK_UNLIKELY { + #if defined(SK_DEBUG) + sk_print_index_out_of_bounds(static_cast(i), static_cast(size)); + #else + SkUNREACHABLE; + #endif + } +} + +[[noreturn]] SK_API inline void sk_print_length_too_big(size_t i, size_t size) { + SK_ABORT("Length (%zu) is too big for size %zu.\n", i, size); +} + +template SK_API inline T sk_collection_check_length(T i, T size) { + if (0 <= i && i <= size) SK_LIKELY { + return i; + } + + SK_UNLIKELY { + #if defined(SK_DEBUG) + sk_print_length_too_big(static_cast(i), static_cast(size)); + #else + SkUNREACHABLE; + #endif + } +} + +SK_API inline void sk_collection_not_empty(bool empty) { + if (empty) SK_UNLIKELY { + #if defined(SK_DEBUG) + SK_ABORT("Collection is empty.\n"); + #else + SkUNREACHABLE; + #endif + } +} + +[[noreturn]] SK_API inline void sk_print_size_too_big(size_t size, size_t maxSize) { + SK_ABORT("Size (%zu) can't be represented in bytes. Max size is %zu.\n", size, maxSize); +} + +template +SK_ALWAYS_INLINE size_t check_size_bytes_too_big(size_t size) { + const size_t kMaxSize = std::numeric_limits::max() / sizeof(T); + if (size > kMaxSize) { + #if defined(SK_DEBUG) + sk_print_size_too_big(size, kMaxSize); + #else + SkUNREACHABLE; + #endif + } + return size; +} + +#endif // SkAssert_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkAttributes.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkAttributes.h new file mode 100644 index 0000000000..f8df5905cd --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkAttributes.h @@ -0,0 +1,90 @@ +/* + * 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 SkAttributes_DEFINED +#define SkAttributes_DEFINED + +#include "include/private/base/SkFeatures.h" // IWYU pragma: keep +#include "include/private/base/SkLoadUserConfig.h" // IWYU pragma: keep + +#if defined(__clang__) || defined(__GNUC__) +# define SK_ATTRIBUTE(attr) __attribute__((attr)) +#else +# define SK_ATTRIBUTE(attr) +#endif + +/** + * If your judgment is better than the compiler's (i.e. you've profiled it), + * you can use SK_ALWAYS_INLINE to force inlining. E.g. + * inline void someMethod() { ... } // may not be inlined + * SK_ALWAYS_INLINE void someMethod() { ... } // should always be inlined + */ +#if !defined(SK_ALWAYS_INLINE) +# if defined(SK_BUILD_FOR_WIN) +# define SK_ALWAYS_INLINE __forceinline +# else +# define SK_ALWAYS_INLINE SK_ATTRIBUTE(always_inline) inline +# endif +#endif + +/** + * If your judgment is better than the compiler's (i.e. you've profiled it), + * you can use SK_NEVER_INLINE to prevent inlining. + */ +#if !defined(SK_NEVER_INLINE) +# if defined(SK_BUILD_FOR_WIN) +# define SK_NEVER_INLINE __declspec(noinline) +# else +# define SK_NEVER_INLINE SK_ATTRIBUTE(noinline) +# endif +#endif + +/** + * Used to annotate a function as taking printf style arguments. + * `A` is the (1 based) index of the format string argument. + * `B` is the (1 based) index of the first argument used by the format string. + */ +#if !defined(SK_PRINTF_LIKE) +# define SK_PRINTF_LIKE(A, B) SK_ATTRIBUTE(format(printf, (A), (B))) +#endif + +/** + * Used to ignore sanitizer warnings. + */ +#if !defined(SK_NO_SANITIZE) +# define SK_NO_SANITIZE(A) SK_ATTRIBUTE(no_sanitize(A)) +#endif + +/** + * Helper macro to define no_sanitize attributes only with clang. + */ +#if defined(__clang__) && defined(__has_attribute) + #if __has_attribute(no_sanitize) + #define SK_CLANG_NO_SANITIZE(A) SK_NO_SANITIZE(A) + #endif +#endif + +#if !defined(SK_CLANG_NO_SANITIZE) + #define SK_CLANG_NO_SANITIZE(A) +#endif + +/** + * Annotates a class' non-trivial special functions as trivial for the purposes of calls. + * Allows a class with a non-trivial destructor to be __is_trivially_relocatable. + * Use of this attribute on a public API breaks platform ABI. + * Annotated classes may not hold pointers derived from `this`. + * Annotated classes must implement move+delete as equivalent to memcpy+free. + * Use may require more complete types, as callee destroys. + * + * https://clang.llvm.org/docs/AttributeReference.html#trivial-abi + * https://libcxx.llvm.org/DesignDocs/UniquePtrTrivialAbi.html + */ +#if !defined(SK_TRIVIAL_ABI) +# define SK_TRIVIAL_ABI +#endif + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkCPUTypes.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkCPUTypes.h new file mode 100644 index 0000000000..a5f60fd3ef --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkCPUTypes.h @@ -0,0 +1,25 @@ +/* + * 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 SkCPUTypes_DEFINED +#define SkCPUTypes_DEFINED + +// TODO(bungeman,kjlubick) There are a lot of assumptions throughout the codebase that +// these types are 32 bits, when they could be more or less. Public APIs should stop +// using these. Internally, we could use uint_fast8_t and uint_fast16_t, but not in +// public APIs due to ABI incompatibilities. + +/** Fast type for unsigned 8 bits. Use for parameter passing and local + variables, not for storage +*/ +typedef unsigned U8CPU; + +/** Fast type for unsigned 16 bits. Use for parameter passing and local + variables, not for storage +*/ +typedef unsigned U16CPU; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkContainers.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkContainers.h new file mode 100644 index 0000000000..587e295efa --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkContainers.h @@ -0,0 +1,54 @@ +// 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 SkContainers_DEFINED +#define SkContainers_DEFINED + +#include "include/private/base/SkAPI.h" +#include "include/private/base/SkAlign.h" +#include "include/private/base/SkSpan_impl.h" + +#include +#include + +class SK_SPI SkContainerAllocator { +public: + SkContainerAllocator(size_t sizeOfT, int maxCapacity) + : fSizeOfT{sizeOfT} + , fMaxCapacity{maxCapacity} {} + + // allocate will abort on failure. Given a capacity of 0, it will return the empty span. + // The bytes allocated are freed using sk_free(). + SkSpan allocate(int capacity, double growthFactor = 1.0); + + // Rounds a requested capacity up towards `kCapacityMultiple` in a constexpr-friendly fashion. + template + static constexpr size_t RoundUp(size_t capacity) { + return SkAlignTo(capacity * sizeof(T), kCapacityMultiple) / sizeof(T); + } + +private: + friend struct SkContainerAllocatorTestingPeer; + + // All capacity counts will be rounded up to kCapacityMultiple. This matches ASAN's shadow + // granularity, as well as our typical struct alignment on a 64-bit machine. + static constexpr int64_t kCapacityMultiple = 8; + + // Rounds up capacity to next multiple of kCapacityMultiple and pin to fMaxCapacity. + size_t roundUpCapacity(int64_t capacity) const; + + // Grows the capacity by growthFactor being sure to stay with in kMinBytes and fMaxCapacity. + size_t growthFactorCapacity(int capacity, double growthFactor) const; + + const size_t fSizeOfT; + const int64_t fMaxCapacity; +}; + +// sk_allocate_canfail returns the empty span on failure. Parameter size must be > 0. +SkSpan sk_allocate_canfail(size_t size); + +// Returns the empty span if size is 0. sk_allocate_throw aborts on failure. +SkSpan sk_allocate_throw(size_t size); + +SK_SPI void sk_report_container_overflow_and_die(); +#endif // SkContainers_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkDebug.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkDebug.h new file mode 100644 index 0000000000..2e4810fc1c --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkDebug.h @@ -0,0 +1,27 @@ +/* + * 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 SkDebug_DEFINED +#define SkDebug_DEFINED + +#include "include/private/base/SkAPI.h" +#include "include/private/base/SkAttributes.h" +#include "include/private/base/SkLoadUserConfig.h" // IWYU pragma: keep + +#if !defined(SkDebugf) + void SK_SPI SkDebugf(const char format[], ...) SK_PRINTF_LIKE(1, 2); +#endif + +#if defined(SK_DEBUG) + #define SkDEBUGCODE(...) __VA_ARGS__ + #define SkDEBUGF(...) SkDebugf(__VA_ARGS__) +#else + #define SkDEBUGCODE(...) + #define SkDEBUGF(...) +#endif + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkDeque.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkDeque.h new file mode 100644 index 0000000000..c7a43c9fe4 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkDeque.h @@ -0,0 +1,138 @@ + +/* + * 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 SkDeque_DEFINED +#define SkDeque_DEFINED + +#include "include/private/base/SkAPI.h" + +#include + +/* + * The deque class works by blindly creating memory space of a specified element + * size. It manages the memory as a doubly linked list of blocks each of which + * can contain multiple elements. Pushes and pops add/remove blocks from the + * beginning/end of the list as necessary while each block tracks the used + * portion of its memory. + * One behavior to be aware of is that the pops do not immediately remove an + * empty block from the beginning/end of the list (Presumably so push/pop pairs + * on the block boundaries don't cause thrashing). This can result in the first/ + * last element not residing in the first/last block. + */ +class SK_API SkDeque { +public: + /** + * elemSize specifies the size of each individual element in the deque + * allocCount specifies how many elements are to be allocated as a block + */ + explicit SkDeque(size_t elemSize, int allocCount = 1); + SkDeque(size_t elemSize, void* storage, size_t storageSize, int allocCount = 1); + ~SkDeque(); + + bool empty() const { return 0 == fCount; } + int count() const { return fCount; } + size_t elemSize() const { return fElemSize; } + + const void* front() const { return fFront; } + const void* back() const { return fBack; } + + void* front() { return fFront; } + void* back() { return fBack; } + + /** + * push_front and push_back return a pointer to the memory space + * for the new element + */ + void* push_front(); + void* push_back(); + + void pop_front(); + void pop_back(); + +private: + struct Block; + +public: + class Iter { + public: + enum IterStart { + kFront_IterStart, + kBack_IterStart, + }; + + /** + * Creates an uninitialized iterator. Must be reset() + */ + Iter(); + + Iter(const SkDeque& d, IterStart startLoc); + void* next(); + void* prev(); + + void reset(const SkDeque& d, IterStart startLoc); + + private: + SkDeque::Block* fCurBlock; + char* fPos; + size_t fElemSize; + }; + + // Inherit privately from Iter to prevent access to reverse iteration + class F2BIter : private Iter { + public: + F2BIter() {} + + /** + * Wrap Iter's 2 parameter ctor to force initialization to the + * beginning of the deque + */ + F2BIter(const SkDeque& d) : INHERITED(d, kFront_IterStart) {} + + using Iter::next; + + /** + * Wrap Iter::reset to force initialization to the beginning of the + * deque + */ + void reset(const SkDeque& d) { + this->INHERITED::reset(d, kFront_IterStart); + } + + private: + using INHERITED = Iter; + }; + +private: + // allow unit test to call numBlocksAllocated + friend class DequeUnitTestHelper; + + void* fFront; + void* fBack; + + Block* fFrontBlock; + Block* fBackBlock; + size_t fElemSize; + void* fInitialStorage; + int fCount; // number of elements in the deque + int fAllocCount; // number of elements to allocate per block + + Block* allocateBlock(int allocCount); + void freeBlock(Block* block); + + /** + * This returns the number of chunk blocks allocated by the deque. It + * can be used to gauge the effectiveness of the selected allocCount. + */ + int numBlocksAllocated() const; + + SkDeque(const SkDeque&) = delete; + SkDeque& operator=(const SkDeque&) = delete; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkFeatures.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkFeatures.h new file mode 100644 index 0000000000..353ce22897 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkFeatures.h @@ -0,0 +1,165 @@ +/* + * 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 SkFeatures_DEFINED +#define SkFeatures_DEFINED + +#if !defined(SK_BUILD_FOR_ANDROID) && !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_WIN) && \ + !defined(SK_BUILD_FOR_UNIX) && !defined(SK_BUILD_FOR_MAC) + + #ifdef __APPLE__ + #include + #endif + + #if defined(_WIN32) || defined(__SYMBIAN32__) + #define SK_BUILD_FOR_WIN + #elif defined(ANDROID) || defined(__ANDROID__) + #define SK_BUILD_FOR_ANDROID + #elif defined(linux) || defined(__linux) || defined(__FreeBSD__) || \ + defined(__OpenBSD__) || defined(__sun) || defined(__NetBSD__) || \ + defined(__DragonFly__) || defined(__Fuchsia__) || \ + defined(__GLIBC__) || defined(__GNU__) || defined(__unix__) + #define SK_BUILD_FOR_UNIX + #elif TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR + #define SK_BUILD_FOR_IOS + #else + #define SK_BUILD_FOR_MAC + #endif +#endif // end SK_BUILD_FOR_* + + +#if defined(SK_BUILD_FOR_WIN) && !defined(__clang__) + #if !defined(SK_RESTRICT) + #define SK_RESTRICT __restrict + #endif +#endif + +#if !defined(SK_RESTRICT) + #define SK_RESTRICT __restrict__ +#endif + +#if !defined(SK_CPU_BENDIAN) && !defined(SK_CPU_LENDIAN) + #if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + #define SK_CPU_BENDIAN + #elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + #define SK_CPU_LENDIAN + #elif defined(__sparc) || defined(__sparc__) || \ + defined(_POWER) || defined(__powerpc__) || \ + defined(__ppc__) || defined(__hppa) || \ + defined(__PPC__) || defined(__PPC64__) || \ + defined(_MIPSEB) || defined(__ARMEB__) || \ + defined(__s390__) || \ + (defined(__sh__) && defined(__BIG_ENDIAN__)) || \ + (defined(__ia64) && defined(__BIG_ENDIAN__)) + #define SK_CPU_BENDIAN + #else + #define SK_CPU_LENDIAN + #endif +#endif + +#if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64) + #define SK_CPU_X86 1 +#endif + +#if defined(__loongarch__) || defined (__loongarch64) + #define SK_CPU_LOONGARCH 1 +#endif + +/** + * SK_CPU_SSE_LEVEL + * + * If defined, SK_CPU_SSE_LEVEL should be set to the highest supported level. + * On non-intel CPU this should be undefined. + */ +#define SK_CPU_SSE_LEVEL_SSE1 10 +#define SK_CPU_SSE_LEVEL_SSE2 20 +#define SK_CPU_SSE_LEVEL_SSE3 30 +#define SK_CPU_SSE_LEVEL_SSSE3 31 +#define SK_CPU_SSE_LEVEL_SSE41 41 +#define SK_CPU_SSE_LEVEL_SSE42 42 +#define SK_CPU_SSE_LEVEL_AVX 51 +#define SK_CPU_SSE_LEVEL_AVX2 52 +#define SK_CPU_SSE_LEVEL_SKX 60 + +/** + * SK_CPU_LSX_LEVEL + * + * If defined, SK_CPU_LSX_LEVEL should be set to the highest supported level. + * On non-loongarch CPU this should be undefined. + */ +#define SK_CPU_LSX_LEVEL_LSX 70 +#define SK_CPU_LSX_LEVEL_LASX 80 + +// TODO(brianosman,kjlubick) clean up these checks + +// Are we in GCC/Clang? +#ifndef SK_CPU_SSE_LEVEL + // These checks must be done in descending order to ensure we set the highest + // available SSE level. + #if defined(__AVX512F__) && defined(__AVX512DQ__) && defined(__AVX512CD__) && \ + defined(__AVX512BW__) && defined(__AVX512VL__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SKX + #elif defined(__AVX2__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX2 + #elif defined(__AVX__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX + #elif defined(__SSE4_2__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE42 + #elif defined(__SSE4_1__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE41 + #elif defined(__SSSE3__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSSE3 + #elif defined(__SSE3__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE3 + #elif defined(__SSE2__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2 + #endif +#endif + +#ifndef SK_CPU_LSX_LEVEL + #if defined(__loongarch_asx) + #define SK_CPU_LSX_LEVEL SK_CPU_LSX_LEVEL_LASX + #elif defined(__loongarch_sx) + #define SK_CPU_LSX_LEVEL SK_CPU_LSX_LEVEL_LSX + #endif +#endif + +// Are we in VisualStudio? +#ifndef SK_CPU_SSE_LEVEL + // These checks must be done in descending order to ensure we set the highest + // available SSE level. 64-bit intel guarantees at least SSE2 support. + #if defined(__AVX512F__) && defined(__AVX512DQ__) && defined(__AVX512CD__) && \ + defined(__AVX512BW__) && defined(__AVX512VL__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SKX + #elif defined(__AVX2__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX2 + #elif defined(__AVX__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX + #elif defined(_M_X64) || defined(_M_AMD64) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2 + #elif defined(_M_IX86_FP) + #if _M_IX86_FP >= 2 + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2 + #elif _M_IX86_FP == 1 + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE1 + #endif + #endif +#endif + +// ARM defines +#if defined(__arm__) && (!defined(__APPLE__) || !TARGET_IPHONE_SIMULATOR) + #define SK_CPU_ARM32 +#elif defined(__aarch64__) + #define SK_CPU_ARM64 +#endif + +// All 64-bit ARM chips have NEON. Many 32-bit ARM chips do too. +#if !defined(SK_ARM_HAS_NEON) && defined(__ARM_NEON) + #define SK_ARM_HAS_NEON +#endif + +#endif // SkFeatures_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkFixed.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkFixed.h new file mode 100644 index 0000000000..2c8f2fb56c --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkFixed.h @@ -0,0 +1,143 @@ +/* + * 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 SkFixed_DEFINED +#define SkFixed_DEFINED + +#include "include/private/base/SkAssert.h" +#include "include/private/base/SkDebug.h" +#include "include/private/base/SkMath.h" // IWYU pragma: keep +#include "include/private/base/SkTPin.h" // IWYU pragma: keep + +#include + +/** \file SkFixed.h + + Types and macros for 16.16 fixed point +*/ + +/** 32 bit signed integer used to represent fractions values with 16 bits to the right of the decimal point +*/ +typedef int32_t SkFixed; +#define SK_Fixed1 (1 << 16) +#define SK_FixedHalf (1 << 15) +#define SK_FixedQuarter (1 << 14) +#define SK_FixedMax (0x7FFFFFFF) +#define SK_FixedMin (-SK_FixedMax) +#define SK_FixedPI (0x3243F) +#define SK_FixedSqrt2 (92682) +#define SK_FixedTanPIOver8 (0x6A0A) +#define SK_FixedRoot2Over2 (0xB505) + +// NOTE: SkFixedToFloat is exact. SkFloatToFixed seems to lack a rounding step. For all fixed-point +// values, this version is as accurate as possible for (fixed -> float -> fixed). Rounding reduces +// accuracy if the intermediate floats are in the range that only holds integers (adding 0.5f to an +// odd integer then snaps to nearest even). Using double for the rounding math gives maximum +// accuracy for (float -> fixed -> float), but that's usually overkill. +#define SkFixedToFloat(x) ((x) * 1.52587890625e-5f) +#define SkFloatToFixed(x) sk_float_saturate2int((x) * SK_Fixed1) + +#ifdef SK_DEBUG + static inline SkFixed SkFloatToFixed_Check(float x) { + int64_t n64 = (int64_t)(x * SK_Fixed1); + SkFixed n32 = (SkFixed)n64; + SkASSERT(n64 == n32); + return n32; + } +#else + #define SkFloatToFixed_Check(x) SkFloatToFixed(x) +#endif + +#define SkFixedToDouble(x) ((x) * 1.52587890625e-5) +#define SkDoubleToFixed(x) ((SkFixed)((x) * SK_Fixed1)) + +/** Converts an integer to a SkFixed, asserting that the result does not overflow + a 32 bit signed integer +*/ +#ifdef SK_DEBUG + inline SkFixed SkIntToFixed(int n) + { + SkASSERT(n >= -32768 && n <= 32767); + // Left shifting a negative value has undefined behavior in C, so we cast to unsigned before + // shifting. + return (SkFixed)( (unsigned)n << 16 ); + } +#else + // Left shifting a negative value has undefined behavior in C, so we cast to unsigned before + // shifting. Then we force the cast to SkFixed to ensure that the answer is signed (like the + // debug version). + #define SkIntToFixed(n) (SkFixed)((unsigned)(n) << 16) +#endif + +#define SkFixedRoundToInt(x) (((x) + SK_FixedHalf) >> 16) +#define SkFixedCeilToInt(x) (((x) + SK_Fixed1 - 1) >> 16) +#define SkFixedFloorToInt(x) ((x) >> 16) + +static inline SkFixed SkFixedRoundToFixed(SkFixed x) { + return (SkFixed)( (uint32_t)(x + SK_FixedHalf) & 0xFFFF0000 ); +} +static inline SkFixed SkFixedCeilToFixed(SkFixed x) { + return (SkFixed)( (uint32_t)(x + SK_Fixed1 - 1) & 0xFFFF0000 ); +} +static inline SkFixed SkFixedFloorToFixed(SkFixed x) { + return (SkFixed)( (uint32_t)x & 0xFFFF0000 ); +} + +#define SkFixedAve(a, b) (((a) + (b)) >> 1) + +// The divide may exceed 32 bits. Clamp to a signed 32 bit result. +#define SkFixedDiv(numer, denom) \ + SkToS32(SkTPin((SkLeftShift((int64_t)(numer), 16) / (denom)), SK_MinS32, SK_MaxS32)) + +static inline SkFixed SkFixedMul(SkFixed a, SkFixed b) { + return (SkFixed)((int64_t)a * b >> 16); +} + +/////////////////////////////////////////////////////////////////////////////// +// Platform-specific alternatives to our portable versions. + +// The VCVT float-to-fixed instruction is part of the VFPv3 instruction set. +#if defined(__ARM_VFPV3__) + #include + + /* This does not handle NaN or other obscurities, but is faster than + than (int)(x*65536). When built on Android with -Os, needs forcing + to inline or we lose the speed benefit. + */ + SK_ALWAYS_INLINE SkFixed SkFloatToFixed_arm(float x) + { + int32_t y; + asm("vcvt.s32.f32 %0, %0, #16": "+w"(x)); + std::memcpy(&y, &x, sizeof(y)); + return y; + } + #undef SkFloatToFixed + #define SkFloatToFixed(x) SkFloatToFixed_arm(x) +#endif + +/////////////////////////////////////////////////////////////////////////////// + +#define SkFixedToScalar(x) SkFixedToFloat(x) +#define SkScalarToFixed(x) SkFloatToFixed(x) + +/////////////////////////////////////////////////////////////////////////////// + +typedef int64_t SkFixed3232; // 32.32 + +#define SkFixed3232Max SK_MaxS64 +#define SkFixed3232Min (-SkFixed3232Max) + +#define SkIntToFixed3232(x) (SkLeftShift((SkFixed3232)(x), 32)) +#define SkFixed3232ToInt(x) ((int)((x) >> 32)) +#define SkFixedToFixed3232(x) (SkLeftShift((SkFixed3232)(x), 16)) +#define SkFixed3232ToFixed(x) ((SkFixed)((x) >> 16)) +#define SkFloatToFixed3232(x) sk_float_saturate2int64((x) * (65536.0f * 65536.0f)) +#define SkFixed3232ToFloat(x) (x * (1 / (65536.0f * 65536.0f))) + +#define SkScalarToFixed3232(x) SkFloatToFixed3232(x) + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkFloatingPoint.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkFloatingPoint.h new file mode 100644 index 0000000000..5a1e4e30b7 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkFloatingPoint.h @@ -0,0 +1,184 @@ +/* + * 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 SkFloatingPoint_DEFINED +#define SkFloatingPoint_DEFINED + +#include "include/private/base/SkAttributes.h" +#include "include/private/base/SkMath.h" + +#include +#include +#include +#include + +inline constexpr float SK_FloatSqrt2 = 1.41421356f; +inline constexpr float SK_FloatPI = 3.14159265f; +inline constexpr double SK_DoublePI = 3.14159265358979323846264338327950288; + +static constexpr int sk_float_sgn(float x) { + return (0.0f < x) - (x < 0.0f); +} + +static constexpr float sk_float_degrees_to_radians(float degrees) { + return degrees * (SK_FloatPI / 180); +} + +static constexpr float sk_float_radians_to_degrees(float radians) { + return radians * (180 / SK_FloatPI); +} + +// floor(double+0.5) vs. floorf(float+0.5f) give comparable performance, but upcasting to double +// means tricky values like 0.49999997 and 2^24 get rounded correctly. If these were rounded +// as floatf(x + .5f), they would be 1 higher than expected. +#define sk_float_round(x) (float)sk_double_round((double)(x)) + +template , bool> = true> +static inline constexpr bool SkIsNaN(T x) { + return x != x; +} + +// Subtracting a value from itself will result in zero, except for NAN or ±Inf, which make NAN. +// Multiplying a group of values against zero will result in zero for each product, except for +// NAN or ±Inf, which will result in NAN and continue resulting in NAN for the rest of the elements. +// This generates better code than `std::isfinite` when building with clang-cl (April 2024). +template , bool> = true> +static inline bool SkIsFinite(T x, Pack... values) { + T prod = x - x; + prod = (prod * ... * values); + // At this point, `prod` will either be NaN or 0. + return prod == prod; +} + +template , bool> = true> +static inline bool SkIsFinite(const T array[], int count) { + T x = array[0]; + T prod = x - x; + for (int i = 1; i < count; ++i) { + prod *= array[i]; + } + // At this point, `prod` will either be NaN or 0. + return prod == prod; +} + +inline constexpr int SK_MaxS32FitsInFloat = 2147483520; +inline constexpr int SK_MinS32FitsInFloat = -SK_MaxS32FitsInFloat; + +// 0x7fffff8000000000 +inline constexpr int64_t SK_MaxS64FitsInFloat = SK_MaxS64 >> (63-24) << (63-24); +inline constexpr int64_t SK_MinS64FitsInFloat = -SK_MaxS64FitsInFloat; + +// sk_[float|double]_saturate2int are written to return their maximum values when passed NaN. +// MSVC 19.38+ has a bug with this implementation, leading to incorrect results: +// https://developercommunity.visualstudio.com/t/Optimizer-incorrectly-handles-NaN-floati/10654403 +// +// We inject an explicit NaN test on MSVC to work around the problem. +#if defined(_MSC_VER) && !defined(__clang__) + #define SK_CHECK_NAN(resultVal) if (SkIsNaN(x)) { return resultVal; } +#else + #define SK_CHECK_NAN(resultVal) +#endif + +/** + * Return the closest int for the given float. Returns SK_MaxS32FitsInFloat for NaN. + */ +static constexpr int sk_float_saturate2int(float x) { + SK_CHECK_NAN(SK_MaxS32FitsInFloat) + x = x < SK_MaxS32FitsInFloat ? x : SK_MaxS32FitsInFloat; + x = x > SK_MinS32FitsInFloat ? x : SK_MinS32FitsInFloat; + return (int)x; +} + +/** + * Return the closest int for the given double. Returns SK_MaxS32 for NaN. + */ +static constexpr int sk_double_saturate2int(double x) { + SK_CHECK_NAN(SK_MaxS32) + x = x < SK_MaxS32 ? x : SK_MaxS32; + x = x > SK_MinS32 ? x : SK_MinS32; + return (int)x; +} + +/** + * Return the closest int64_t for the given float. Returns SK_MaxS64FitsInFloat for NaN. + */ +static constexpr int64_t sk_float_saturate2int64(float x) { + SK_CHECK_NAN(SK_MaxS64FitsInFloat) + x = x < SK_MaxS64FitsInFloat ? x : SK_MaxS64FitsInFloat; + x = x > SK_MinS64FitsInFloat ? x : SK_MinS64FitsInFloat; + return (int64_t)x; +} + +#undef SK_CHECK_NAN + +#define sk_float_floor2int(x) sk_float_saturate2int(std::floor(x)) +#define sk_float_round2int(x) sk_float_saturate2int(sk_float_round(x)) +#define sk_float_ceil2int(x) sk_float_saturate2int(std::ceil(x)) + +#define sk_float_floor2int_no_saturate(x) ((int)std::floor(x)) +#define sk_float_round2int_no_saturate(x) ((int)sk_float_round(x)) +#define sk_float_ceil2int_no_saturate(x) ((int)std::ceil(x)) + +#define sk_double_round(x) (std::floor((x) + 0.5)) +#define sk_double_floor2int(x) ((int)std::floor(x)) +#define sk_double_round2int(x) ((int)std::round(x)) +#define sk_double_ceil2int(x) ((int)std::ceil(x)) + +// Cast double to float, ignoring any warning about too-large finite values being cast to float. +// Clang thinks this is undefined, but it's actually implementation defined to return either +// the largest float or infinity (one of the two bracketing representable floats). Good enough! +SK_NO_SANITIZE("float-cast-overflow") +static constexpr float sk_double_to_float(double x) { + return static_cast(x); +} + +inline constexpr float SK_FloatNaN = std::numeric_limits::quiet_NaN(); +inline constexpr float SK_FloatInfinity = std::numeric_limits::infinity(); +inline constexpr float SK_FloatNegativeInfinity = -SK_FloatInfinity; + +inline constexpr double SK_DoubleNaN = std::numeric_limits::quiet_NaN(); + +// Calculate the midpoint between a and b. Similar to std::midpoint in c++20. +static constexpr float sk_float_midpoint(float a, float b) { + // Use double math to avoid underflow and overflow. + return static_cast(0.5 * (static_cast(a) + b)); +} + +static inline float sk_float_rsqrt_portable(float x) { return 1.0f / std::sqrt(x); } +static inline float sk_float_rsqrt (float x) { return 1.0f / std::sqrt(x); } + +// IEEE defines how float divide behaves for non-finite values and zero-denoms, but C does not, +// so we have a helper that suppresses the possible undefined-behavior warnings. +#ifdef SK_BUILD_FOR_WIN +#pragma warning(push) +#pragma warning(disable : 4723) +#endif +SK_NO_SANITIZE("float-divide-by-zero") +static constexpr float sk_ieee_float_divide(float numer, float denom) { + return numer / denom; +} + +SK_NO_SANITIZE("float-divide-by-zero") +static constexpr double sk_ieee_double_divide(double numer, double denom) { + return numer / denom; +} +#ifdef SK_BUILD_FOR_WIN +#pragma warning( pop ) +#endif + +// Returns true iff the provided number is within a small epsilon of 0. +bool sk_double_nearly_zero(double a); + +// Compare two doubles and return true if they are within maxUlpsDiff of each other. +// * nan as a or b - returns false. +// * infinity, infinity or -infinity, -infinity - returns true. +// * infinity and any other number - returns false. +// +// ulp is an initialism for Units in the Last Place. +bool sk_doubles_nearly_equal_ulps(double a, double b, uint8_t maxUlpsDiff = 16); + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkLoadUserConfig.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkLoadUserConfig.h new file mode 100644 index 0000000000..9f949782c0 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkLoadUserConfig.h @@ -0,0 +1,63 @@ +/* + * 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 SK_USER_CONFIG_WAS_LOADED + +// Include this to set reasonable defaults (e.g. for SK_CPU_LENDIAN) +#include "include/private/base/SkFeatures.h" + +// Allows embedders that want to disable macros that take arguments to just +// define that symbol to be one of these +#define SK_NOTHING_ARG1(arg1) +#define SK_NOTHING_ARG2(arg1, arg2) +#define SK_NOTHING_ARG3(arg1, arg2, arg3) + +// IWYU pragma: begin_exports + +// Note: SK_USER_CONFIG_HEADER will not work with Bazel builds and some C++ compilers. +#if defined(SK_USER_CONFIG_HEADER) + #include SK_USER_CONFIG_HEADER +#elif defined(SK_USE_BAZEL_CONFIG_HEADER) + // The Bazel config file is presumed to be in the root directory of its Bazel Workspace. + // This is achieved in Skia by having a nested WORKSPACE in include/config and a cc_library + // defined in that folder. As a result, we do not try to include SkUserConfig.h from the + // top of Skia because Bazel sandboxing will move it to a different location. + #include "SkUserConfig.h" // NO_G3_REWRITE +#else + #include "include/config/SkUserConfig.h" +#endif +// IWYU pragma: end_exports + +// Checks to make sure the SkUserConfig options do not conflict. +#if !defined(SK_DEBUG) && !defined(SK_RELEASE) + #ifdef NDEBUG + #define SK_RELEASE + #else + #define SK_DEBUG + #endif +#endif + +#if defined(SK_DEBUG) && defined(SK_RELEASE) +# error "cannot define both SK_DEBUG and SK_RELEASE" +#elif !defined(SK_DEBUG) && !defined(SK_RELEASE) +# error "must define either SK_DEBUG or SK_RELEASE" +#endif + +#if defined(SK_CPU_LENDIAN) && defined(SK_CPU_BENDIAN) +# error "cannot define both SK_CPU_LENDIAN and SK_CPU_BENDIAN" +#elif !defined(SK_CPU_LENDIAN) && !defined(SK_CPU_BENDIAN) +# error "must define either SK_CPU_LENDIAN or SK_CPU_BENDIAN" +#endif + +#if defined(SK_CPU_BENDIAN) && !defined(I_ACKNOWLEDGE_SKIA_DOES_NOT_SUPPORT_BIG_ENDIAN) + #error "The Skia team is not endian-savvy enough to support big-endian CPUs." + #error "If you still want to use Skia," + #error "please define I_ACKNOWLEDGE_SKIA_DOES_NOT_SUPPORT_BIG_ENDIAN." +#endif + +#define SK_USER_CONFIG_WAS_LOADED +#endif // SK_USER_CONFIG_WAS_LOADED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkMacros.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkMacros.h new file mode 100644 index 0000000000..5d1835d013 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkMacros.h @@ -0,0 +1,94 @@ +/* + * 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 SkMacros_DEFINED +#define SkMacros_DEFINED + +/* + * Usage: SK_MACRO_CONCAT(a, b) to construct the symbol ab + * + * SK_MACRO_CONCAT_IMPL_PRIV just exists to make this work. Do not use directly + * + */ +#define SK_MACRO_CONCAT(X, Y) SK_MACRO_CONCAT_IMPL_PRIV(X, Y) +#define SK_MACRO_CONCAT_IMPL_PRIV(X, Y) X ## Y + +/* + * Usage: SK_MACRO_APPEND_LINE(foo) to make foo123, where 123 is the current + * line number. Easy way to construct + * unique names for local functions or + * variables. + */ +#define SK_MACRO_APPEND_LINE(name) SK_MACRO_CONCAT(name, __LINE__) + +#define SK_MACRO_APPEND_COUNTER(name) SK_MACRO_CONCAT(name, __COUNTER__) + +//////////////////////////////////////////////////////////////////////////////// + +// Can be used to bracket data types that must be dense/packed, e.g. hash keys. +#if defined(__clang__) // This should work on GCC too, but GCC diagnostic pop didn't seem to work! + #define SK_BEGIN_REQUIRE_DENSE _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic error \"-Wpadded\"") + #define SK_END_REQUIRE_DENSE _Pragma("GCC diagnostic pop") +#else + #define SK_BEGIN_REQUIRE_DENSE + #define SK_END_REQUIRE_DENSE +#endif + +#if defined(__clang__) && defined(__has_feature) + // Some compilers have a preprocessor that does not appear to do short-circuit + // evaluation as expected + #if __has_feature(leak_sanitizer) || __has_feature(address_sanitizer) + // Chrome had issues if we tried to include lsan_interface.h ourselves. + // https://github.com/llvm/llvm-project/blob/10a35632d55bb05004fe3d0c2d4432bb74897ee7/compiler-rt/include/sanitizer/lsan_interface.h#L26 +extern "C" { + void __lsan_ignore_object(const void *p); +} + #define SK_INTENTIONALLY_LEAKED(X) __lsan_ignore_object(X) + #else + #define SK_INTENTIONALLY_LEAKED(X) ((void)0) + #endif +#else + #define SK_INTENTIONALLY_LEAKED(X) ((void)0) +#endif + +#define SK_INIT_TO_AVOID_WARNING = 0 + +//////////////////////////////////////////////////////////////////////////////// + +/** + * Defines overloaded bitwise operators to make it easier to use an enum as a + * bitfield. + */ +#define SK_MAKE_BITFIELD_OPS(X) \ + inline X operator ~(X a) { \ + using U = std::underlying_type_t; \ + return (X) (~static_cast(a)); \ + } \ + inline X operator |(X a, X b) { \ + using U = std::underlying_type_t; \ + return (X) (static_cast(a) | static_cast(b)); \ + } \ + inline X& operator |=(X& a, X b) { \ + return (a = a | b); \ + } \ + inline X operator &(X a, X b) { \ + using U = std::underlying_type_t; \ + return (X) (static_cast(a) & static_cast(b)); \ + } \ + inline X& operator &=(X& a, X b) { \ + return (a = a & b); \ + } + +#define SK_DECL_BITFIELD_OPS_FRIENDS(X) \ + friend X operator ~(X a); \ + friend X operator |(X a, X b); \ + friend X& operator |=(X& a, X b); \ + \ + friend X operator &(X a, X b); \ + friend X& operator &=(X& a, X b); + +#endif // SkMacros_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkMalloc.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkMalloc.h new file mode 100644 index 0000000000..60a77ee7a9 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkMalloc.h @@ -0,0 +1,152 @@ +/* + * 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 SkMalloc_DEFINED +#define SkMalloc_DEFINED + +#include + +#include "include/private/base/SkAPI.h" + +/* + memory wrappers to be implemented by the porting layer (platform) +*/ + + +/** Free memory returned by sk_malloc(). It is safe to pass null. */ +SK_API extern void sk_free(void*); + +/** + * Called internally if we run out of memory. The platform implementation must + * not return, but should either throw an exception or otherwise exit. + */ +SK_API extern void sk_out_of_memory(void); + +enum { + /** + * If this bit is set, the returned buffer must be zero-initialized. If this bit is not set + * the buffer can be uninitialized. + */ + SK_MALLOC_ZERO_INITIALIZE = 1 << 0, + + /** + * If this bit is set, the implementation must throw/crash/quit if the request cannot + * be fulfilled. If this bit is not set, then it should return nullptr on failure. + */ + SK_MALLOC_THROW = 1 << 1, +}; +/** + * Return a block of memory (at least 4-byte aligned) of at least the specified size. + * If the requested memory cannot be returned, either return nullptr or throw/exit, depending + * on the SK_MALLOC_THROW bit. If the allocation succeeds, the memory will be zero-initialized + * if the SK_MALLOC_ZERO_INITIALIZE bit was set. + * + * To free the memory, call sk_free() + */ +SK_API extern void* sk_malloc_flags(size_t size, unsigned flags); + +/** Same as standard realloc(), but this one never returns null on failure. It will throw + * if it fails. + * If size is 0, it will call sk_free on buffer and return null. (This behavior is implementation- + * defined for normal realloc. We follow what glibc does.) + */ +SK_API extern void* sk_realloc_throw(void* buffer, size_t size); + +/** + * Return the size of the block of memory allocated in reality for a given pointer. The pointer + * passed must have been allocated using the sk_malloc_* or sk_realloc_* functions. The "size" + * parameter indicates the size originally requested when the memory block was allocated, and + * the value returned by this function must be bigger or equal to it. + */ +SK_API extern size_t sk_malloc_size(void* addr, size_t size); + +static inline void* sk_malloc_throw(size_t size) { + return sk_malloc_flags(size, SK_MALLOC_THROW); +} + +static inline void* sk_calloc_throw(size_t size) { + return sk_malloc_flags(size, SK_MALLOC_THROW | SK_MALLOC_ZERO_INITIALIZE); +} + +static inline void* sk_calloc_canfail(size_t size) { +#if defined(SK_BUILD_FOR_FUZZER) + // To reduce the chance of OOM, pretend we can't allocate more than 200kb. + if (size > 200000) { + return nullptr; + } +#endif + return sk_malloc_flags(size, SK_MALLOC_ZERO_INITIALIZE); +} + +// Performs a safe multiply count * elemSize, checking for overflow +SK_API extern void* sk_calloc_throw(size_t count, size_t elemSize); +SK_API extern void* sk_malloc_throw(size_t count, size_t elemSize); +SK_API extern void* sk_realloc_throw(void* buffer, size_t count, size_t elemSize); + +/** + * These variants return nullptr on failure + */ +static inline void* sk_malloc_canfail(size_t size) { +#if defined(SK_BUILD_FOR_FUZZER) + // To reduce the chance of OOM, pretend we can't allocate more than 200kb. + if (size > 200000) { + return nullptr; + } +#endif + return sk_malloc_flags(size, 0); +} +SK_API extern void* sk_malloc_canfail(size_t count, size_t elemSize); + +// bzero is safer than memset, but we can't rely on it, so... sk_bzero() +static inline void sk_bzero(void* buffer, size_t size) { + // Please c.f. sk_careful_memcpy. It's undefined behavior to call memset(null, 0, 0). + if (size) { + memset(buffer, 0, size); + } +} + +/** + * sk_careful_memcpy() is just like memcpy(), but guards against undefined behavior. + * + * It is undefined behavior to call memcpy() with null dst or src, even if len is 0. + * If an optimizer is "smart" enough, it can exploit this to do unexpected things. + * memcpy(dst, src, 0); + * if (src) { + * printf("%x\n", *src); + * } + * In this code the compiler can assume src is not null and omit the if (src) {...} check, + * unconditionally running the printf, crashing the program if src really is null. + * Of the compilers we pay attention to only GCC performs this optimization in practice. + */ +static inline void* sk_careful_memcpy(void* dst, const void* src, size_t len) { + // When we pass >0 len we had better already be passing valid pointers. + // So we just need to skip calling memcpy when len == 0. + if (len) { + memcpy(dst,src,len); + } + return dst; +} + +static inline void* sk_careful_memmove(void* dst, const void* src, size_t len) { + // When we pass >0 len we had better already be passing valid pointers. + // So we just need to skip calling memcpy when len == 0. + if (len) { + memmove(dst,src,len); + } + return dst; +} + +static inline int sk_careful_memcmp(const void* a, const void* b, size_t len) { + // When we pass >0 len we had better already be passing valid pointers. + // So we just need to skip calling memcmp when len == 0. + if (len == 0) { + return 0; // we treat zero-length buffers as "equal" + } + return memcmp(a, b, len); +} + +#endif // SkMalloc_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkMath.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkMath.h new file mode 100644 index 0000000000..34bfa739f7 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkMath.h @@ -0,0 +1,77 @@ +/* + * 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 SkMath_DEFINED +#define SkMath_DEFINED + +#include "include/private/base/SkAssert.h" +#include "include/private/base/SkCPUTypes.h" + +#include +#include + +// Max Signed 16 bit value +static constexpr int16_t SK_MaxS16 = INT16_MAX; +static constexpr int16_t SK_MinS16 = -SK_MaxS16; + +static constexpr int32_t SK_MaxS32 = INT32_MAX; +static constexpr int32_t SK_MinS32 = -SK_MaxS32; +static constexpr int32_t SK_NaN32 = INT32_MIN; + +static constexpr int64_t SK_MaxS64 = INT64_MAX; +static constexpr int64_t SK_MinS64 = -SK_MaxS64; + +// 64bit -> 32bit utilities + +// Handy util that can be passed two ints, and will automatically promote to +// 64bits before the multiply, so the caller doesn't have to remember to cast +// e.g. (int64_t)a * b; +static inline int64_t sk_64_mul(int64_t a, int64_t b) { + return a * b; +} + +static inline constexpr int32_t SkLeftShift(int32_t value, int32_t shift) { + return (int32_t) ((uint32_t) value << shift); +} + +static inline constexpr int64_t SkLeftShift(int64_t value, int32_t shift) { + return (int64_t) ((uint64_t) value << shift); +} + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Returns true if value is a power of 2. Does not explicitly check for + * value <= 0. + */ +template constexpr inline bool SkIsPow2(T value) { + return (value & (value - 1)) == 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Return a*b/((1 << shift) - 1), rounding any fractional bits. + * Only valid if a and b are unsigned and <= 32767 and shift is > 0 and <= 8 + */ +static inline unsigned SkMul16ShiftRound(U16CPU a, U16CPU b, int shift) { + SkASSERT(a <= 32767); + SkASSERT(b <= 32767); + SkASSERT(shift > 0 && shift <= 8); + unsigned prod = a*b + (1 << (shift - 1)); + return (prod + (prod >> shift)) >> shift; +} + +/** + * Return a*b/255, rounding any fractional bits. + * Only valid if a and b are unsigned and <= 32767. + */ +static inline U8CPU SkMulDiv255Round(U16CPU a, U16CPU b) { + return SkMul16ShiftRound(a, b, 8); +} + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkMutex.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkMutex.h new file mode 100644 index 0000000000..4452beb912 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkMutex.h @@ -0,0 +1,64 @@ +/* + * 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 SkMutex_DEFINED +#define SkMutex_DEFINED + +#include "include/private/base/SkAssert.h" +#include "include/private/base/SkDebug.h" +#include "include/private/base/SkSemaphore.h" +#include "include/private/base/SkThreadAnnotations.h" +#include "include/private/base/SkThreadID.h" + +class SK_CAPABILITY("mutex") SkMutex { +public: + constexpr SkMutex() = default; + + ~SkMutex() { + this->assertNotHeld(); + } + + void acquire() SK_ACQUIRE() { + fSemaphore.wait(); + SkDEBUGCODE(fOwner = SkGetThreadID();) + } + + void release() SK_RELEASE_CAPABILITY() { + this->assertHeld(); + SkDEBUGCODE(fOwner = kIllegalThreadID;) + fSemaphore.signal(); + } + + void assertHeld() SK_ASSERT_CAPABILITY(this) { + SkASSERT(fOwner == SkGetThreadID()); + } + + void assertNotHeld() { + SkASSERT(fOwner == kIllegalThreadID); + } + +private: + SkSemaphore fSemaphore{1}; + SkDEBUGCODE(SkThreadID fOwner{kIllegalThreadID};) +}; + +class SK_SCOPED_CAPABILITY SkAutoMutexExclusive { +public: + SkAutoMutexExclusive(SkMutex& mutex) SK_ACQUIRE(mutex) : fMutex(mutex) { fMutex.acquire(); } + ~SkAutoMutexExclusive() SK_RELEASE_CAPABILITY() { fMutex.release(); } + + SkAutoMutexExclusive(const SkAutoMutexExclusive&) = delete; + SkAutoMutexExclusive(SkAutoMutexExclusive&&) = delete; + + SkAutoMutexExclusive& operator=(const SkAutoMutexExclusive&) = delete; + SkAutoMutexExclusive& operator=(SkAutoMutexExclusive&&) = delete; + +private: + SkMutex& fMutex; +}; + +#endif // SkMutex_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkNoncopyable.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkNoncopyable.h new file mode 100644 index 0000000000..ec4a4e5161 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkNoncopyable.h @@ -0,0 +1,30 @@ +/* + * 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 SkNoncopyable_DEFINED +#define SkNoncopyable_DEFINED + +#include "include/private/base/SkAPI.h" + +/** \class SkNoncopyable (DEPRECATED) + + SkNoncopyable is the base class for objects that do not want to + be copied. It hides its copy-constructor and its assignment-operator. +*/ +class SK_API SkNoncopyable { +public: + SkNoncopyable() = default; + + SkNoncopyable(SkNoncopyable&&) = default; + SkNoncopyable& operator =(SkNoncopyable&&) = default; + +private: + SkNoncopyable(const SkNoncopyable&) = delete; + SkNoncopyable& operator=(const SkNoncopyable&) = delete; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkOnce.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkOnce.h new file mode 100644 index 0000000000..97ce6b6311 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkOnce.h @@ -0,0 +1,55 @@ +/* + * 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 SkOnce_DEFINED +#define SkOnce_DEFINED + +#include "include/private/base/SkThreadAnnotations.h" + +#include +#include +#include + +// SkOnce provides call-once guarantees for Skia, much like std::once_flag/std::call_once(). +// +// There should be no particularly error-prone gotcha use cases when using SkOnce. +// It works correctly as a class member, a local, a global, a function-scoped static, whatever. + +class SkOnce { +public: + constexpr SkOnce() = default; + + template + void operator()(Fn&& fn, Args&&... args) { + auto state = fState.load(std::memory_order_acquire); + + if (state == Done) { + return; + } + + // If it looks like no one has started calling fn(), try to claim that job. + if (state == NotStarted && fState.compare_exchange_strong(state, Claimed, + std::memory_order_relaxed, + std::memory_order_relaxed)) { + // Great! We'll run fn() then notify the other threads by releasing Done into fState. + fn(std::forward(args)...); + return fState.store(Done, std::memory_order_release); + } + + // Some other thread is calling fn(). + // We'll just spin here acquiring until it releases Done into fState. + SK_POTENTIALLY_BLOCKING_REGION_BEGIN; + while (fState.load(std::memory_order_acquire) != Done) { /*spin*/ } + SK_POTENTIALLY_BLOCKING_REGION_END; + } + +private: + enum State : uint8_t { NotStarted, Claimed, Done}; + std::atomic fState{NotStarted}; +}; + +#endif // SkOnce_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkPoint_impl.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkPoint_impl.h new file mode 100644 index 0000000000..e3843b240b --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkPoint_impl.h @@ -0,0 +1,560 @@ +/* + * 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 SkPoint_DEFINED +#define SkPoint_DEFINED + +#include "include/private/base/SkAPI.h" +#include "include/private/base/SkFloatingPoint.h" +#include "include/private/base/SkSafe32.h" + +#include +#include + +struct SkIPoint; + +/** SkIVector provides an alternative name for SkIPoint. SkIVector and SkIPoint + can be used interchangeably for all purposes. +*/ +typedef SkIPoint SkIVector; + +/** \struct SkIPoint + SkIPoint holds two 32-bit integer coordinates. +*/ +struct SkIPoint { + int32_t fX; //!< x-axis value + int32_t fY; //!< y-axis value + + /** Sets fX to x, fY to y. + + @param x integer x-axis value of constructed SkIPoint + @param y integer y-axis value of constructed SkIPoint + @return SkIPoint (x, y) + */ + static constexpr SkIPoint Make(int32_t x, int32_t y) { + return {x, y}; + } + + /** Returns x-axis value of SkIPoint. + + @return fX + */ + constexpr int32_t x() const { return fX; } + + /** Returns y-axis value of SkIPoint. + + @return fY + */ + constexpr int32_t y() const { return fY; } + + /** Returns true if fX and fY are both zero. + + @return true if fX is zero and fY is zero + */ + bool isZero() const { return (fX | fY) == 0; } + + /** Sets fX to x and fY to y. + + @param x new value for fX + @param y new value for fY + */ + void set(int32_t x, int32_t y) { + fX = x; + fY = y; + } + + /** Returns SkIPoint changing the signs of fX and fY. + + @return SkIPoint as (-fX, -fY) + */ + SkIPoint operator-() const { + return {-fX, -fY}; + } + + /** Offsets SkIPoint by ivector v. Sets SkIPoint to (fX + v.fX, fY + v.fY). + + @param v ivector to add + */ + void operator+=(const SkIVector& v) { + fX = Sk32_sat_add(fX, v.fX); + fY = Sk32_sat_add(fY, v.fY); + } + + /** Subtracts ivector v from SkIPoint. Sets SkIPoint to: (fX - v.fX, fY - v.fY). + + @param v ivector to subtract + */ + void operator-=(const SkIVector& v) { + fX = Sk32_sat_sub(fX, v.fX); + fY = Sk32_sat_sub(fY, v.fY); + } + + /** Returns true if SkIPoint is equivalent to SkIPoint constructed from (x, y). + + @param x value compared with fX + @param y value compared with fY + @return true if SkIPoint equals (x, y) + */ + bool equals(int32_t x, int32_t y) const { + return fX == x && fY == y; + } + + /** Returns true if a is equivalent to b. + + @param a SkIPoint to compare + @param b SkIPoint to compare + @return true if a.fX == b.fX and a.fY == b.fY + */ + friend bool operator==(const SkIPoint& a, const SkIPoint& b) { + return a.fX == b.fX && a.fY == b.fY; + } + + /** Returns true if a is not equivalent to b. + + @param a SkIPoint to compare + @param b SkIPoint to compare + @return true if a.fX != b.fX or a.fY != b.fY + */ + friend bool operator!=(const SkIPoint& a, const SkIPoint& b) { + return a.fX != b.fX || a.fY != b.fY; + } + + /** Returns ivector from b to a; computed as (a.fX - b.fX, a.fY - b.fY). + + Can also be used to subtract ivector from ivector, returning ivector. + + @param a SkIPoint or ivector to subtract from + @param b ivector to subtract + @return ivector from b to a + */ + friend SkIVector operator-(const SkIPoint& a, const SkIPoint& b) { + return { Sk32_sat_sub(a.fX, b.fX), Sk32_sat_sub(a.fY, b.fY) }; + } + + /** Returns SkIPoint resulting from SkIPoint a offset by ivector b, computed as: + (a.fX + b.fX, a.fY + b.fY). + + Can also be used to offset SkIPoint b by ivector a, returning SkIPoint. + Can also be used to add ivector to ivector, returning ivector. + + @param a SkIPoint or ivector to add to + @param b SkIPoint or ivector to add + @return SkIPoint equal to a offset by b + */ + friend SkIPoint operator+(const SkIPoint& a, const SkIVector& b) { + return { Sk32_sat_add(a.fX, b.fX), Sk32_sat_add(a.fY, b.fY) }; + } +}; + +struct SkPoint; + +/** SkVector provides an alternative name for SkPoint. SkVector and SkPoint can + be used interchangeably for all purposes. +*/ +typedef SkPoint SkVector; + +/** \struct SkPoint + SkPoint holds two 32-bit floating point coordinates. +*/ +struct SK_API SkPoint { + float fX; //!< x-axis value + float fY; //!< y-axis value + + /** Sets fX to x, fY to y. Used both to set SkPoint and vector. + + @param x float x-axis value of constructed SkPoint or vector + @param y float y-axis value of constructed SkPoint or vector + @return SkPoint (x, y) + */ + static constexpr SkPoint Make(float x, float y) { + return {x, y}; + } + + /** Returns x-axis value of SkPoint or vector. + + @return fX + */ + constexpr float x() const { return fX; } + + /** Returns y-axis value of SkPoint or vector. + + @return fY + */ + constexpr float y() const { return fY; } + + /** Returns true if fX and fY are both zero. + + @return true if fX is zero and fY is zero + */ + bool isZero() const { return (0 == fX) & (0 == fY); } + + /** Sets fX to x and fY to y. + + @param x new value for fX + @param y new value for fY + */ + void set(float x, float y) { + fX = x; + fY = y; + } + + /** Sets fX to x and fY to y, promoting integers to float values. + + Assigning a large integer value directly to fX or fY may cause a compiler + error, triggered by narrowing conversion of int to float. This safely + casts x and y to avoid the error. + + @param x new value for fX + @param y new value for fY + */ + void iset(int32_t x, int32_t y) { + fX = static_cast(x); + fY = static_cast(y); + } + + /** Sets fX to p.fX and fY to p.fY, promoting integers to float values. + + Assigning an SkIPoint containing a large integer value directly to fX or fY may + cause a compiler error, triggered by narrowing conversion of int to float. + This safely casts p.fX and p.fY to avoid the error. + + @param p SkIPoint members promoted to float + */ + void iset(const SkIPoint& p) { + fX = static_cast(p.fX); + fY = static_cast(p.fY); + } + + /** Sets fX to absolute value of pt.fX; and fY to absolute value of pt.fY. + + @param pt members providing magnitude for fX and fY + */ + void setAbs(const SkPoint& pt) { + fX = std::abs(pt.fX); + fY = std::abs(pt.fY); + } + + /** Adds offset to each SkPoint in points array with count entries. + + @param points SkPoint array + @param count entries in array + @param offset vector added to points + */ + static void Offset(SkPoint points[], int count, const SkVector& offset) { + Offset(points, count, offset.fX, offset.fY); + } + + /** Adds offset (dx, dy) to each SkPoint in points array of length count. + + @param points SkPoint array + @param count entries in array + @param dx added to fX in points + @param dy added to fY in points + */ + static void Offset(SkPoint points[], int count, float dx, float dy) { + for (int i = 0; i < count; ++i) { + points[i].offset(dx, dy); + } + } + + /** Adds offset (dx, dy) to SkPoint. + + @param dx added to fX + @param dy added to fY + */ + void offset(float dx, float dy) { + fX += dx; + fY += dy; + } + + /** Returns the Euclidean distance from origin, computed as: + + sqrt(fX * fX + fY * fY) + + . + + @return straight-line distance to origin + */ + float length() const { return SkPoint::Length(fX, fY); } + + /** Returns the Euclidean distance from origin, computed as: + + sqrt(fX * fX + fY * fY) + + . + + @return straight-line distance to origin + */ + float distanceToOrigin() const { return this->length(); } + + /** Scales (fX, fY) so that length() returns one, while preserving ratio of fX to fY, + if possible. If prior length is nearly zero, sets vector to (0, 0) and returns + false; otherwise returns true. + + @return true if former length is not zero or nearly zero + + example: https://fiddle.skia.org/c/@Point_normalize_2 + */ + bool normalize(); + + /** Sets vector to (x, y) scaled so length() returns one, and so that + (fX, fY) is proportional to (x, y). If (x, y) length is nearly zero, + sets vector to (0, 0) and returns false; otherwise returns true. + + @param x proportional value for fX + @param y proportional value for fY + @return true if (x, y) length is not zero or nearly zero + + example: https://fiddle.skia.org/c/@Point_setNormalize + */ + bool setNormalize(float x, float y); + + /** Scales vector so that distanceToOrigin() returns length, if possible. If former + length is nearly zero, sets vector to (0, 0) and return false; otherwise returns + true. + + @param length straight-line distance to origin + @return true if former length is not zero or nearly zero + + example: https://fiddle.skia.org/c/@Point_setLength + */ + bool setLength(float length); + + /** Sets vector to (x, y) scaled to length, if possible. If former + length is nearly zero, sets vector to (0, 0) and return false; otherwise returns + true. + + @param x proportional value for fX + @param y proportional value for fY + @param length straight-line distance to origin + @return true if (x, y) length is not zero or nearly zero + + example: https://fiddle.skia.org/c/@Point_setLength_2 + */ + bool setLength(float x, float y, float length); + + /** Sets dst to SkPoint times scale. dst may be SkPoint to modify SkPoint in place. + + @param scale factor to multiply SkPoint by + @param dst storage for scaled SkPoint + + example: https://fiddle.skia.org/c/@Point_scale + */ + void scale(float scale, SkPoint* dst) const; + + /** Scales SkPoint in place by scale. + + @param value factor to multiply SkPoint by + */ + void scale(float value) { this->scale(value, this); } + + /** Changes the sign of fX and fY. + */ + void negate() { + fX = -fX; + fY = -fY; + } + + /** Returns SkPoint changing the signs of fX and fY. + + @return SkPoint as (-fX, -fY) + */ + SkPoint operator-() const { + return {-fX, -fY}; + } + + /** Adds vector v to SkPoint. Sets SkPoint to: (fX + v.fX, fY + v.fY). + + @param v vector to add + */ + void operator+=(const SkVector& v) { + fX += v.fX; + fY += v.fY; + } + + /** Subtracts vector v from SkPoint. Sets SkPoint to: (fX - v.fX, fY - v.fY). + + @param v vector to subtract + */ + void operator-=(const SkVector& v) { + fX -= v.fX; + fY -= v.fY; + } + + /** Returns SkPoint multiplied by scale. + + @param scale float to multiply by + @return SkPoint as (fX * scale, fY * scale) + */ + SkPoint operator*(float scale) const { + return {fX * scale, fY * scale}; + } + + /** Multiplies SkPoint by scale. Sets SkPoint to: (fX * scale, fY * scale). + + @param scale float to multiply by + @return reference to SkPoint + */ + SkPoint& operator*=(float scale) { + fX *= scale; + fY *= scale; + return *this; + } + + /** Returns true if both fX and fY are measurable values. + + @return true for values other than infinities and NaN + */ + bool isFinite() const { + return SkIsFinite(fX, fY); + } + + /** Returns true if SkPoint is equivalent to SkPoint constructed from (x, y). + + @param x value compared with fX + @param y value compared with fY + @return true if SkPoint equals (x, y) + */ + bool equals(float x, float y) const { + return fX == x && fY == y; + } + + /** Returns true if a is equivalent to b. + + @param a SkPoint to compare + @param b SkPoint to compare + @return true if a.fX == b.fX and a.fY == b.fY + */ + friend bool operator==(const SkPoint& a, const SkPoint& b) { + return a.fX == b.fX && a.fY == b.fY; + } + + /** Returns true if a is not equivalent to b. + + @param a SkPoint to compare + @param b SkPoint to compare + @return true if a.fX != b.fX or a.fY != b.fY + */ + friend bool operator!=(const SkPoint& a, const SkPoint& b) { + return a.fX != b.fX || a.fY != b.fY; + } + + /** Returns vector from b to a, computed as (a.fX - b.fX, a.fY - b.fY). + + Can also be used to subtract vector from SkPoint, returning SkPoint. + Can also be used to subtract vector from vector, returning vector. + + @param a SkPoint to subtract from + @param b SkPoint to subtract + @return vector from b to a + */ + friend SkVector operator-(const SkPoint& a, const SkPoint& b) { + return {a.fX - b.fX, a.fY - b.fY}; + } + + /** Returns SkPoint resulting from SkPoint a offset by vector b, computed as: + (a.fX + b.fX, a.fY + b.fY). + + Can also be used to offset SkPoint b by vector a, returning SkPoint. + Can also be used to add vector to vector, returning vector. + + @param a SkPoint or vector to add to + @param b SkPoint or vector to add + @return SkPoint equal to a offset by b + */ + friend SkPoint operator+(const SkPoint& a, const SkVector& b) { + return {a.fX + b.fX, a.fY + b.fY}; + } + + /** Returns the Euclidean distance from origin, computed as: + + sqrt(x * x + y * y) + + . + + @param x component of length + @param y component of length + @return straight-line distance to origin + + example: https://fiddle.skia.org/c/@Point_Length + */ + static float Length(float x, float y); + + /** Scales (vec->fX, vec->fY) so that length() returns one, while preserving ratio of vec->fX + to vec->fY, if possible. If original length is nearly zero, sets vec to (0, 0) and returns + zero; otherwise, returns length of vec before vec is scaled. + + Returned prior length may be INFINITY if it can not be represented by float. + + Note that normalize() is faster if prior length is not required. + + @param vec normalized to unit length + @return original vec length + + example: https://fiddle.skia.org/c/@Point_Normalize + */ + static float Normalize(SkVector* vec); + + /** Returns the Euclidean distance between a and b. + + @param a line end point + @param b line end point + @return straight-line distance from a to b + */ + static float Distance(const SkPoint& a, const SkPoint& b) { + return Length(a.fX - b.fX, a.fY - b.fY); + } + + /** Returns the dot product of vector a and vector b. + + @param a left side of dot product + @param b right side of dot product + @return product of input magnitudes and cosine of the angle between them + */ + static float DotProduct(const SkVector& a, const SkVector& b) { + return a.fX * b.fX + a.fY * b.fY; + } + + /** Returns the cross product of vector a and vector b. + + a and b form three-dimensional vectors with z-axis value equal to zero. The + cross product is a three-dimensional vector with x-axis and y-axis values equal + to zero. The cross product z-axis component is returned. + + @param a left side of cross product + @param b right side of cross product + @return area spanned by vectors signed by angle direction + */ + static float CrossProduct(const SkVector& a, const SkVector& b) { + return a.fX * b.fY - a.fY * b.fX; + } + + /** Returns the cross product of vector and vec. + + Vector and vec form three-dimensional vectors with z-axis value equal to zero. + The cross product is a three-dimensional vector with x-axis and y-axis values + equal to zero. The cross product z-axis component is returned. + + @param vec right side of cross product + @return area spanned by vectors signed by angle direction + */ + float cross(const SkVector& vec) const { + return CrossProduct(*this, vec); + } + + /** Returns the dot product of vector and vector vec. + + @param vec right side of dot product + @return product of input magnitudes and cosine of the angle between them + */ + float dot(const SkVector& vec) const { + return DotProduct(*this, vec); + } + +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkSafe32.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkSafe32.h new file mode 100644 index 0000000000..5ba4c2f9a4 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkSafe32.h @@ -0,0 +1,49 @@ +/* + * 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 SkSafe32_DEFINED +#define SkSafe32_DEFINED + +#include "include/private/base/SkAssert.h" +#include "include/private/base/SkMath.h" + +#include + +static constexpr int32_t Sk64_pin_to_s32(int64_t x) { + return x < SK_MinS32 ? SK_MinS32 : (x > SK_MaxS32 ? SK_MaxS32 : (int32_t)x); +} + +static constexpr int32_t Sk32_sat_add(int32_t a, int32_t b) { + return Sk64_pin_to_s32((int64_t)a + (int64_t)b); +} + +static constexpr int32_t Sk32_sat_sub(int32_t a, int32_t b) { + return Sk64_pin_to_s32((int64_t)a - (int64_t)b); +} + +// To avoid UBSAN complaints about 2's compliment overflows +// +static constexpr int32_t Sk32_can_overflow_add(int32_t a, int32_t b) { + return (int32_t)((uint32_t)a + (uint32_t)b); +} +static constexpr int32_t Sk32_can_overflow_sub(int32_t a, int32_t b) { + return (int32_t)((uint32_t)a - (uint32_t)b); +} + +/** + * This is a 'safe' abs for 32-bit integers that asserts when undefined behavior would occur. + * SkTAbs (in SkTemplates.h) is a general purpose absolute-value function. + */ +static inline int32_t SkAbs32(int32_t value) { + SkASSERT(value != SK_NaN32); // The most negative int32_t can't be negated. + if (value < 0) { + value = -value; + } + return value; +} + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkSemaphore.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkSemaphore.h new file mode 100644 index 0000000000..f78ee86625 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkSemaphore.h @@ -0,0 +1,84 @@ +/* + * 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 SkSemaphore_DEFINED +#define SkSemaphore_DEFINED + +#include "include/private/base/SkAPI.h" +#include "include/private/base/SkOnce.h" +#include "include/private/base/SkThreadAnnotations.h" + +#include +#include + +class SkSemaphore { +public: + constexpr SkSemaphore(int count = 0) : fCount(count), fOSSemaphore(nullptr) {} + + // Cleanup the underlying OS semaphore. + SK_SPI ~SkSemaphore(); + + // Increment the counter n times. + // Generally it's better to call signal(n) instead of signal() n times. + void signal(int n = 1); + + // Decrement the counter by 1, + // then if the counter is < 0, sleep this thread until the counter is >= 0. + void wait(); + + // If the counter is positive, decrement it by 1 and return true, otherwise return false. + SK_SPI bool try_wait(); + +private: + // This implementation follows the general strategy of + // 'A Lightweight Semaphore with Partial Spinning' + // found here + // http://preshing.com/20150316/semaphores-are-surprisingly-versatile/ + // That article (and entire blog) are very much worth reading. + // + // We wrap an OS-provided semaphore with a user-space atomic counter that + // lets us avoid interacting with the OS semaphore unless strictly required: + // moving the count from >=0 to <0 or vice-versa, i.e. sleeping or waking threads. + struct OSSemaphore; + + SK_SPI void osSignal(int n); + SK_SPI void osWait(); + + std::atomic fCount; + SkOnce fOSSemaphoreOnce; + OSSemaphore* fOSSemaphore; +}; + +inline void SkSemaphore::signal(int n) { + int prev = fCount.fetch_add(n, std::memory_order_release); + + // We only want to call the OS semaphore when our logical count crosses + // from <0 to >=0 (when we need to wake sleeping threads). + // + // This is easiest to think about with specific examples of prev and n. + // If n == 5 and prev == -3, there are 3 threads sleeping and we signal + // std::min(-(-3), 5) == 3 times on the OS semaphore, leaving the count at 2. + // + // If prev >= 0, no threads are waiting, std::min(-prev, n) is always <= 0, + // so we don't call the OS semaphore, leaving the count at (prev + n). + int toSignal = std::min(-prev, n); + if (toSignal > 0) { + this->osSignal(toSignal); + } +} + +inline void SkSemaphore::wait() { + // Since this fetches the value before the subtract, zero and below means that there are no + // resources left, so the thread needs to wait. + if (fCount.fetch_sub(1, std::memory_order_acquire) <= 0) { + SK_POTENTIALLY_BLOCKING_REGION_BEGIN; + this->osWait(); + SK_POTENTIALLY_BLOCKING_REGION_END; + } +} + +#endif//SkSemaphore_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkSpan_impl.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkSpan_impl.h new file mode 100644 index 0000000000..09b2a754e9 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkSpan_impl.h @@ -0,0 +1,131 @@ +/* + * 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 SkSpan_DEFINED +#define SkSpan_DEFINED + +#include "include/private/base/SkAssert.h" +#include "include/private/base/SkDebug.h" +#include "include/private/base/SkTo.h" + +#include +#include +#include +#include +#include + +// Having this be an export works around IWYU churn related to +// https://github.com/include-what-you-use/include-what-you-use/issues/1121 +#include // IWYU pragma: export + +// Add macro to check the lifetime of initializer_list arguments. initializer_list has a very +// short life span, and can only be used as a parameter, and not as a variable. +#if defined(__clang__) && defined(__has_cpp_attribute) && __has_cpp_attribute(clang::lifetimebound) +#define SK_CHECK_IL_LIFETIME [[clang::lifetimebound]] +#else +#define SK_CHECK_IL_LIFETIME +#endif + +/** + * SkSpan holds a reference to contiguous data of type T along with a count. SkSpan does not own + * the data itself but is merely a reference, therefore you must take care with the lifetime of + * the underlying data. + * + * SkSpan is a count and a pointer into existing array or data type that stores its data in + * contiguous memory like std::vector. Any container that works with std::size() and std::data() + * can be used. + * + * SkSpan makes a convenient parameter for a routine to accept array like things. This allows you to + * write the routine without overloads for all different container types. + * + * Example: + * void routine(SkSpan a) { ... } + * + * std::vector v = {1, 2, 3, 4, 5}; + * + * routine(a); + * + * A word of caution when working with initializer_list, initializer_lists have a lifetime that is + * limited to the current statement. The following is correct and safe: + * + * Example: + * routine({1,2,3,4,5}); + * + * The following is undefined, and will result in erratic execution: + * + * Bad Example: + * initializer_list l = {1, 2, 3, 4, 5}; // The data behind l dies at the ;. + * routine(l); + */ +template +class SkSpan { +public: + constexpr SkSpan() : fPtr{nullptr}, fSize{0} {} + + template , bool> = true> + constexpr SkSpan(T* ptr, Integer size) : fPtr{ptr}, fSize{SkToSizeT(size)} { + SkASSERT(ptr || fSize == 0); // disallow nullptr + a nonzero size + SkASSERT(fSize < kMaxSize); + } + template >> + constexpr SkSpan(const SkSpan& that) : fPtr(std::data(that)), fSize(std::size(that)) {} + constexpr SkSpan(const SkSpan& o) = default; + template constexpr SkSpan(T(&a)[N]) : SkSpan(a, N) { } + template + constexpr SkSpan(Container&& c) : SkSpan(std::data(c), std::size(c)) { } + SkSpan(std::initializer_list il SK_CHECK_IL_LIFETIME) + : SkSpan(std::data(il), std::size(il)) {} + + constexpr SkSpan& operator=(const SkSpan& that) = default; + + constexpr T& operator [] (size_t i) const { + return fPtr[sk_collection_check_bounds(i, this->size())]; + } + constexpr T& front() const { sk_collection_not_empty(this->empty()); return fPtr[0]; } + constexpr T& back() const { sk_collection_not_empty(this->empty()); return fPtr[fSize - 1]; } + constexpr T* begin() const { return fPtr; } + constexpr T* end() const { return fPtr + fSize; } + constexpr auto rbegin() const { return std::make_reverse_iterator(this->end()); } + constexpr auto rend() const { return std::make_reverse_iterator(this->begin()); } + constexpr T* data() const { return this->begin(); } + constexpr size_t size() const { return fSize; } + constexpr bool empty() const { return fSize == 0; } + constexpr size_t size_bytes() const { return fSize * sizeof(T); } + constexpr SkSpan first(size_t prefixLen) const { + return SkSpan{fPtr, sk_collection_check_length(prefixLen, fSize)}; + } + constexpr SkSpan last(size_t postfixLen) const { + return SkSpan{fPtr + (this->size() - postfixLen), + sk_collection_check_length(postfixLen, fSize)}; + } + constexpr SkSpan subspan(size_t offset) const { + return this->subspan(offset, this->size() - offset); + } + constexpr SkSpan subspan(size_t offset, size_t count) const { + const size_t safeOffset = sk_collection_check_length(offset, fSize); + + // Should read offset + count > size(), but that could overflow. We know that safeOffset + // is <= size, therefore the subtraction will not overflow. + if (count > this->size() - safeOffset) SK_UNLIKELY { + // The count is too large. + SkUNREACHABLE; + } + return SkSpan{fPtr + safeOffset, count}; + } + +private: + static constexpr size_t kMaxSize = std::numeric_limits::max() / sizeof(T); + + T* fPtr; + size_t fSize; +}; + +template +SkSpan(Container&&) -> + SkSpan()))>>; + +#endif // SkSpan_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkTArray.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkTArray.h new file mode 100644 index 0000000000..bb17c854c3 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkTArray.h @@ -0,0 +1,806 @@ +/* + * 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 SkTArray_DEFINED +#define SkTArray_DEFINED + +#include "include/private/base/SkASAN.h" // IWYU pragma: keep +#include "include/private/base/SkAlignedStorage.h" +#include "include/private/base/SkAssert.h" +#include "include/private/base/SkAttributes.h" +#include "include/private/base/SkContainers.h" +#include "include/private/base/SkDebug.h" +#include "include/private/base/SkMalloc.h" +#include "include/private/base/SkMath.h" +#include "include/private/base/SkSpan_impl.h" +#include "include/private/base/SkTo.h" +#include "include/private/base/SkTypeTraits.h" // IWYU pragma: keep + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace skia_private { +/** TArray implements a typical, mostly std::vector-like array. + Each T will be default-initialized on allocation, and ~T will be called on destruction. + + MEM_MOVE controls the behavior when a T needs to be moved (e.g. when the array is resized) + - true: T will be bit-copied via memcpy. + - false: T will be moved via move-constructors. +*/ +template > class TArray { +public: + using value_type = T; + + /** + * Creates an empty array with no initial storage + */ + TArray() : fOwnMemory(true), fCapacity{0} {} + + /** + * Creates an empty array that will preallocate space for reserveCount elements. + */ + explicit TArray(int reserveCount) : TArray() { this->reserve_exact(reserveCount); } + + /** + * Copies one array to another. The new array will be heap allocated. + */ + TArray(const TArray& that) : TArray(that.fData, that.fSize) {} + + TArray(TArray&& that) { + if (that.fOwnMemory) { + this->setData(that); + that.setData({}); + } else { + this->initData(that.fSize); + that.move(fData); + } + this->changeSize(that.fSize); + that.changeSize(0); + } + + /** + * Creates a TArray by copying contents of a standard C array. The new + * array will be heap allocated. Be careful not to use this constructor + * when you really want the (void*, int) version. + */ + TArray(const T* array, int count) { + this->initData(count); + this->copy(array); + } + + /** + * Creates a TArray by copying contents of an initializer list. + */ + TArray(std::initializer_list data) : TArray(data.begin(), data.size()) {} + + TArray& operator=(const TArray& that) { + if (this == &that) { + return *this; + } + this->clear(); + this->checkRealloc(that.size(), kExactFit); + this->changeSize(that.fSize); + this->copy(that.fData); + return *this; + } + + TArray& operator=(TArray&& that) { + if (this != &that) { + this->clear(); + this->unpoison(); + that.unpoison(); + if (that.fOwnMemory) { + // The storage is on the heap, so move the data pointer. + if (fOwnMemory) { + sk_free(fData); + } + + fData = std::exchange(that.fData, nullptr); + + // Can't use exchange with bitfields. + fCapacity = that.fCapacity; + that.fCapacity = 0; + + fOwnMemory = true; + + this->changeSize(that.fSize); + } else { + // The data is stored inline in that, so move it element-by-element. + this->checkRealloc(that.size(), kExactFit); + this->changeSize(that.fSize); + that.move(fData); + } + that.changeSize(0); + } + return *this; + } + + ~TArray() { + this->destroyAll(); + this->unpoison(); + if (fOwnMemory) { + sk_free(fData); + } + } + + /** + * Resets to size() = n newly constructed T objects and resets any reserve count. + */ + void reset(int n) { + SkASSERT(n >= 0); + this->clear(); + this->checkRealloc(n, kExactFit); + this->changeSize(n); + for (int i = 0; i < this->size(); ++i) { + new (fData + i) T; + } + } + + /** + * Resets to a copy of a C array and resets any reserve count. + */ + void reset(const T* array, int count) { + SkASSERT(count >= 0); + this->clear(); + this->checkRealloc(count, kExactFit); + this->changeSize(count); + this->copy(array); + } + + /** + * Ensures there is enough reserved space for at least n elements. This is guaranteed at least + * until the array size grows above n and subsequently shrinks below n, any version of reset() + * is called, or reserve() is called again. + */ + void reserve(int n) { + SkASSERT(n >= 0); + if (n > this->size()) { + this->checkRealloc(n - this->size(), kGrowing); + } + } + + /** + * Ensures there is enough reserved space for exactly n elements. The same capacity guarantees + * as above apply. + */ + void reserve_exact(int n) { + SkASSERT(n >= 0); + if (n > this->size()) { + this->checkRealloc(n - this->size(), kExactFit); + } + } + + void removeShuffle(int n) { + SkASSERT(n < this->size()); + int newCount = fSize - 1; + fData[n].~T(); + if (n != newCount) { + this->move(n, newCount); + } + this->changeSize(newCount); + } + + // Is the array empty. + bool empty() const { return fSize == 0; } + + /** + * Adds one new default-initialized T value and returns it by reference. Note that the reference + * only remains valid until the next call that adds or removes elements. + */ + T& push_back() { + void* newT = this->push_back_raw(1); + return *new (newT) T; + } + + /** + * Adds one new T value which is copy-constructed, returning it by reference. As always, + * the reference only remains valid until the next call that adds or removes elements. + */ + T& push_back(const T& t) { + this->unpoison(); + T* newT; + if (this->capacity() > fSize) SK_LIKELY { + // Copy over the element directly. + newT = new (fData + fSize) T(t); + } else { + newT = this->growAndConstructAtEnd(t); + } + + this->changeSize(fSize + 1); + return *newT; + } + + /** + * Adds one new T value which is copy-constructed, returning it by reference. + */ + T& push_back(T&& t) { + this->unpoison(); + T* newT; + if (this->capacity() > fSize) SK_LIKELY { + // Move over the element directly. + newT = new (fData + fSize) T(std::move(t)); + } else { + newT = this->growAndConstructAtEnd(std::move(t)); + } + + this->changeSize(fSize + 1); + return *newT; + } + + /** + * Constructs a new T at the back of this array, returning it by reference. + */ + template T& emplace_back(Args&&... args) { + this->unpoison(); + T* newT; + if (this->capacity() > fSize) SK_LIKELY { + // Emplace the new element in directly. + newT = new (fData + fSize) T(std::forward(args)...); + } else { + newT = this->growAndConstructAtEnd(std::forward(args)...); + } + + this->changeSize(fSize + 1); + return *newT; + } + + /** + * Allocates n more default-initialized T values, and returns the address of + * the start of that new range. Note: this address is only valid until the + * next API call made on the array that might add or remove elements. + */ + T* push_back_n(int n) { + SkASSERT(n >= 0); + T* newTs = TCast(this->push_back_raw(n)); + for (int i = 0; i < n; ++i) { + new (&newTs[i]) T; + } + return newTs; + } + + /** + * Version of above that uses a copy constructor to initialize all n items + * to the same T. + */ + T* push_back_n(int n, const T& t) { + SkASSERT(n >= 0); + T* newTs = TCast(this->push_back_raw(n)); + for (int i = 0; i < n; ++i) { + new (&newTs[i]) T(t); + } + return static_cast(newTs); + } + + /** + * Version of above that uses a copy constructor to initialize the n items + * to separate T values. + */ + T* push_back_n(int n, const T t[]) { + SkASSERT(n >= 0); + this->checkRealloc(n, kGrowing); + T* end = this->end(); + this->changeSize(fSize + n); + for (int i = 0; i < n; ++i) { + new (end + i) T(t[i]); + } + return end; + } + + /** + * Version of above that uses the move constructor to set n items. + */ + T* move_back_n(int n, T* t) { + SkASSERT(n >= 0); + this->checkRealloc(n, kGrowing); + T* end = this->end(); + this->changeSize(fSize + n); + for (int i = 0; i < n; ++i) { + new (end + i) T(std::move(t[i])); + } + return end; + } + + /** + * Removes the last element. Not safe to call when size() == 0. + */ + void pop_back() { + sk_collection_not_empty(this->empty()); + fData[fSize - 1].~T(); + this->changeSize(fSize - 1); + } + + /** + * Removes the last n elements. Not safe to call when size() < n. + */ + void pop_back_n(int n) { + SkASSERT(n >= 0); + SkASSERT(this->size() >= n); + int i = fSize; + while (i-- > fSize - n) { + (*this)[i].~T(); + } + this->changeSize(fSize - n); + } + + /** + * Pushes or pops from the back to resize. Pushes will be default initialized. + */ + void resize_back(int newCount) { + SkASSERT(newCount >= 0); + if (newCount > this->size()) { + if (this->empty()) { + // When the container is completely empty, grow to exactly the requested size. + this->checkRealloc(newCount, kExactFit); + } + this->push_back_n(newCount - fSize); + } else if (newCount < this->size()) { + this->pop_back_n(fSize - newCount); + } + } + + /** Swaps the contents of this array with that array. Does a pointer swap if possible, + otherwise copies the T values. */ + void swap(TArray& that) { + using std::swap; + if (this == &that) { + return; + } + if (fOwnMemory && that.fOwnMemory) { + swap(fData, that.fData); + swap(fSize, that.fSize); + + // Can't use swap because fCapacity is a bit field. + auto allocCount = fCapacity; + fCapacity = that.fCapacity; + that.fCapacity = allocCount; + } else { + // This could be more optimal... + TArray copy(std::move(that)); + that = std::move(*this); + *this = std::move(copy); + } + } + + /** + * Moves all elements of `that` to the end of this array, leaving `that` empty. + * This is a no-op if `that` is empty or equal to this array. + */ + void move_back(TArray& that) { + if (that.empty() || &that == this) { + return; + } + void* dst = this->push_back_raw(that.size()); + // After move() returns, the contents of `dst` will have either been in-place initialized + // using a the move constructor (per-item from `that`'s elements), or will have been + // mem-copied into when MEM_MOVE is true (now valid objects). + that.move(dst); + // All items in `that` have either been destroyed (when MEM_MOVE is false) or should be + // considered invalid (when MEM_MOVE is true). Reset fSize to 0 directly to skip any further + // per-item destruction. + that.changeSize(0); + } + + T* begin() { + return fData; + } + const T* begin() const { + return fData; + } + + // It's safe to use fItemArray + fSize because if fItemArray is nullptr then adding 0 is + // valid and returns nullptr. See [expr.add] in the C++ standard. + T* end() { + if (fData == nullptr) { + SkASSERT(fSize == 0); + } + return fData + fSize; + } + const T* end() const { + if (fData == nullptr) { + SkASSERT(fSize == 0); + } + return fData + fSize; + } + T* data() { return fData; } + const T* data() const { return fData; } + int size() const { return fSize; } + size_t size_bytes() const { return Bytes(fSize); } + void resize(size_t count) { this->resize_back((int)count); } + + void clear() { + this->destroyAll(); + this->changeSize(0); + } + + void shrink_to_fit() { + if (!fOwnMemory || fSize == fCapacity) { + return; + } + this->unpoison(); + if (fSize == 0) { + sk_free(fData); + fData = nullptr; + fCapacity = 0; + } else { + SkSpan allocation = Allocate(fSize); + this->move(TCast(allocation.data())); + if (fOwnMemory) { + sk_free(fData); + } + // Poison is applied in `setDataFromBytes`. + this->setDataFromBytes(allocation); + } + } + + /** + * Get the i^th element. + */ + T& operator[] (int i) { + return fData[sk_collection_check_bounds(i, this->size())]; + } + + const T& operator[] (int i) const { + return fData[sk_collection_check_bounds(i, this->size())]; + } + + T& at(int i) { return (*this)[i]; } + const T& at(int i) const { return (*this)[i]; } + + /** + * equivalent to operator[](0) + */ + T& front() { + sk_collection_not_empty(this->empty()); + return fData[0]; + } + + const T& front() const { + sk_collection_not_empty(this->empty()); + return fData[0]; + } + + /** + * equivalent to operator[](size() - 1) + */ + T& back() { + sk_collection_not_empty(this->empty()); + return fData[fSize - 1]; + } + + const T& back() const { + sk_collection_not_empty(this->empty()); + return fData[fSize - 1]; + } + + /** + * equivalent to operator[](size()-1-i) + */ + T& fromBack(int i) { + return (*this)[fSize - i - 1]; + } + + const T& fromBack(int i) const { + return (*this)[fSize - i - 1]; + } + + bool operator==(const TArray& right) const { + int leftCount = this->size(); + if (leftCount != right.size()) { + return false; + } + for (int index = 0; index < leftCount; ++index) { + if (fData[index] != right.fData[index]) { + return false; + } + } + return true; + } + + bool operator!=(const TArray& right) const { + return !(*this == right); + } + + int capacity() const { + return fCapacity; + } + +protected: + // Creates an empty array that will use the passed storage block until it is insufficiently + // large to hold the entire array. + template + TArray(SkAlignedSTStorage* storage, int size = 0) { + static_assert(InitialCapacity >= 0); + SkASSERT(size >= 0); + SkASSERT(storage->get() != nullptr); + if (size > InitialCapacity) { + this->initData(size); + } else { + this->setDataFromBytes(*storage); + this->changeSize(size); + + // setDataFromBytes always sets fOwnMemory to true, but we are actually using static + // storage here, which shouldn't ever be freed. + fOwnMemory = false; + } + } + + // Copy a C array, using pre-allocated storage if preAllocCount >= count. Otherwise, storage + // will only be used when array shrinks to fit. + template + TArray(const T* array, int size, SkAlignedSTStorage* storage) + : TArray{storage, size} { + this->copy(array); + } + +private: + // Growth factors for checkRealloc. + static constexpr double kExactFit = 1.0; + static constexpr double kGrowing = 1.5; + + static constexpr int kMinHeapAllocCount = 8; + static_assert(SkIsPow2(kMinHeapAllocCount), "min alloc count not power of two."); + + // Note for 32-bit machines kMaxCapacity will be <= SIZE_MAX. For 64-bit machines it will + // just be INT_MAX if the sizeof(T) < 2^32. + static constexpr int kMaxCapacity = SkToInt(std::min(SIZE_MAX / sizeof(T), (size_t)INT_MAX)); + + void setDataFromBytes(SkSpan allocation) { + T* data = TCast(allocation.data()); + // We have gotten extra bytes back from the allocation limit, pin to kMaxCapacity. It + // would seem like the SkContainerAllocator should handle the divide, but it would have + // to a full divide instruction. If done here the size is known at compile, and usually + // can be implemented by a right shift. The full divide takes ~50X longer than the shift. + size_t size = std::min(allocation.size() / sizeof(T), SkToSizeT(kMaxCapacity)); + this->setData(SkSpan(data, size)); + } + + void setData(SkSpan array) { + this->unpoison(); + + fData = array.data(); + fCapacity = SkToU32(array.size()); + fOwnMemory = true; + + this->poison(); + } + + void unpoison() { +#ifdef SK_SANITIZE_ADDRESS + if (fData) { + // SkDebugf("UNPOISONING %p : 0 -> %zu\n", fData, Bytes(fCapacity)); + sk_asan_unpoison_memory_region(this->begin(), Bytes(fCapacity)); + } +#endif + } + + void poison() { +#ifdef SK_SANITIZE_ADDRESS + if (fData && fCapacity > fSize) { + // SkDebugf(" POISONING %p : %zu -> %zu\n", fData, Bytes(fSize), Bytes(fCapacity)); + sk_asan_poison_memory_region(this->end(), Bytes(fCapacity - fSize)); + } +#endif + } + + void changeSize(int n) { + this->unpoison(); + fSize = n; + this->poison(); + } + + // We disable Control-Flow Integrity sanitization (go/cfi) when casting item-array buffers. + // CFI flags this code as dangerous because we are casting `buffer` to a T* while the buffer's + // contents might still be uninitialized memory. When T has a vtable, this is especially risky + // because we could hypothetically access a virtual method on fItemArray and jump to an + // unpredictable location in memory. Of course, TArray won't actually use fItemArray in this + // way, and we don't want to construct a T before the user requests one. There's no real risk + // here, so disable CFI when doing these casts. + SK_CLANG_NO_SANITIZE("cfi") + static T* TCast(void* buffer) { + return (T*)buffer; + } + + static size_t Bytes(int n) { + SkASSERT(n <= kMaxCapacity); + return SkToSizeT(n) * sizeof(T); + } + + static SkSpan Allocate(int capacity, double growthFactor = 1.0) { + return SkContainerAllocator{sizeof(T), kMaxCapacity}.allocate(capacity, growthFactor); + } + + void initData(int count) { + this->setDataFromBytes(Allocate(count)); + this->changeSize(count); + } + + void destroyAll() { + if (!this->empty()) { + T* cursor = this->begin(); + T* const end = this->end(); + do { + cursor->~T(); + cursor++; + } while (cursor < end); + } + } + + /** In the following move and copy methods, 'dst' is assumed to be uninitialized raw storage. + * In the following move methods, 'src' is destroyed leaving behind uninitialized raw storage. + */ + void copy(const T* src) { + if constexpr (std::is_trivially_copyable_v) { + if (!this->empty() && src != nullptr) { + sk_careful_memcpy(fData, src, this->size_bytes()); + } + } else { + for (int i = 0; i < this->size(); ++i) { + new (fData + i) T(src[i]); + } + } + } + + void move(int dst, int src) { + if constexpr (MEM_MOVE) { + memcpy(static_cast(&fData[dst]), + static_cast(&fData[src]), + sizeof(T)); + } else { + new (&fData[dst]) T(std::move(fData[src])); + fData[src].~T(); + } + } + + void move(void* dst) { + if constexpr (MEM_MOVE) { + sk_careful_memcpy(dst, fData, Bytes(fSize)); + } else { + for (int i = 0; i < this->size(); ++i) { + new (static_cast(dst) + Bytes(i)) T(std::move(fData[i])); + fData[i].~T(); + } + } + } + + // Helper function that makes space for n objects, adjusts the count, but does not initialize + // the new objects. + void* push_back_raw(int n) { + this->checkRealloc(n, kGrowing); + void* ptr = fData + fSize; + this->changeSize(fSize + n); + return ptr; + } + + template + SK_ALWAYS_INLINE T* growAndConstructAtEnd(Args&&... args) { + SkSpan buffer = this->preallocateNewData(/*delta=*/1, kGrowing); + T* newT = new (TCast(buffer.data()) + fSize) T(std::forward(args)...); + this->installDataAndUpdateCapacity(buffer); + + return newT; + } + + void checkRealloc(int delta, double growthFactor) { + SkASSERT(delta >= 0); + SkASSERT(fSize >= 0); + SkASSERT(fCapacity >= 0); + + // Check if there are enough remaining allocated elements to satisfy the request. + if (this->capacity() - fSize < delta) { + // Looks like we need to reallocate. + this->installDataAndUpdateCapacity(this->preallocateNewData(delta, growthFactor)); + } + } + + SkSpan preallocateNewData(int delta, double growthFactor) { + SkASSERT(delta >= 0); + SkASSERT(fSize >= 0); + SkASSERT(fCapacity >= 0); + + // Don't overflow fSize or size_t later in the memory allocation. Overflowing memory + // allocation really only applies to fSizes on 32-bit machines; on 64-bit machines this + // will probably never produce a check. Since kMaxCapacity is bounded above by INT_MAX, + // this also checks the bounds of fSize. + if (delta > kMaxCapacity - fSize) { + sk_report_container_overflow_and_die(); + } + const int newCount = fSize + delta; + + return Allocate(newCount, growthFactor); + } + + void installDataAndUpdateCapacity(SkSpan allocation) { + this->move(TCast(allocation.data())); + if (fOwnMemory) { + sk_free(fData); + } + this->setDataFromBytes(allocation); + SkASSERT(fData != nullptr); + } + + T* fData{nullptr}; + int fSize{0}; + uint32_t fOwnMemory : 1; + uint32_t fCapacity : 31; +}; + +template static inline void swap(TArray& a, TArray& b) { + a.swap(b); +} + +// Subclass of TArray that contains a pre-allocated memory block for the array. +template > +class STArray : private SkAlignedSTStorage(Nreq), T>, + public TArray { + // We round up the requested array size to the next capacity multiple. + // This space would likely otherwise go to waste. + static constexpr int N = SkContainerAllocator::RoundUp(Nreq); + static_assert(Nreq > 0); + static_assert(N >= Nreq); + + using Storage = SkAlignedSTStorage; + +public: + STArray() + : Storage{} + , TArray(this) {} // Must use () to avoid confusion with initializer_list + // when T=bool because * are convertable to bool. + + STArray(const T* array, int count) + : Storage{} + , TArray{array, count, this} {} + + STArray(std::initializer_list data) + : STArray{data.begin(), SkToInt(data.size())} {} + + explicit STArray(int reserveCount) + : STArray() { this->reserve_exact(reserveCount); } + + STArray(const STArray& that) + : STArray() { *this = that; } + + explicit STArray(const TArray& that) + : STArray() { *this = that; } + + STArray(STArray&& that) + : STArray() { *this = std::move(that); } + + explicit STArray(TArray&& that) + : STArray() { *this = std::move(that); } + + STArray& operator=(const STArray& that) { + TArray::operator=(that); + return *this; + } + + STArray& operator=(const TArray& that) { + TArray::operator=(that); + return *this; + } + + STArray& operator=(STArray&& that) { + TArray::operator=(std::move(that)); + return *this; + } + + STArray& operator=(TArray&& that) { + TArray::operator=(std::move(that)); + return *this; + } + + // Force the use of TArray for data() and size(). + using TArray::data; + using TArray::size; +}; +} // namespace skia_private +#endif // SkTArray_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkTDArray.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkTDArray.h new file mode 100644 index 0000000000..fef454bdc4 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkTDArray.h @@ -0,0 +1,235 @@ +/* + * 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 SkTDArray_DEFINED +#define SkTDArray_DEFINED + +#include "include/private/base/SkAPI.h" +#include "include/private/base/SkAssert.h" +#include "include/private/base/SkDebug.h" +#include "include/private/base/SkTo.h" + +#include +#include +#include + +class SK_SPI SkTDStorage { +public: + explicit SkTDStorage(int sizeOfT); + SkTDStorage(const void* src, int size, int sizeOfT); + + // Copy + SkTDStorage(const SkTDStorage& that); + SkTDStorage& operator= (const SkTDStorage& that); + + // Move + SkTDStorage(SkTDStorage&& that); + SkTDStorage& operator= (SkTDStorage&& that); + + ~SkTDStorage(); + + void reset(); + void swap(SkTDStorage& that); + + // Size routines + bool empty() const { return fSize == 0; } + void clear() { fSize = 0; } + int size() const { return fSize; } + void resize(int newSize); + size_t size_bytes() const { return this->bytes(fSize); } + + // Capacity routines + int capacity() const { return fCapacity; } + void reserve(int newCapacity); + void shrink_to_fit(); + + void* data() { return fStorage; } + const void* data() const { return fStorage; } + + // Deletion routines + void erase(int index, int count); + // Removes the entry at 'index' and replaces it with the last array element + void removeShuffle(int index); + + // Insertion routines + void* prepend(); + + void append(); + void append(int count); + void* append(const void* src, int count); + + void* insert(int index); + void* insert(int index, int count, const void* src); + + void pop_back() { + SkASSERT(fSize > 0); + fSize--; + } + + friend bool operator==(const SkTDStorage& a, const SkTDStorage& b); + friend bool operator!=(const SkTDStorage& a, const SkTDStorage& b) { + return !(a == b); + } + +private: + size_t bytes(int n) const { return SkToSizeT(n * fSizeOfT); } + void* address(int n) { return fStorage + this->bytes(n); } + + // Adds delta to fSize. Crash if outside [0, INT_MAX] + int calculateSizeOrDie(int delta); + + // Move the tail of the array defined by the indexes tailStart and tailEnd to dstIndex. The + // elements at dstIndex are overwritten by the tail. + void moveTail(int dstIndex, int tailStart, int tailEnd); + + // Copy src into the array at dstIndex. + void copySrc(int dstIndex, const void* src, int count); + + const int fSizeOfT; + std::byte* fStorage{nullptr}; + int fCapacity{0}; // size of the allocation in fArray (#elements) + int fSize{0}; // logical number of elements (fSize <= fCapacity) +}; + +static inline void swap(SkTDStorage& a, SkTDStorage& b) { + a.swap(b); +} + +// SkTDArray implements a std::vector-like array for raw data-only objects that do not require +// construction or destruction. The constructor and destructor for T will not be called; T objects +// will always be moved via raw memcpy. Newly created T objects will contain uninitialized memory. +template class SkTDArray { +public: + SkTDArray() : fStorage{sizeof(T)} {} + SkTDArray(const T src[], int count) : fStorage{src, count, sizeof(T)} { } + SkTDArray(const std::initializer_list& list) : SkTDArray(list.begin(), list.size()) {} + + // Copy + SkTDArray(const SkTDArray& src) : SkTDArray(src.data(), src.size()) {} + SkTDArray& operator=(const SkTDArray& src) { + fStorage = src.fStorage; + return *this; + } + + // Move + SkTDArray(SkTDArray&& src) : fStorage{std::move(src.fStorage)} {} + SkTDArray& operator=(SkTDArray&& src) { + fStorage = std::move(src.fStorage); + return *this; + } + + friend bool operator==(const SkTDArray& a, const SkTDArray& b) { + return a.fStorage == b.fStorage; + } + friend bool operator!=(const SkTDArray& a, const SkTDArray& b) { return !(a == b); } + + void swap(SkTDArray& that) { + using std::swap; + swap(fStorage, that.fStorage); + } + + bool empty() const { return fStorage.empty(); } + + // Return the number of elements in the array + int size() const { return fStorage.size(); } + + // Return the total number of elements allocated. + // Note: capacity() - size() gives you the number of elements you can add without causing an + // allocation. + int capacity() const { return fStorage.capacity(); } + + // return the number of bytes in the array: count * sizeof(T) + size_t size_bytes() const { return fStorage.size_bytes(); } + + T* data() { return static_cast(fStorage.data()); } + const T* data() const { return static_cast(fStorage.data()); } + T* begin() { return this->data(); } + const T* begin() const { return this->data(); } + T* end() { return this->data() + this->size(); } + const T* end() const { return this->data() + this->size(); } + + T& operator[](int index) { + return this->data()[sk_collection_check_bounds(index, this->size())]; + } + const T& operator[](int index) const { + return this->data()[sk_collection_check_bounds(index, this->size())]; + } + + const T& back() const { + sk_collection_not_empty(this->empty()); + return this->data()[this->size() - 1]; + } + T& back() { + sk_collection_not_empty(this->empty()); + return this->data()[this->size() - 1]; + } + + void reset() { + fStorage.reset(); + } + + void clear() { + fStorage.clear(); + } + + // Sets the number of elements in the array. + // If the array does not have space for count elements, it will increase + // the storage allocated to some amount greater than that required. + // It will never shrink the storage. + void resize(int count) { + fStorage.resize(count); + } + + void reserve(int n) { + fStorage.reserve(n); + } + + T* append() { + fStorage.append(); + return this->end() - 1; + } + T* append(int count) { + fStorage.append(count); + return this->end() - count; + } + T* append(int count, const T* src) { + return static_cast(fStorage.append(src, count)); + } + + T* insert(int index) { + return static_cast(fStorage.insert(index)); + } + T* insert(int index, int count, const T* src = nullptr) { + return static_cast(fStorage.insert(index, count, src)); + } + + void remove(int index, int count = 1) { + fStorage.erase(index, count); + } + + void removeShuffle(int index) { + fStorage.removeShuffle(index); + } + + // routines to treat the array like a stack + void push_back(const T& v) { + this->append(); + this->back() = v; + } + void pop_back() { fStorage.pop_back(); } + + void shrink_to_fit() { + fStorage.shrink_to_fit(); + } + +private: + SkTDStorage fStorage; +}; + +template static inline void swap(SkTDArray& a, SkTDArray& b) { a.swap(b); } + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkTFitsIn.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkTFitsIn.h new file mode 100644 index 0000000000..365748abef --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkTFitsIn.h @@ -0,0 +1,105 @@ +/* + * 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 SkTFitsIn_DEFINED +#define SkTFitsIn_DEFINED + +#include "include/private/base/SkDebug.h" + +#include +#include +#include + +/** + * std::underlying_type is only defined for enums. For integral types, we just want the type. + */ +template +struct sk_strip_enum { + typedef T type; +}; + +template +struct sk_strip_enum::value>::type> { + typedef typename std::underlying_type::type type; +}; + + +/** + * In C++ an unsigned to signed cast where the source value cannot be represented in the destination + * type results in an implementation defined destination value. Unlike C, C++ does not allow a trap. + * This makes "(S)(D)s == s" a possibly useful test. However, there are two cases where this is + * incorrect: + * + * when testing if a value of a smaller signed type can be represented in a larger unsigned type + * (int8_t)(uint16_t)-1 == -1 => (int8_t)0xFFFF == -1 => [implementation defined] == -1 + * + * when testing if a value of a larger unsigned type can be represented in a smaller signed type + * (uint16_t)(int8_t)0xFFFF == 0xFFFF => (uint16_t)-1 == 0xFFFF => 0xFFFF == 0xFFFF => true. + * + * Consider the cases: + * u = unsigned, less digits + * U = unsigned, more digits + * s = signed, less digits + * S = signed, more digits + * v is the value we're considering. + * + * u -> U: (u)(U)v == v, trivially true + * U -> u: (U)(u)v == v, both casts well defined, test works + * s -> S: (s)(S)v == v, trivially true + * S -> s: (S)(s)v == v, first cast implementation value, second cast defined, test works + * s -> U: (s)(U)v == v, *this is bad*, the second cast results in implementation defined value + * S -> u: (S)(u)v == v, the second cast is required to prevent promotion of rhs to unsigned + * u -> S: (u)(S)v == v, trivially true + * U -> s: (U)(s)v == v, *this is bad*, + * first cast results in implementation defined value, + * second cast is defined. However, this creates false positives + * uint16_t x = 0xFFFF + * (uint16_t)(int8_t)x == x + * => (uint16_t)-1 == x + * => 0xFFFF == x + * => true + * + * So for the eight cases three are trivially true, three more are valid casts, and two are special. + * The two 'full' checks which otherwise require two comparisons are valid cast checks. + * The two remaining checks s -> U [v >= 0] and U -> s [v <= max(s)] can be done with one op. + */ + +template +static constexpr inline +typename std::enable_if<(std::is_integral::value || std::is_enum::value) && + (std::is_integral::value || std::is_enum::value), bool>::type +/*bool*/ SkTFitsIn(S src) { + // Ensure that is_signed and is_unsigned are passed the arithmetic underlyng types of enums. + using Sa = typename sk_strip_enum::type; + using Da = typename sk_strip_enum::type; + + // SkTFitsIn() is used in public headers, so needs to be written targeting at most C++11. + return + + // E.g. (int8_t)(uint8_t) int8_t(-1) == -1, but the uint8_t == 255, not -1. + (std::is_signed::value && std::is_unsigned::value && sizeof(Sa) <= sizeof(Da)) ? + (S)0 <= src : + + // E.g. (uint8_t)(int8_t) uint8_t(255) == 255, but the int8_t == -1. + (std::is_signed::value && std::is_unsigned::value && sizeof(Da) <= sizeof(Sa)) ? + src <= (S)std::numeric_limits::max() : + +#if !defined(SK_DEBUG) && !defined(__MSVC_RUNTIME_CHECKS ) + // Correct (simple) version. This trips up MSVC's /RTCc run-time checking. + (S)(D)src == src; +#else + // More complex version that's safe with /RTCc. Used in all debug builds, for coverage. + (std::is_signed::value) ? + (intmax_t)src >= (intmax_t)std::numeric_limits::min() && + (intmax_t)src <= (intmax_t)std::numeric_limits::max() : + + // std::is_unsigned ? + (uintmax_t)src <= (uintmax_t)std::numeric_limits::max(); +#endif +} + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkTLogic.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkTLogic.h new file mode 100644 index 0000000000..26f363c946 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkTLogic.h @@ -0,0 +1,56 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * + * This header provides some std:: features early in the skstd namespace + * and several Skia-specific additions in the sknonstd namespace. + */ + +#ifndef SkTLogic_DEFINED +#define SkTLogic_DEFINED + +#include +#include +#include "include/private/base/SkTo.h" + +// The sknonstd namespace contains things we would like to be proposed and feel std-ish. +namespace sknonstd { + +// The name 'copy' here is fraught with peril. In this case it means 'append', not 'overwrite'. +// Alternate proposed names are 'propagate', 'augment', or 'append' (and 'add', but already taken). +// std::experimental::propagate_const already exists for other purposes in TSv2. +// These also follow the pattern used by boost. +template struct copy_const { + using type = std::conditional_t::value, std::add_const_t, D>; +}; +template using copy_const_t = typename copy_const::type; + +template struct copy_volatile { + using type = std::conditional_t::value, std::add_volatile_t, D>; +}; +template using copy_volatile_t = typename copy_volatile::type; + +template struct copy_cv { + using type = copy_volatile_t, S>; +}; +template using copy_cv_t = typename copy_cv::type; + +// The name 'same' here means 'overwrite'. +// Alternate proposed names are 'replace', 'transfer', or 'qualify_from'. +// same_xxx can be written as copy_xxx, S> +template using same_const = copy_const, S>; +template using same_const_t = typename same_const::type; +template using same_volatile =copy_volatile,S>; +template using same_volatile_t = typename same_volatile::type; +template using same_cv = copy_cv, S>; +template using same_cv_t = typename same_cv::type; + +} // namespace sknonstd + +template +constexpr int SkCount(const Container& c) { return SkTo(std::size(c)); } + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkTPin.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkTPin.h new file mode 100644 index 0000000000..c824c44640 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkTPin.h @@ -0,0 +1,23 @@ +/* + * 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 SkTPin_DEFINED +#define SkTPin_DEFINED + +#include + +/** @return x pinned (clamped) between lo and hi, inclusively. + + Unlike std::clamp(), SkTPin() always returns a value between lo and hi. + If x is NaN, SkTPin() returns lo but std::clamp() returns NaN. +*/ +template +static constexpr const T& SkTPin(const T& x, const T& lo, const T& hi) { + return std::max(lo, std::min(x, hi)); +} + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkTemplates.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkTemplates.h new file mode 100644 index 0000000000..3c9ca55125 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkTemplates.h @@ -0,0 +1,446 @@ +/* + * 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 SkTemplates_DEFINED +#define SkTemplates_DEFINED + +#include "include/private/base/SkAlign.h" +#include "include/private/base/SkAssert.h" +#include "include/private/base/SkDebug.h" +#include "include/private/base/SkMalloc.h" +#include "include/private/base/SkTLogic.h" +#include "include/private/base/SkTo.h" + +#include +#include +#include +#include +#include +#include +#include + + +/** \file SkTemplates.h + + This file contains light-weight template classes for type-safe and exception-safe + resource management. +*/ + +/** + * Marks a local variable as known to be unused (to avoid warnings). + * Note that this does *not* prevent the local variable from being optimized away. + */ +template inline void sk_ignore_unused_variable(const T&) { } + +/** + * This is a general purpose absolute-value function. + * See SkAbs32 in (SkSafe32.h) for a 32-bit int specific version that asserts. + */ +template static inline T SkTAbs(T value) { + if (value < 0) { + value = -value; + } + return value; +} + +/** + * Returns a pointer to a D which comes immediately after S[count]. + */ +template inline D* SkTAfter(S* ptr, size_t count = 1) { + return reinterpret_cast(ptr + count); +} + +/** + * Returns a pointer to a D which comes byteOffset bytes after S. + */ +template inline D* SkTAddOffset(S* ptr, ptrdiff_t byteOffset) { + // The intermediate char* has the same cv-ness as D as this produces better error messages. + // This relies on the fact that reinterpret_cast can add constness, but cannot remove it. + return reinterpret_cast(reinterpret_cast*>(ptr) + byteOffset); +} + +template struct SkOverloadedFunctionObject { + template + auto operator()(Args&&... args) const -> decltype(P(std::forward(args)...)) { + return P(std::forward(args)...); + } +}; + +template using SkFunctionObject = + SkOverloadedFunctionObject, F>; + +/** \class SkAutoTCallVProc + + Call a function when this goes out of scope. The template uses two + parameters, the object, and a function that is to be called in the destructor. + If release() is called, the object reference is set to null. If the object + reference is null when the destructor is called, we do not call the + function. +*/ +template class SkAutoTCallVProc + : public std::unique_ptr> { + using inherited = std::unique_ptr>; +public: + using inherited::inherited; + SkAutoTCallVProc(const SkAutoTCallVProc&) = delete; + SkAutoTCallVProc(SkAutoTCallVProc&& that) : inherited(std::move(that)) {} + + operator T*() const { return this->get(); } +}; + + +namespace skia_private { +/** Allocate an array of T elements, and free the array in the destructor + */ +template class AutoTArray { +public: + AutoTArray() {} + // Allocate size number of T elements + explicit AutoTArray(size_t size) { + fSize = check_size_bytes_too_big(size); + fData.reset(size > 0 ? new T[size] : nullptr); + } + + // TODO: remove when all uses are gone. + explicit AutoTArray(int size) : AutoTArray(SkToSizeT(size)) {} + + AutoTArray(AutoTArray&& other) : fData(std::move(other.fData)) { + fSize = std::exchange(other.fSize, 0); + } + AutoTArray& operator=(AutoTArray&& other) { + if (this != &other) { + fData = std::move(other.fData); + fSize = std::exchange(other.fSize, 0); + } + return *this; + } + + // Reallocates given a new count. Reallocation occurs even if new count equals old count. + void reset(size_t count = 0) { + *this = AutoTArray(count); + } + + T* get() const { return fData.get(); } + + T& operator[](size_t index) const { + return fData[sk_collection_check_bounds(index, fSize)]; + } + + const T* data() const { return fData.get(); } + T* data() { return fData.get(); } + + size_t size() const { return fSize; } + bool empty() const { return fSize == 0; } + size_t size_bytes() const { return sizeof(T) * fSize; } + + T* begin() { + return fData; + } + const T* begin() const { + return fData; + } + + // It's safe to use fItemArray + fSize because if fItemArray is nullptr then adding 0 is + // valid and returns nullptr. See [expr.add] in the C++ standard. + T* end() { + if (fData == nullptr) { + SkASSERT(fSize == 0); + } + return fData + fSize; + } + const T* end() const { + if (fData == nullptr) { + SkASSERT(fSize == 0); + } + return fData + fSize; + } + +private: + std::unique_ptr fData; + size_t fSize = 0; +}; + +/** Wraps AutoTArray, with room for kCountRequested elements preallocated. + */ +template class AutoSTArray { +public: + AutoSTArray(AutoSTArray&&) = delete; + AutoSTArray(const AutoSTArray&) = delete; + AutoSTArray& operator=(AutoSTArray&&) = delete; + AutoSTArray& operator=(const AutoSTArray&) = delete; + + /** Initialize with no objects */ + AutoSTArray() { + fArray = nullptr; + fCount = 0; + } + + /** Allocate count number of T elements + */ + AutoSTArray(int count) { + fArray = nullptr; + fCount = 0; + this->reset(count); + } + + ~AutoSTArray() { + this->reset(0); + } + + /** Destroys previous objects in the array and default constructs count number of objects */ + void reset(int count) { + T* start = fArray; + T* iter = start + fCount; + while (iter > start) { + (--iter)->~T(); + } + + SkASSERT(count >= 0); + if (fCount != count) { + if (fCount > kCount) { + // 'fArray' was allocated last time so free it now + SkASSERT((T*) fStorage != fArray); + sk_free(fArray); + } + + if (count > kCount) { + fArray = (T*) sk_malloc_throw(count, sizeof(T)); + } else if (count > 0) { + fArray = (T*) fStorage; + } else { + fArray = nullptr; + } + + fCount = count; + } + + iter = fArray; + T* stop = fArray + count; + while (iter < stop) { + new (iter++) T; + } + } + + /** Return the number of T elements in the array + */ + int count() const { return fCount; } + + /** Return the array of T elements. Will be NULL if count == 0 + */ + T* get() const { return fArray; } + + T* begin() { return fArray; } + + const T* begin() const { return fArray; } + + T* end() { return fArray + fCount; } + + const T* end() const { return fArray + fCount; } + + /** Return the nth element in the array + */ + T& operator[](int index) const { + return fArray[sk_collection_check_bounds(index, fCount)]; + } + + /** Aliases matching other types, like std::vector. */ + const T* data() const { return fArray; } + T* data() { return fArray; } + size_t size() const { return fCount; } + +private: +#if defined(SK_BUILD_FOR_GOOGLE3) + // Stack frame size is limited for SK_BUILD_FOR_GOOGLE3. 4k is less than the actual max, + // but some functions have multiple large stack allocations. + static const int kMaxBytes = 4 * 1024; + static const int kCount = kCountRequested * sizeof(T) > kMaxBytes + ? kMaxBytes / sizeof(T) + : kCountRequested; +#else + static const int kCount = kCountRequested; +#endif + + int fCount; + T* fArray; + alignas(T) char fStorage[kCount * sizeof(T)]; +}; + +/** Manages an array of T elements, freeing the array in the destructor. + * Does NOT call any constructors/destructors on T (T must be POD). + */ +template ::value && + std::is_trivially_destructible::value>> +class AutoTMalloc { +public: + /** Takes ownership of the ptr. The ptr must be a value which can be passed to sk_free. */ + explicit AutoTMalloc(T* ptr = nullptr) : fPtr(ptr) {} + + /** Allocates space for 'count' Ts. */ + explicit AutoTMalloc(size_t count) + : fPtr(count ? (T*)sk_malloc_throw(count, sizeof(T)) : nullptr) {} + + AutoTMalloc(AutoTMalloc&&) = default; + AutoTMalloc& operator=(AutoTMalloc&&) = default; + + /** Resize the memory area pointed to by the current ptr preserving contents. */ + void realloc(size_t count) { + fPtr.reset(count ? (T*)sk_realloc_throw(fPtr.release(), count * sizeof(T)) : nullptr); + } + + /** Resize the memory area pointed to by the current ptr without preserving contents. */ + T* reset(size_t count = 0) { + fPtr.reset(count ? (T*)sk_malloc_throw(count, sizeof(T)) : nullptr); + return this->get(); + } + + T* get() const { return fPtr.get(); } + + operator T*() { return fPtr.get(); } + + operator const T*() const { return fPtr.get(); } + + T& operator[](int index) { return fPtr.get()[index]; } + + const T& operator[](int index) const { return fPtr.get()[index]; } + + /** Aliases matching other types, like std::vector. */ + const T* data() const { return fPtr.get(); } + T* data() { return fPtr.get(); } + + /** + * Transfer ownership of the ptr to the caller, setting the internal + * pointer to NULL. Note that this differs from get(), which also returns + * the pointer, but it does not transfer ownership. + */ + T* release() { return fPtr.release(); } + +private: + std::unique_ptr> fPtr; +}; + +template ::value && + std::is_trivially_destructible::value>> +class AutoSTMalloc { +public: + AutoSTMalloc() : fPtr(fTStorage) {} + + AutoSTMalloc(size_t count) { + if (count > kCount) { + fPtr = (T*)sk_malloc_throw(count, sizeof(T)); + } else if (count) { + fPtr = fTStorage; + } else { + fPtr = nullptr; + } + } + + AutoSTMalloc(AutoSTMalloc&&) = delete; + AutoSTMalloc(const AutoSTMalloc&) = delete; + AutoSTMalloc& operator=(AutoSTMalloc&&) = delete; + AutoSTMalloc& operator=(const AutoSTMalloc&) = delete; + + ~AutoSTMalloc() { + if (fPtr != fTStorage) { + sk_free(fPtr); + } + } + + // doesn't preserve contents + T* reset(size_t count) { + if (fPtr != fTStorage) { + sk_free(fPtr); + } + if (count > kCount) { + fPtr = (T*)sk_malloc_throw(count, sizeof(T)); + } else if (count) { + fPtr = fTStorage; + } else { + fPtr = nullptr; + } + return fPtr; + } + + T* get() const { return fPtr; } + + operator T*() { + return fPtr; + } + + operator const T*() const { + return fPtr; + } + + T& operator[](int index) { + return fPtr[index]; + } + + const T& operator[](int index) const { + return fPtr[index]; + } + + /** Aliases matching other types, like std::vector. */ + const T* data() const { return fPtr; } + T* data() { return fPtr; } + + // Reallocs the array, can be used to shrink the allocation. Makes no attempt to be intelligent + void realloc(size_t count) { + if (count > kCount) { + if (fPtr == fTStorage) { + fPtr = (T*)sk_malloc_throw(count, sizeof(T)); + memcpy((void*)fPtr, fTStorage, kCount * sizeof(T)); + } else { + fPtr = (T*)sk_realloc_throw(fPtr, count, sizeof(T)); + } + } else if (count) { + if (fPtr != fTStorage) { + fPtr = (T*)sk_realloc_throw(fPtr, count, sizeof(T)); + } + } else { + this->reset(0); + } + } + +private: + // Since we use uint32_t storage, we might be able to get more elements for free. + static const size_t kCountWithPadding = SkAlign4(kCountRequested*sizeof(T)) / sizeof(T); +#if defined(SK_BUILD_FOR_GOOGLE3) + // Stack frame size is limited for SK_BUILD_FOR_GOOGLE3. 4k is less than the actual max, but some functions + // have multiple large stack allocations. + static const size_t kMaxBytes = 4 * 1024; + static const size_t kCount = kCountRequested * sizeof(T) > kMaxBytes + ? kMaxBytes / sizeof(T) + : kCountWithPadding; +#else + static const size_t kCount = kCountWithPadding; +#endif + + T* fPtr; + union { + uint32_t fStorage32[SkAlign4(kCount*sizeof(T)) >> 2]; + T fTStorage[1]; // do NOT want to invoke T::T() + }; +}; + +using UniqueVoidPtr = std::unique_ptr>; + +} // namespace skia_private + +template +constexpr auto SkMakeArrayFromIndexSequence(C c, std::index_sequence is) +-> std::array())), sizeof...(Is)> { + return {{ c(Is)... }}; +} + +template constexpr auto SkMakeArray(C c) +-> std::array::value_type>())), N> { + return SkMakeArrayFromIndexSequence(c, std::make_index_sequence{}); +} + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkThreadAnnotations.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkThreadAnnotations.h new file mode 100644 index 0000000000..a67fbaaca0 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkThreadAnnotations.h @@ -0,0 +1,104 @@ +/* + * 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 SkThreadAnnotations_DEFINED +#define SkThreadAnnotations_DEFINED + +#include "include/private/base/SkFeatures.h" // IWYU pragma: keep + +// The bulk of this code is cribbed from: +// http://clang.llvm.org/docs/ThreadSafetyAnalysis.html + +#if defined(__clang__) && (!defined(SWIG)) +#define SK_THREAD_ANNOTATION_ATTRIBUTE(x) __attribute__((x)) +#else +#define SK_THREAD_ANNOTATION_ATTRIBUTE(x) // no-op +#endif + +#define SK_CAPABILITY(x) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(capability(x)) + +#define SK_SCOPED_CAPABILITY \ + SK_THREAD_ANNOTATION_ATTRIBUTE(scoped_lockable) + +#define SK_GUARDED_BY(x) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(guarded_by(x)) + +#define SK_PT_GUARDED_BY(x) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(pt_guarded_by(x)) + +#define SK_ACQUIRED_BEFORE(...) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(acquired_before(__VA_ARGS__)) + +#define SK_ACQUIRED_AFTER(...) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(acquired_after(__VA_ARGS__)) + +#define SK_REQUIRES(...) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(requires_capability(__VA_ARGS__)) + +#define SK_REQUIRES_SHARED(...) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(requires_shared_capability(__VA_ARGS__)) + +#define SK_ACQUIRE(...) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(acquire_capability(__VA_ARGS__)) + +#define SK_ACQUIRE_SHARED(...) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(acquire_shared_capability(__VA_ARGS__)) + +// Would be SK_RELEASE, but that is already in use as SK_DEBUG vs. SK_RELEASE. +#define SK_RELEASE_CAPABILITY(...) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(release_capability(__VA_ARGS__)) + +// For symmetry with SK_RELEASE_CAPABILITY. +#define SK_RELEASE_SHARED_CAPABILITY(...) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(release_shared_capability(__VA_ARGS__)) + +#define SK_TRY_ACQUIRE(...) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(try_acquire_capability(__VA_ARGS__)) + +#define SK_TRY_ACQUIRE_SHARED(...) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(try_acquire_shared_capability(__VA_ARGS__)) + +#define SK_EXCLUDES(...) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(locks_excluded(__VA_ARGS__)) + +#define SK_ASSERT_CAPABILITY(x) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(assert_capability(x)) + +#define SK_ASSERT_SHARED_CAPABILITY(x) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(assert_shared_capability(x)) + +#define SK_RETURN_CAPABILITY(x) \ + SK_THREAD_ANNOTATION_ATTRIBUTE(lock_returned(x)) + +#define SK_NO_THREAD_SAFETY_ANALYSIS \ + SK_THREAD_ANNOTATION_ATTRIBUTE(no_thread_safety_analysis) + +#if defined(SK_BUILD_FOR_GOOGLE3) && !defined(SK_BUILD_FOR_WASM_IN_GOOGLE3) \ + && !defined(SK_BUILD_FOR_WIN) + extern "C" { + void __google_cxa_guard_acquire_begin(void) __attribute__((weak)); + void __google_cxa_guard_acquire_end (void) __attribute__((weak)); + } + static inline void sk_potentially_blocking_region_begin() { + if (&__google_cxa_guard_acquire_begin) { + __google_cxa_guard_acquire_begin(); + } + } + static inline void sk_potentially_blocking_region_end() { + if (&__google_cxa_guard_acquire_end) { + __google_cxa_guard_acquire_end(); + } + } + #define SK_POTENTIALLY_BLOCKING_REGION_BEGIN sk_potentially_blocking_region_begin() + #define SK_POTENTIALLY_BLOCKING_REGION_END sk_potentially_blocking_region_end() +#else + #define SK_POTENTIALLY_BLOCKING_REGION_BEGIN + #define SK_POTENTIALLY_BLOCKING_REGION_END +#endif + +#endif // SkThreadAnnotations_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkThreadID.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkThreadID.h new file mode 100644 index 0000000000..18984884c9 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkThreadID.h @@ -0,0 +1,23 @@ +/* + * 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 SkThreadID_DEFINED +#define SkThreadID_DEFINED + +#include "include/private/base/SkAPI.h" +#include "include/private/base/SkDebug.h" + +#include + +typedef int64_t SkThreadID; + +// SkMutex.h uses SkGetThreadID in debug only code. +SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID(); + +const SkThreadID kIllegalThreadID = 0; + +#endif // SkThreadID_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkTo.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkTo.h new file mode 100644 index 0000000000..51ccafeeaf --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkTo.h @@ -0,0 +1,39 @@ +/* + * 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 SkTo_DEFINED +#define SkTo_DEFINED + +#include "include/private/base/SkAssert.h" +#include "include/private/base/SkTFitsIn.h" + +#include +#include + +template constexpr D SkTo(S s) { + return SkASSERT(SkTFitsIn(s)), + static_cast(s); +} + +template constexpr int8_t SkToS8(S x) { return SkTo(x); } +template constexpr uint8_t SkToU8(S x) { return SkTo(x); } +template constexpr int16_t SkToS16(S x) { return SkTo(x); } +template constexpr uint16_t SkToU16(S x) { return SkTo(x); } +template constexpr int32_t SkToS32(S x) { return SkTo(x); } +template constexpr uint32_t SkToU32(S x) { return SkTo(x); } +template constexpr int64_t SkToS64(S x) { return SkTo(x); } +template constexpr uint64_t SkToU64(S x) { return SkTo(x); } +template constexpr int SkToInt(S x) { return SkTo(x); } +template constexpr unsigned SkToUInt(S x) { return SkTo(x); } +template constexpr size_t SkToSizeT(S x) { return SkTo(x); } + +/** @return false or true based on the condition +*/ +template static constexpr bool SkToBool(const T& x) { + return (bool)x; +} + +#endif // SkTo_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkTypeTraits.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkTypeTraits.h new file mode 100644 index 0000000000..736f789776 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/base/SkTypeTraits.h @@ -0,0 +1,33 @@ +// 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 SkTypeTraits_DEFINED +#define SkTypeTraits_DEFINED + +#include +#include + +// Trait for identifying types which are relocatable via memcpy, for container optimizations. +template +struct sk_has_trivially_relocatable_member : std::false_type {}; + +// Types can declare themselves trivially relocatable with a public +// using sk_is_trivially_relocatable = std::true_type; +template +struct sk_has_trivially_relocatable_member> + : T::sk_is_trivially_relocatable {}; + +// By default, all trivially copyable types are trivially relocatable. +template +struct sk_is_trivially_relocatable + : std::disjunction, sk_has_trivially_relocatable_member>{}; + +// Here be some dragons: while technically not guaranteed, we count on all sane unique_ptr +// implementations to be trivially relocatable. +template +struct sk_is_trivially_relocatable> : std::true_type {}; + +template +inline constexpr bool sk_is_trivially_relocatable_v = sk_is_trivially_relocatable::value; + +#endif // SkTypeTraits_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/chromium/GrDeferredDisplayList.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/chromium/GrDeferredDisplayList.h new file mode 100644 index 0000000000..e54b51c43b --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/chromium/GrDeferredDisplayList.h @@ -0,0 +1,120 @@ +/* + * 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 GrDeferredDisplayList_DEFINED +#define GrDeferredDisplayList_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" +#include "include/gpu/GrRecordingContext.h" +#include "include/private/base/SkTArray.h" +#include "include/private/chromium/GrSurfaceCharacterization.h" + +class GrDirectContext; +class GrRenderTargetProxy; +class GrRenderTask; +class GrDeferredDisplayListPriv; +class SkSurface; + +/* + * This class contains pre-processed gpu operations that can be replayed into + * an SkSurface via SkSurface::draw(GrDeferredDisplayList*). + */ +class GrDeferredDisplayList : public SkNVRefCnt { +public: + SK_API ~GrDeferredDisplayList(); + + SK_API const GrSurfaceCharacterization& characterization() const { + return fCharacterization; + } + /** + * Iterate through the programs required by the DDL. + */ + class SK_API ProgramIterator { + public: + ProgramIterator(GrDirectContext*, GrDeferredDisplayList*); + ~ProgramIterator(); + + // This returns true if any work was done. Getting a cache hit does not count as work. + bool compile(); + bool done() const; + void next(); + + private: + GrDirectContext* fDContext; + const skia_private::TArray& fProgramData; + int fIndex; + }; + + // Provides access to functions that aren't part of the public API. + GrDeferredDisplayListPriv priv(); + const GrDeferredDisplayListPriv priv() const; // NOLINT(readability-const-return-type) + +private: + friend class GrDrawingManager; // for access to 'fRenderTasks', 'fLazyProxyData', 'fArenas' + friend class GrDeferredDisplayListRecorder; // for access to 'fLazyProxyData' + friend class GrDeferredDisplayListPriv; + + // This object is the source from which the lazy proxy backing the DDL will pull its backing + // texture when the DDL is replayed. It has to be separately ref counted bc the lazy proxy + // can outlive the DDL. + class LazyProxyData : public SkRefCnt { + public: + // Upon being replayed - this field will be filled in (by the DrawingManager) with the + // proxy backing the destination SkSurface. Note that, since there is no good place to + // clear it, it can become a dangling pointer. Additionally, since the renderTargetProxy + // doesn't get a ref here, the SkSurface that owns it must remain alive until the DDL + // is flushed. + // TODO: the drawing manager could ref the renderTargetProxy for the DDL and then add + // a renderingTask to unref it after the DDL's ops have been executed. + GrRenderTargetProxy* fReplayDest = nullptr; + }; + + SK_API GrDeferredDisplayList(const GrSurfaceCharacterization& characterization, + sk_sp fTargetProxy, + sk_sp); + + const skia_private::TArray& programData() const { + return fProgramData; + } + + const GrSurfaceCharacterization fCharacterization; + + // These are ordered such that the destructor cleans op tasks up first (which may refer back + // to the arena and memory pool in their destructors). + GrRecordingContext::OwnedArenas fArenas; + skia_private::TArray> fRenderTasks; + + skia_private::TArray fProgramData; + sk_sp fTargetProxy; + sk_sp fLazyProxyData; +}; + +namespace skgpu::ganesh { +/** Draws the deferred display list created via a GrDeferredDisplayListRecorder. + If the deferred display list is not compatible with the surface, the draw is skipped + and false is return. + + The xOffset and yOffset parameters are experimental and, if not both zero, will cause + the draw to be ignored. + When implemented, if xOffset or yOffset are non-zero, the DDL will be drawn offset by that + amount into the surface. + + @param SkSurface The surface to apply the commands to, cannot be nullptr. + @param ddl drawing commands, cannot be nullptr. + @return false if ddl is not compatible + + example: https://fiddle.skia.org/c/@Surface_draw_2 +*/ +SK_API bool DrawDDL(SkSurface*, + sk_sp ddl); + +SK_API bool DrawDDL(sk_sp, + sk_sp ddl); +} + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/chromium/GrDeferredDisplayListRecorder.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/chromium/GrDeferredDisplayListRecorder.h new file mode 100644 index 0000000000..f66cb94d0c --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/chromium/GrDeferredDisplayListRecorder.h @@ -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 GrDeferredDisplayListRecorder_DEFINED +#define GrDeferredDisplayListRecorder_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" +#include "include/private/chromium/GrDeferredDisplayList.h" +#include "include/private/chromium/GrSurfaceCharacterization.h" + +class GrRecordingContext; +class GrRenderTargetProxy; +class SkCanvas; +class SkSurface; + +/* + * This class is intended to be used as: + * Get a GrSurfaceCharacterization representing the intended gpu-backed destination SkSurface + * Create one of these (a GrDeferredDisplayListRecorder) on the stack + * Get the canvas and render into it + * Snap off and hold on to a GrDeferredDisplayList + * Once your app actually needs the pixels, call skgpu::ganesh::DrawDDL(GrDeferredDisplayList*) + * + * This class never accesses the GPU but performs all the cpu work it can. It + * is thread-safe (i.e., one can break a scene into tiles and perform their cpu-side + * work in parallel ahead of time). + */ +class SK_API GrDeferredDisplayListRecorder { +public: + GrDeferredDisplayListRecorder(const GrSurfaceCharacterization&); + ~GrDeferredDisplayListRecorder(); + + const GrSurfaceCharacterization& characterization() const { + return fCharacterization; + } + + // The backing canvas will become invalid (and this entry point will return + // null) once 'detach' is called. + // Note: ownership of the SkCanvas is not transferred via this call. + SkCanvas* getCanvas(); + + sk_sp detach(); + +private: + GrDeferredDisplayListRecorder(const GrDeferredDisplayListRecorder&) = delete; + GrDeferredDisplayListRecorder& operator=(const GrDeferredDisplayListRecorder&) = delete; + + bool init(); + + const GrSurfaceCharacterization fCharacterization; + sk_sp fContext; + sk_sp fTargetProxy; + sk_sp fLazyProxyData; + sk_sp fSurface; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/chromium/GrPromiseImageTexture.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/chromium/GrPromiseImageTexture.h new file mode 100644 index 0000000000..0f144c92f1 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/chromium/GrPromiseImageTexture.h @@ -0,0 +1,43 @@ +/* + * 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 GrPromiseImageTexture_DEFINED +#define GrPromiseImageTexture_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" +#include "include/gpu/GrBackendSurface.h" +/** + * This type is used to fulfill textures for PromiseImages. Once an instance is returned from a + * PromiseImageTextureFulfillProc the GrBackendTexture it wraps must remain valid until the + * corresponding PromiseImageTextureReleaseProc is called. + */ +class SK_API GrPromiseImageTexture : public SkNVRefCnt { +public: + GrPromiseImageTexture() = delete; + GrPromiseImageTexture(const GrPromiseImageTexture&) = delete; + GrPromiseImageTexture(GrPromiseImageTexture&&) = delete; + ~GrPromiseImageTexture(); + GrPromiseImageTexture& operator=(const GrPromiseImageTexture&) = delete; + GrPromiseImageTexture& operator=(GrPromiseImageTexture&&) = delete; + + static sk_sp Make(const GrBackendTexture& backendTexture) { + if (!backendTexture.isValid()) { + return nullptr; + } + return sk_sp(new GrPromiseImageTexture(backendTexture)); + } + + GrBackendTexture backendTexture() const { return fBackendTexture; } + +private: + explicit GrPromiseImageTexture(const GrBackendTexture& backendTexture); + + GrBackendTexture fBackendTexture; +}; + +#endif // GrPromiseImageTexture_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/chromium/GrSurfaceCharacterization.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/chromium/GrSurfaceCharacterization.h new file mode 100644 index 0000000000..ecf3f92f9d --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/chromium/GrSurfaceCharacterization.h @@ -0,0 +1,211 @@ +/* + * 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 GrSurfaceCharacterization_DEFINED +#define GrSurfaceCharacterization_DEFINED + +#include "include/core/SkColorSpace.h" // IWYU pragma: keep +#include "include/core/SkColorType.h" +#include "include/core/SkImageInfo.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkSize.h" +#include "include/core/SkSurfaceProps.h" +#include "include/core/SkTypes.h" +#include "include/gpu/GpuTypes.h" +#include "include/gpu/GrBackendSurface.h" +#include "include/gpu/GrContextThreadSafeProxy.h" +#include "include/gpu/GrTypes.h" +#include "include/private/base/SkDebug.h" + +#include +#include + +/** \class GrSurfaceCharacterization + A surface characterization contains all the information Ganesh requires to makes its internal + rendering decisions. When passed into a GrDeferredDisplayListRecorder it will copy the + data and pass it on to the GrDeferredDisplayList if/when it is created. Note that both of + those objects (the Recorder and the DisplayList) will take a ref on the + GrContextThreadSafeProxy and SkColorSpace objects. +*/ +class SK_API GrSurfaceCharacterization { +public: + enum class Textureable : bool { kNo = false, kYes = true }; + enum class UsesGLFBO0 : bool { kNo = false, kYes = true }; + // This flag indicates that the backing VkImage for this Vulkan surface will have the + // VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT set. This bit allows skia to handle advanced blends + // more optimally in a shader by being able to directly read the dst values. + enum class VkRTSupportsInputAttachment : bool { kNo = false, kYes = true }; + // This flag indicates if the surface is wrapping a raw Vulkan secondary command buffer. + enum class VulkanSecondaryCBCompatible : bool { kNo = false, kYes = true }; + + GrSurfaceCharacterization() + : fCacheMaxResourceBytes(0) + , fOrigin(kBottomLeft_GrSurfaceOrigin) + , fSampleCnt(0) + , fIsTextureable(Textureable::kYes) + , fIsMipmapped(skgpu::Mipmapped::kYes) + , fUsesGLFBO0(UsesGLFBO0::kNo) + , fVulkanSecondaryCBCompatible(VulkanSecondaryCBCompatible::kNo) + , fIsProtected(skgpu::Protected::kNo) + , fSurfaceProps() {} + + GrSurfaceCharacterization(GrSurfaceCharacterization&&) = default; + GrSurfaceCharacterization& operator=(GrSurfaceCharacterization&&) = default; + + GrSurfaceCharacterization(const GrSurfaceCharacterization&) = default; + GrSurfaceCharacterization& operator=(const GrSurfaceCharacterization& other) = default; + bool operator==(const GrSurfaceCharacterization& other) const; + bool operator!=(const GrSurfaceCharacterization& other) const { + return !(*this == other); + } + + /* + * Return a new surface characterization with the only difference being a different width + * and height + */ + GrSurfaceCharacterization createResized(int width, int height) const; + + /* + * Return a new surface characterization with only a replaced color space + */ + GrSurfaceCharacterization createColorSpace(sk_sp) const; + + /* + * Return a new surface characterization with the backend format replaced. A colorType + * must also be supplied to indicate the interpretation of the new format. + */ + GrSurfaceCharacterization createBackendFormat(SkColorType colorType, + const GrBackendFormat& backendFormat) const; + + /* + * Return a new surface characterization with just a different use of FBO0 (in GL) + */ + GrSurfaceCharacterization createFBO0(bool usesGLFBO0) const; + + GrContextThreadSafeProxy* contextInfo() const { return fContextInfo.get(); } + sk_sp refContextInfo() const { return fContextInfo; } + size_t cacheMaxResourceBytes() const { return fCacheMaxResourceBytes; } + + bool isValid() const { return kUnknown_SkColorType != fImageInfo.colorType(); } + + const SkImageInfo& imageInfo() const { return fImageInfo; } + const GrBackendFormat& backendFormat() const { return fBackendFormat; } + GrSurfaceOrigin origin() const { return fOrigin; } + SkISize dimensions() const { return fImageInfo.dimensions(); } + int width() const { return fImageInfo.width(); } + int height() const { return fImageInfo.height(); } + SkColorType colorType() const { return fImageInfo.colorType(); } + int sampleCount() const { return fSampleCnt; } + bool isTextureable() const { return Textureable::kYes == fIsTextureable; } + bool isMipMapped() const { return skgpu::Mipmapped::kYes == fIsMipmapped; } + bool usesGLFBO0() const { return UsesGLFBO0::kYes == fUsesGLFBO0; } + bool vkRTSupportsInputAttachment() const { + return VkRTSupportsInputAttachment::kYes == fVkRTSupportsInputAttachment; + } + bool vulkanSecondaryCBCompatible() const { + return VulkanSecondaryCBCompatible::kYes == fVulkanSecondaryCBCompatible; + } + skgpu::Protected isProtected() const { return fIsProtected; } + SkColorSpace* colorSpace() const { return fImageInfo.colorSpace(); } + sk_sp refColorSpace() const { return fImageInfo.refColorSpace(); } + const SkSurfaceProps& surfaceProps()const { return fSurfaceProps; } + +private: + friend class SkSurface_Ganesh; // for 'set' & 'config' + friend class GrVkSecondaryCBDrawContext; // for 'set' & 'config' + friend class GrContextThreadSafeProxy; // for private ctor + friend class GrVkContextThreadSafeProxy; // for private ctor + friend class GrDeferredDisplayListRecorder; // for 'config' + friend class SkSurface; // for 'config' + + SkDEBUGCODE(void validate() const;) + + GrSurfaceCharacterization(sk_sp contextInfo, + size_t cacheMaxResourceBytes, + const SkImageInfo& ii, + const GrBackendFormat& backendFormat, + GrSurfaceOrigin origin, + int sampleCnt, + Textureable isTextureable, + skgpu::Mipmapped isMipmapped, + UsesGLFBO0 usesGLFBO0, + VkRTSupportsInputAttachment vkRTSupportsInputAttachment, + VulkanSecondaryCBCompatible vulkanSecondaryCBCompatible, + skgpu::Protected isProtected, + const SkSurfaceProps& surfaceProps) + : fContextInfo(std::move(contextInfo)) + , fCacheMaxResourceBytes(cacheMaxResourceBytes) + , fImageInfo(ii) + , fBackendFormat(std::move(backendFormat)) + , fOrigin(origin) + , fSampleCnt(sampleCnt) + , fIsTextureable(isTextureable) + , fIsMipmapped(isMipmapped) + , fUsesGLFBO0(usesGLFBO0) + , fVkRTSupportsInputAttachment(vkRTSupportsInputAttachment) + , fVulkanSecondaryCBCompatible(vulkanSecondaryCBCompatible) + , fIsProtected(isProtected) + , fSurfaceProps(surfaceProps) { + if (fSurfaceProps.flags() & SkSurfaceProps::kDynamicMSAA_Flag) { + // Dynamic MSAA is not currently supported with DDL. + *this = {}; + } + SkDEBUGCODE(this->validate()); + } + + void set(sk_sp contextInfo, + size_t cacheMaxResourceBytes, + const SkImageInfo& ii, + const GrBackendFormat& backendFormat, + GrSurfaceOrigin origin, + int sampleCnt, + Textureable isTextureable, + skgpu::Mipmapped isMipmapped, + UsesGLFBO0 usesGLFBO0, + VkRTSupportsInputAttachment vkRTSupportsInputAttachment, + VulkanSecondaryCBCompatible vulkanSecondaryCBCompatible, + skgpu::Protected isProtected, + const SkSurfaceProps& surfaceProps) { + if (surfaceProps.flags() & SkSurfaceProps::kDynamicMSAA_Flag) { + // Dynamic MSAA is not currently supported with DDL. + *this = {}; + } else { + fContextInfo = std::move(contextInfo); + fCacheMaxResourceBytes = cacheMaxResourceBytes; + + fImageInfo = ii; + fBackendFormat = std::move(backendFormat); + fOrigin = origin; + fSampleCnt = sampleCnt; + fIsTextureable = isTextureable; + fIsMipmapped = isMipmapped; + fUsesGLFBO0 = usesGLFBO0; + fVkRTSupportsInputAttachment = vkRTSupportsInputAttachment; + fVulkanSecondaryCBCompatible = vulkanSecondaryCBCompatible; + fIsProtected = isProtected; + fSurfaceProps = surfaceProps; + } + SkDEBUGCODE(this->validate()); + } + + sk_sp fContextInfo; + size_t fCacheMaxResourceBytes; + + SkImageInfo fImageInfo; + GrBackendFormat fBackendFormat; + GrSurfaceOrigin fOrigin; + int fSampleCnt; + Textureable fIsTextureable; + skgpu::Mipmapped fIsMipmapped; + UsesGLFBO0 fUsesGLFBO0; + VkRTSupportsInputAttachment fVkRTSupportsInputAttachment; + VulkanSecondaryCBCompatible fVulkanSecondaryCBCompatible; + skgpu::Protected fIsProtected; + SkSurfaceProps fSurfaceProps; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/chromium/GrVkSecondaryCBDrawContext.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/chromium/GrVkSecondaryCBDrawContext.h new file mode 100644 index 0000000000..d0348312bd --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/chromium/GrVkSecondaryCBDrawContext.h @@ -0,0 +1,131 @@ +/* + * Copyright 2019 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrVkSecondaryCBDrawContext_DEFINED +#define GrVkSecondaryCBDrawContext_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkSurfaceProps.h" +#include "include/core/SkTypes.h" + +#include + +class GrBackendSemaphore; +class GrDeferredDisplayList; +class GrRecordingContext; +class GrSurfaceCharacterization; +struct GrVkDrawableInfo; +namespace skgpu::ganesh { +class Device; +} +class SkCanvas; +struct SkImageInfo; +class SkSurfaceProps; + +/** + * This class is a private header that is intended to only be used inside of Chromium. This requires + * Chromium to burrow in and include this specifically since it is not part of skia's public include + * directory. + */ + +/** + * This class is used to draw into an external Vulkan secondary command buffer that is imported + * by the client. The secondary command buffer that gets imported must already have had begin called + * on it with VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT. Thus any draws to the imported + * command buffer cannot require changing the render pass. This requirement means that certain types + * of draws will not be supported when using a GrVkSecondaryCBDrawContext. This includes: + * Draws that require a dst copy for blending will be dropped + * Text draws will be dropped (these may require intermediate uploads of text data) + * Read and Write pixels will not work + * Any other draw that requires a copy will fail (this includes using backdrop filter with save + * layer). + * Stenciling is also disabled, but that should not restrict any actual draws from working. + * + * While using a GrVkSecondaryCBDrawContext, the client can also draw into normal SkSurfaces and + * then draw those SkSufaces (as SkImages) into the GrVkSecondaryCBDrawContext. If any of the + * previously mentioned unsupported draws are needed by the client, they can draw them into an + * offscreen surface, and then draw that into the GrVkSecondaryCBDrawContext. + * + * After all drawing to the GrVkSecondaryCBDrawContext has been done, the client must call flush() + * on the GrVkSecondaryCBDrawContext to actually fill in the secondary VkCommandBuffer with the + * draws. + * + * Additionally, the client must keep the GrVkSecondaryCBDrawContext alive until the secondary + * VkCommandBuffer has been submitted and all work finished on the GPU. Before deleting the + * GrVkSecondaryCBDrawContext, the client must call releaseResources() so that Skia can cleanup + * any internal objects that were created for the draws into the secondary command buffer. + */ +class SK_SPI GrVkSecondaryCBDrawContext : public SkRefCnt { +public: + static sk_sp Make(GrRecordingContext*, + const SkImageInfo&, + const GrVkDrawableInfo&, + const SkSurfaceProps* props); + + ~GrVkSecondaryCBDrawContext() override; + + SkCanvas* getCanvas(); + + // Records all the draws to the imported secondary command buffer and sets any dependent + // offscreen draws to the GPU. + void flush(); + + /** Inserts a list of GPU semaphores that Skia will have the driver wait on before executing + commands for this secondary CB. The wait semaphores will get added to the VkCommandBuffer + owned by this GrContext when flush() is called, and not the command buffer which the + Secondary CB is from. This will guarantee that the driver waits on the semaphores before + the secondary command buffer gets executed. We will submit the semphore to wait at + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT and VK_PIPELINE_STAGE_TRANSFER_BIT. If this + call returns false, then the GPU back end will not wait on any passed in semaphores, and the + client will still own the semaphores, regardless of the value of deleteSemaphoresAfterWait. + + If deleteSemaphoresAfterWait is false then Skia will not delete the semaphores. In this case + it is the client's responsibility to not destroy or attempt to reuse the semaphores until it + knows that Skia has finished waiting on them. This can be done by using finishedProcs + on flush calls. + + @param numSemaphores size of waitSemaphores array + @param waitSemaphores array of semaphore containers + @paramm deleteSemaphoresAfterWait who owns and should delete the semaphores + @return true if GPU is waiting on semaphores + */ + bool wait(int numSemaphores, + const GrBackendSemaphore waitSemaphores[], + bool deleteSemaphoresAfterWait = true); + + // This call will release all resources held by the draw context. The client must call + // releaseResources() before deleting the drawing context. However, the resources also include + // any Vulkan resources that were created and used for draws. Therefore the client must only + // call releaseResources() after submitting the secondary command buffer, and waiting for it to + // finish on the GPU. If it is called earlier then some vulkan objects may be deleted while they + // are still in use by the GPU. + void releaseResources(); + + const SkSurfaceProps& props() const { return fProps; } + + // TODO: Fill out these calls to support DDL + bool characterize(GrSurfaceCharacterization* characterization) const; + +#ifndef SK_DDL_IS_UNIQUE_POINTER + bool draw(sk_sp deferredDisplayList); +#else + bool draw(const GrDeferredDisplayList* deferredDisplayList); +#endif + + bool isCompatible(const GrSurfaceCharacterization& characterization) const; + +private: + explicit GrVkSecondaryCBDrawContext(sk_sp, const SkSurfaceProps*); + + sk_sp fDevice; + std::unique_ptr fCachedCanvas; + const SkSurfaceProps fProps; + + using INHERITED = SkRefCnt; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/chromium/SkChromeRemoteGlyphCache.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/chromium/SkChromeRemoteGlyphCache.h new file mode 100644 index 0000000000..3a71a45e17 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/chromium/SkChromeRemoteGlyphCache.h @@ -0,0 +1,150 @@ +/* + * 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 SkChromeRemoteGlyphCache_DEFINED +#define SkChromeRemoteGlyphCache_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypeface.h" +#include "include/private/base/SkAPI.h" + +#include +#include +#include +#include + +class SkAutoDescriptor; +class SkCanvas; +class SkColorSpace; +class SkStrikeCache; +class SkStrikeClientImpl; +class SkStrikeServerImpl; +class SkSurfaceProps; +namespace sktext::gpu { class Slug; } + +using SkDiscardableHandleId = uint32_t; +// This class is not thread-safe. +class SkStrikeServer { +public: + // An interface used by the server to create handles for pinning SkStrike + // entries on the remote client. + class DiscardableHandleManager { + public: + SK_SPI virtual ~DiscardableHandleManager() = default; + + // Creates a new *locked* handle and returns a unique ID that can be used to identify + // it on the remote client. + SK_SPI virtual SkDiscardableHandleId createHandle() = 0; + + // Returns true if the handle could be successfully locked. The server can + // assume it will remain locked until the next set of serialized entries is + // pulled from the SkStrikeServer. + // If returns false, the cache entry mapped to the handle has been deleted + // on the client. Any subsequent attempts to lock the same handle are not + // allowed. + SK_SPI virtual bool lockHandle(SkDiscardableHandleId) = 0; + + // Returns true if a handle has been deleted on the remote client. It is + // invalid to use a handle id again with this manager once this returns true. + SK_SPI virtual bool isHandleDeleted(SkDiscardableHandleId) = 0; + }; + + SK_SPI explicit SkStrikeServer(DiscardableHandleManager* discardableHandleManager); + SK_SPI ~SkStrikeServer(); + + // Create an analysis SkCanvas used to populate the SkStrikeServer with ops + // which will be serialized and rendered using the SkStrikeClient. + SK_API std::unique_ptr makeAnalysisCanvas(int width, int height, + const SkSurfaceProps& props, + sk_sp colorSpace, + bool DFTSupport, + bool DFTPerspSupport = true); + + // Serializes the strike data captured using a canvas returned by ::makeAnalysisCanvas. Any + // handles locked using the DiscardableHandleManager will be assumed to be + // unlocked after this call. + SK_SPI void writeStrikeData(std::vector* memory); + + // Testing helpers + void setMaxEntriesInDescriptorMapForTesting(size_t count); + size_t remoteStrikeMapSizeForTesting() const; + +private: + SkStrikeServerImpl* impl(); + + std::unique_ptr fImpl; +}; + +class SkStrikeClient { +public: + // This enum is used in histogram reporting in chromium. Please don't re-order the list of + // entries, and consider it to be append-only. + enum CacheMissType : uint32_t { + // Hard failures where no fallback could be found. + kFontMetrics = 0, + kGlyphMetrics = 1, + kGlyphImage = 2, + kGlyphPath = 3, + + // (DEPRECATED) The original glyph could not be found and a fallback was used. + kGlyphMetricsFallback = 4, + kGlyphPathFallback = 5, + + kGlyphDrawable = 6, + kLast = kGlyphDrawable + }; + + // An interface to delete handles that may be pinned by the remote server. + class DiscardableHandleManager : public SkRefCnt { + public: + ~DiscardableHandleManager() override = default; + + // Returns true if the handle was unlocked and can be safely deleted. Once + // successful, subsequent attempts to delete the same handle are invalid. + virtual bool deleteHandle(SkDiscardableHandleId) = 0; + + virtual void assertHandleValid(SkDiscardableHandleId) {} + + virtual void notifyCacheMiss(CacheMissType type, int fontSize) = 0; + + struct ReadFailureData { + size_t memorySize; + size_t bytesRead; + uint64_t typefaceSize; + uint64_t strikeCount; + uint64_t glyphImagesCount; + uint64_t glyphPathsCount; + }; + virtual void notifyReadFailure(const ReadFailureData& data) {} + }; + + SK_SPI explicit SkStrikeClient(sk_sp, + bool isLogging = true, + SkStrikeCache* strikeCache = nullptr); + SK_SPI ~SkStrikeClient(); + + // Deserializes the strike data from a SkStrikeServer. All messages generated + // from a server when serializing the ops must be deserialized before the op + // is rasterized. + // Returns false if the data is invalid. + SK_SPI bool readStrikeData(const volatile void* memory, size_t memorySize); + + // Given a descriptor re-write the Rec mapping the typefaceID from the renderer to the + // corresponding typefaceID on the GPU. + SK_SPI bool translateTypefaceID(SkAutoDescriptor* descriptor) const; + + // Testing helpers + sk_sp retrieveTypefaceUsingServerIDForTest(SkTypefaceID) const; + + // Given a buffer, unflatten into a slug making sure to do the typefaceID translation from + // renderer to GPU. Returns nullptr if there was a problem. + sk_sp deserializeSlugForTest(const void* data, size_t size) const; + +private: + std::unique_ptr fImpl; +}; +#endif // SkChromeRemoteGlyphCache_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/chromium/SkDiscardableMemory.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/chromium/SkDiscardableMemory.h new file mode 100644 index 0000000000..3aa9870360 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/chromium/SkDiscardableMemory.h @@ -0,0 +1,70 @@ +/* + * 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 SkDiscardableMemory_DEFINED +#define SkDiscardableMemory_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" + +/** + * Interface for discardable memory. Implementation is provided by the + * embedder. + */ +class SK_SPI SkDiscardableMemory { +public: + /** + * Factory method that creates, initializes and locks an SkDiscardableMemory + * object. If either of these steps fails, a nullptr pointer will be returned. + */ + static SkDiscardableMemory* Create(size_t bytes); + + /** + * Factory class that creates, initializes and locks an SkDiscardableMemory + * object. If either of these steps fails, a nullptr pointer will be returned. + */ + class Factory : public SkRefCnt { + public: + virtual SkDiscardableMemory* create(size_t bytes) = 0; + private: + using INHERITED = SkRefCnt; + }; + + /** Must not be called while locked. + */ + virtual ~SkDiscardableMemory() {} + + /** + * Locks the memory, prevent it from being discarded. Once locked. you may + * obtain a pointer to that memory using the data() method. + * + * lock() may return false, indicating that the underlying memory was + * discarded and that the lock failed. + * + * Nested calls to lock are not allowed. + */ + [[nodiscard]] virtual bool lock() = 0; + + /** + * Returns the current pointer for the discardable memory. This call is ONLY + * valid when the discardable memory object is locked. + */ + virtual void* data() = 0; + + /** + * Unlock the memory so that it can be purged by the system. Must be called + * after every successful lock call. + */ + virtual void unlock() = 0; + +protected: + SkDiscardableMemory() = default; + SkDiscardableMemory(const SkDiscardableMemory&) = delete; + SkDiscardableMemory& operator=(const SkDiscardableMemory&) = delete; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/chromium/SkImageChromium.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/chromium/SkImageChromium.h new file mode 100644 index 0000000000..7c62ba581b --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/chromium/SkImageChromium.h @@ -0,0 +1,117 @@ +/* + * 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 SkImageChromium_DEFINED +#define SkImageChromium_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/private/base/SkAPI.h" + +class GrBackendFormat; +class GrContextThreadSafeProxy; +class GrPromiseImageTexture; +class GrDirectContext; +class GrYUVABackendTextureInfo; +class SkColorSpace; +class SkImage; +enum SkAlphaType : int; +enum SkColorType : int; +enum GrSurfaceOrigin : int; +namespace skgpu { +enum class Mipmapped : bool; +} +struct SkISize; + +/** + * These functions expose features that are only for external use in Chromium. + */ + +namespace SkImages { + +using PromiseImageTextureContext = void*; +using PromiseImageTextureFulfillProc = sk_sp (*)(PromiseImageTextureContext); +using PromiseImageTextureReleaseProc = void (*)(PromiseImageTextureContext); + +/** Create a new GPU-backed SkImage that is very similar to an SkImage created by BorrowTextureFrom. + The difference is that the caller need not have created the texture nor populated it with the + image pixel data. Moreover, the SkImage may be created on a thread as the creation of the + image does not require access to the backend API or GrDirectContext. Instead of passing a + GrBackendTexture the client supplies a description of the texture consisting of + GrBackendFormat, width, height, and skgpu::Mipmapped state. The resulting SkImage can be drawn + to a GrDeferredDisplayListRecorder or directly to a GPU-backed SkSurface. + When the actual texture is required to perform a backend API draw, textureFulfillProc will + be called to receive a GrBackendTexture. The properties of the GrBackendTexture must match + those set during the SkImage creation, and it must refer to a valid existing texture in the + backend API context/device, and be populated with the image pixel data. The texture cannot + be deleted until textureReleaseProc is called. + There is at most one call to each of textureFulfillProc and textureReleaseProc. + textureReleaseProc is always called even if image creation fails or if the + image is never fulfilled (e.g. it is never drawn or all draws are clipped out) + @param gpuContextProxy the thread-safe proxy of the gpu context. required. + @param backendFormat format of promised gpu texture + @param dimensions width & height of promised gpu texture + @param mipmapped mip mapped state of promised gpu texture + @param origin surface origin of promised gpu texture + @param colorType color type of promised gpu texture + @param alphaType alpha type of promised gpu texture + @param colorSpace range of colors; may be nullptr + @param textureFulfillProc function called to get actual gpu texture + @param textureReleaseProc function called when texture can be deleted + @param textureContext state passed to textureFulfillProc and textureReleaseProc + @return created SkImage, or nullptr +*/ +SK_API sk_sp PromiseTextureFrom(sk_sp gpuContextProxy, + const GrBackendFormat& backendFormat, + SkISize dimensions, + skgpu::Mipmapped mipmapped, + GrSurfaceOrigin origin, + SkColorType colorType, + SkAlphaType alphaType, + sk_sp colorSpace, + PromiseImageTextureFulfillProc textureFulfillProc, + PromiseImageTextureReleaseProc textureReleaseProc, + PromiseImageTextureContext textureContext); + +/** This is similar to 'PromiseTextureFrom' but it creates a GPU-backed SkImage from YUV[A] data. + The source data may be planar (i.e. spread across multiple textures). In + the extreme Y, U, V, and A are all in different planes and thus the image is specified by + four textures. 'backendTextureInfo' describes the planar arrangement, texture formats, + conversion to RGB, and origin of the textures. Separate 'textureFulfillProc' and + 'textureReleaseProc' calls are made for each texture. Each texture has its own + PromiseImageTextureContext. If 'backendTextureInfo' is not valid then no release proc + calls are made. Otherwise, the calls will be made even on failure. 'textureContexts' has one + entry for each of the up to four textures, as indicated by 'backendTextureInfo'. + Currently the mip mapped property of 'backendTextureInfo' is ignored. However, in the + near future it will be required that if it is kYes then textureFulfillProc must return + a mip mapped texture for each plane in order to successfully draw the image. + @param gpuContextProxy the thread-safe proxy of the gpu context. required. + @param backendTextureInfo info about the promised yuva gpu texture + @param imageColorSpace range of colors; may be nullptr + @param textureFulfillProc function called to get actual gpu texture + @param textureReleaseProc function called when texture can be deleted + @param textureContexts state passed to textureFulfillProc and textureReleaseProc + @return created SkImage, or nullptr +*/ +SK_API sk_sp PromiseTextureFromYUVA(sk_sp gpuContextProxy, + const GrYUVABackendTextureInfo& backendTextureInfo, + sk_sp imageColorSpace, + PromiseImageTextureFulfillProc textureFulfillProc, + PromiseImageTextureReleaseProc textureReleaseProc, + PromiseImageTextureContext textureContexts[]); + +/** Returns the GPU context associated with this image or nullptr if the image is not Ganesh-backed. + We expose this only to help transition certain API calls and do not intend for this to stick + around forever. +*/ +SK_API GrDirectContext* GetContext(const SkImage* src); +inline GrDirectContext* GetContext(const sk_sp& src) { + return GetContext(src.get()); +} + +} // namespace SkImages + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/chromium/Slug.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/chromium/Slug.h new file mode 100644 index 0000000000..0ee6082b8a --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/chromium/Slug.h @@ -0,0 +1,72 @@ +/* + * 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 sktext_gpu_Slug_DEFINED +#define sktext_gpu_Slug_DEFINED + +#include "include/core/SkRect.h" +#include "include/core/SkRefCnt.h" +#include "include/private/base/SkAPI.h" + +#include +#include + +class SkCanvas; +class SkData; +class SkPaint; +class SkReadBuffer; +class SkStrikeClient; +class SkTextBlob; +class SkWriteBuffer; +struct SkDeserialProcs; +struct SkPoint; + +namespace sktext::gpu { +// Slug encapsulates an SkTextBlob at a specific origin, using a specific paint. It can be +// manipulated using matrix and clip changes to the canvas. If the canvas is transformed, then +// the Slug will also transform with smaller glyphs using bi-linear interpolation to render. You +// can think of a Slug as making a rubber stamp out of a SkTextBlob. +class SK_API Slug : public SkRefCnt { +public: + // Return nullptr if the blob would not draw. This is not because of clipping, but because of + // some paint optimization. The Slug is captured as if drawn using drawTextBlob. + static sk_sp ConvertBlob( + SkCanvas* canvas, const SkTextBlob& blob, SkPoint origin, const SkPaint& paint); + + // Serialize the slug. + sk_sp serialize() const; + size_t serialize(void* buffer, size_t size) const; + + // Set the client parameter to the appropriate SkStrikeClient when typeface ID translation + // is needed. + static sk_sp Deserialize(const void* data, + size_t size, + const SkStrikeClient* client = nullptr); + static sk_sp MakeFromBuffer(SkReadBuffer& buffer); + + // Allows clients to deserialize SkPictures that contain slug data + static void AddDeserialProcs(SkDeserialProcs* procs, const SkStrikeClient* client = nullptr); + + // Draw the Slug obeying the canvas's mapping and clipping. + void draw(SkCanvas* canvas, const SkPaint& paint) const; + + virtual SkRect sourceBounds() const = 0; + virtual SkRect sourceBoundsWithOrigin () const = 0; + + virtual void doFlatten(SkWriteBuffer&) const = 0; + + uint32_t uniqueID() const { return fUniqueID; } + +private: + static uint32_t NextUniqueID(); + const uint32_t fUniqueID{NextUniqueID()}; +}; + + +} // namespace sktext::gpu + +#endif // sktext_gpu_Slug_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/gpu/ganesh/GrContext_Base.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/gpu/ganesh/GrContext_Base.h new file mode 100644 index 0000000000..450bea411b --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/gpu/ganesh/GrContext_Base.h @@ -0,0 +1,104 @@ +/* + * Copyright 2019 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrContext_Base_DEFINED +#define GrContext_Base_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/gpu/GrTypes.h" +#include "include/private/base/SkAPI.h" + +#include + +class GrBaseContextPriv; +class GrCaps; +class GrContextThreadSafeProxy; +class GrDirectContext; +class GrImageContext; +class GrRecordingContext; +enum SkColorType : int; +enum class SkTextureCompressionType; +struct GrContextOptions; +class GrBackendFormat; + +class GrContext_Base : public SkRefCnt { +public: + ~GrContext_Base() override; + + /* + * Safely downcast to a GrDirectContext. + */ + virtual GrDirectContext* asDirectContext() { return nullptr; } + + /* + * The 3D API backing this context + */ + SK_API GrBackendApi backend() const; + + /* + * Retrieve the default GrBackendFormat for a given SkColorType and renderability. + * It is guaranteed that this backend format will be the one used by the GrContext + * SkColorType and GrSurfaceCharacterization-based createBackendTexture methods. + * + * The caller should check that the returned format is valid. + */ + SK_API GrBackendFormat defaultBackendFormat(SkColorType, GrRenderable) const; + + SK_API GrBackendFormat compressedBackendFormat(SkTextureCompressionType) const; + + /** + * Gets the maximum supported sample count for a color type. 1 is returned if only non-MSAA + * rendering is supported for the color type. 0 is returned if rendering to this color type + * is not supported at all. + */ + SK_API int maxSurfaceSampleCountForColorType(SkColorType colorType) const; + + // TODO: When the public version is gone, rename to refThreadSafeProxy and add raw ptr ver. + sk_sp threadSafeProxy(); + + // Provides access to functions that aren't part of the public API. + GrBaseContextPriv priv(); + const GrBaseContextPriv priv() const; // NOLINT(readability-const-return-type) + +protected: + friend class GrBaseContextPriv; // for hidden functions + + GrContext_Base(sk_sp); + + virtual bool init(); + + /** + * An identifier for this context. The id is used by all compatible contexts. For example, + * if SkImages are created on one thread using an image creation context, then fed into a + * DDL Recorder on second thread (which has a recording context) and finally replayed on + * a third thread with a direct context, then all three contexts will report the same id. + * It is an error for an image to be used with contexts that report different ids. + */ + uint32_t contextID() const; + + bool matches(GrContext_Base* candidate) const { + return candidate && candidate->contextID() == this->contextID(); + } + + /* + * The options in effect for this context + */ + const GrContextOptions& options() const; + + const GrCaps* caps() const; + sk_sp refCaps() const; + + virtual GrImageContext* asImageContext() { return nullptr; } + virtual GrRecordingContext* asRecordingContext() { return nullptr; } + + sk_sp fThreadSafeProxy; + +private: + using INHERITED = SkRefCnt; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/gpu/ganesh/GrD3DTypesMinimal.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/gpu/ganesh/GrD3DTypesMinimal.h new file mode 100644 index 0000000000..9d6156d621 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/gpu/ganesh/GrD3DTypesMinimal.h @@ -0,0 +1,74 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrD3DTypesMinimal_DEFINED +#define GrD3DTypesMinimal_DEFINED + +// Minimal definitions of Direct3D types, without including d3d12.h + +#include "include/core/SkRefCnt.h" + +#include + +#include "include/gpu/GrTypes.h" + +struct ID3D12Resource; +class GrD3DResourceState; +typedef int GrD3DResourceStateEnum; +struct GrD3DSurfaceInfo; +struct GrD3DTextureResourceInfo; +struct GrD3DTextureResourceSpec; +struct GrD3DFenceInfo; + +// This struct is to used to store the the actual information about the Direct3D backend image on +// GrBackendTexture and GrBackendRenderTarget. When a client calls getD3DTextureInfo on a +// GrBackendTexture/RenderTarget, we use the GrD3DBackendSurfaceInfo to create a snapshot +// GrD3DTextureResourceInfo object. Internally, this uses a ref count GrD3DResourceState object to +// track the current D3D12_RESOURCE_STATES which can be shared with an internal GrD3DTextureResource +// so that state updates can be seen by all users of the texture. +struct GrD3DBackendSurfaceInfo { + GrD3DBackendSurfaceInfo(const GrD3DTextureResourceInfo& info, GrD3DResourceState* state); + + void cleanup(); + + GrD3DBackendSurfaceInfo& operator=(const GrD3DBackendSurfaceInfo&) = delete; + + // Assigns the passed in GrD3DBackendSurfaceInfo to this object. if isValid is true we will also + // attempt to unref the old fLayout on this object. + void assign(const GrD3DBackendSurfaceInfo&, bool isValid); + + void setResourceState(GrD3DResourceStateEnum state); + + sk_sp getGrD3DResourceState() const; + + GrD3DTextureResourceInfo snapTextureResourceInfo() const; + + bool isProtected() const; +#if defined(GR_TEST_UTILS) + bool operator==(const GrD3DBackendSurfaceInfo& that) const; +#endif + +private: + GrD3DTextureResourceInfo* fTextureResourceInfo; + GrD3DResourceState* fResourceState; +}; + +struct GrD3DTextureResourceSpecHolder { +public: + GrD3DTextureResourceSpecHolder(const GrD3DSurfaceInfo&); + + void cleanup(); + + GrD3DSurfaceInfo getSurfaceInfo(uint32_t sampleCount, + uint32_t levelCount, + skgpu::Protected isProtected) const; + +private: + GrD3DTextureResourceSpec* fSpec; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/gpu/ganesh/GrImageContext.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/gpu/ganesh/GrImageContext.h new file mode 100644 index 0000000000..a8c81e2d22 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/gpu/ganesh/GrImageContext.h @@ -0,0 +1,56 @@ +/* + * Copyright 2019 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrImageContext_DEFINED +#define GrImageContext_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/private/base/SingleOwner.h" +#include "include/private/base/SkAPI.h" +#include "include/private/gpu/ganesh/GrContext_Base.h" + +class GrContextThreadSafeProxy; +class GrImageContextPriv; + +// This is now just a view on a ThreadSafeProxy, that SkImages can attempt to +// downcast to a GrDirectContext as a backdoor to some operations. Once we remove the backdoors, +// this goes away and SkImages just hold ThreadSafeProxies. +class GrImageContext : public GrContext_Base { +public: + ~GrImageContext() override; + + // Provides access to functions that aren't part of the public API. + GrImageContextPriv priv(); + const GrImageContextPriv priv() const; // NOLINT(readability-const-return-type) + +protected: + friend class GrImageContextPriv; // for hidden functions + + GrImageContext(sk_sp); + + SK_API virtual void abandonContext(); + SK_API virtual bool abandoned(); + + /** This is only useful for debug purposes */ + skgpu::SingleOwner* singleOwner() const { return &fSingleOwner; } + + GrImageContext* asImageContext() override { return this; } + +private: + // When making promise images, we currently need a placeholder GrImageContext instance to give + // to the SkImage that has no real power, just a wrapper around the ThreadSafeProxy. + // TODO: De-power SkImage to ThreadSafeProxy or at least figure out a way to share one instance. + static sk_sp MakeForPromiseImage(sk_sp); + + // In debug builds we guard against improper thread handling + // This guard is passed to the GrDrawingManager and, from there to all the + // GrSurfaceDrawContexts. It is also passed to the GrResourceProvider and SkGpuDevice. + // TODO: Move this down to GrRecordingContext. + mutable skgpu::SingleOwner fSingleOwner; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/gpu/ganesh/GrTextureGenerator.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/gpu/ganesh/GrTextureGenerator.h new file mode 100644 index 0000000000..a8902d863e --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/gpu/ganesh/GrTextureGenerator.h @@ -0,0 +1,66 @@ +/* + * 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 GrTextureGenerator_DEFINED +#define GrTextureGenerator_DEFINED + +#include "include/core/SkImageGenerator.h" +#include "include/gpu/GrTypes.h" +#include "include/private/base/SkAPI.h" + +#include + +class GrRecordingContext; +class GrSurfaceProxyView; +enum class GrImageTexGenPolicy : int; +namespace skgpu { enum class Mipmapped : bool; } +struct SkImageInfo; + +class SK_API GrTextureGenerator : public SkImageGenerator { +public: + bool isTextureGenerator() const final { return true; } + + /** + * If the generator can natively/efficiently return its pixels as a GPU image (backed by a + * texture) this will return that image. If not, this will return NULL. + * + * Regarding the GrRecordingContext parameter: + * + * It must be non-NULL. The generator should only succeed if: + * - its internal context is the same + * - it can somehow convert its texture into one that is valid for the provided context. + * + * If the mipmapped parameter is kYes, the generator should try to create a TextureProxy that + * at least has the mip levels allocated and the base layer filled in. If this is not possible, + * the generator is allowed to return a non mipped proxy, but this will have some additional + * overhead in later allocating mips and copying of the base layer. + * + * GrImageTexGenPolicy determines whether or not a new texture must be created (and its budget + * status) or whether this may (but is not required to) return a pre-existing texture that is + * retained by the generator (kDraw). + */ + GrSurfaceProxyView generateTexture(GrRecordingContext*, + const SkImageInfo& info, + skgpu::Mipmapped mipmapped, + GrImageTexGenPolicy); + + // External clients should override GrExternalTextureGenerator instead of trying to implement + // this (which uses private Skia types) + virtual GrSurfaceProxyView onGenerateTexture(GrRecordingContext*, const SkImageInfo&, + skgpu::Mipmapped, GrImageTexGenPolicy) = 0; + + // Most internal SkImageGenerators produce textures and views that use kTopLeft_GrSurfaceOrigin. + // If the generator may produce textures with different origins (e.g. + // GrAHardwareBufferImageGenerator) it should override this function to return the correct + // origin. Implementations should be thread-safe. + virtual GrSurfaceOrigin origin() const { return kTopLeft_GrSurfaceOrigin; } + +protected: + GrTextureGenerator(const SkImageInfo& info, uint32_t uniqueId = kNeedNewImageUniqueID); +}; + +#endif // GrTextureGenerator_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/gpu/ganesh/GrTypesPriv.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/gpu/ganesh/GrTypesPriv.h new file mode 100644 index 0000000000..5568cb54de --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/gpu/ganesh/GrTypesPriv.h @@ -0,0 +1,1007 @@ +/* + * 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 GrTypesPriv_DEFINED +#define GrTypesPriv_DEFINED + +#include "include/core/SkColor.h" +#include "include/core/SkColorType.h" +#include "include/core/SkData.h" +#include "include/core/SkPath.h" +#include "include/core/SkPathTypes.h" +#include "include/core/SkRefCnt.h" +#include "include/gpu/GrTypes.h" +#include "include/private/base/SkAssert.h" +#include "include/private/base/SkDebug.h" +#include "include/private/base/SkMacros.h" +#include "include/private/base/SkTypeTraits.h" + +#include +#include +#include +#include + +class GrSurfaceProxy; + +namespace skgpu { +enum class Mipmapped : bool; +} + +/** + * divide, rounding up + */ + +static inline constexpr size_t GrSizeDivRoundUp(size_t x, size_t y) { return (x + (y - 1)) / y; } + +/** + * Geometric primitives used for drawing. + */ +enum class GrPrimitiveType : uint8_t { + kTriangles, + kTriangleStrip, + kPoints, + kLines, // 1 pix wide only + kLineStrip, // 1 pix wide only +}; +static constexpr int kNumGrPrimitiveTypes = (int)GrPrimitiveType::kLineStrip + 1; + +static constexpr bool GrIsPrimTypeLines(GrPrimitiveType type) { + return GrPrimitiveType::kLines == type || GrPrimitiveType::kLineStrip == type; +} + +enum class GrPrimitiveRestart : bool { + kNo = false, + kYes = true +}; + +/** + * Should a created surface be texturable? + */ +enum class GrTexturable : bool { + kNo = false, + kYes = true +}; + +// A DDL recorder has its own proxy provider and proxy cache. This enum indicates if +// a given proxy provider is one of these special ones. +enum class GrDDLProvider : bool { + kNo = false, + kYes = true +}; + +/** Ownership rules for external GPU resources imported into Skia. */ +enum GrWrapOwnership { + /** Skia will assume the client will keep the resource alive and Skia will not free it. */ + kBorrow_GrWrapOwnership, + + /** Skia will assume ownership of the resource and free it. */ + kAdopt_GrWrapOwnership, +}; + +enum class GrWrapCacheable : bool { + /** + * The wrapped resource will be removed from the cache as soon as it becomes purgeable. It may + * still be assigned and found by a unique key, but the presence of the key will not be used to + * keep the resource alive when it has no references. + */ + kNo = false, + /** + * The wrapped resource is allowed to remain in the GrResourceCache when it has no references + * but has a unique key. Such resources should only be given unique keys when it is known that + * the key will eventually be removed from the resource or invalidated via the message bus. + */ + kYes = true +}; + +enum class GrBudgetedType : uint8_t { + /** The resource is budgeted and is subject to purging under budget pressure. */ + kBudgeted, + /** + * The resource is unbudgeted and is purged as soon as it has no refs regardless of whether + * it has a unique or scratch key. + */ + kUnbudgetedUncacheable, + /** + * The resource is unbudgeted and is allowed to remain in the cache with no refs if it + * has a unique key. Scratch keys are ignored. + */ + kUnbudgetedCacheable, +}; + +enum class GrScissorTest : bool { + kDisabled = false, + kEnabled = true +}; + +/* + * Used to say whether texture is backed by memory. + */ +enum class GrMemoryless : bool { + /** + * The texture will be allocated normally and will affect memory budgets. + */ + kNo = false, + /** + * The texture will be not use GPU memory and will not affect memory budgets. + */ + kYes = true +}; + +struct GrMipLevel { + const void* fPixels = nullptr; + size_t fRowBytes = 0; + // This may be used to keep fPixels from being freed while a GrMipLevel exists. + sk_sp fOptionalStorage; + + static_assert(::sk_is_trivially_relocatable::value); + static_assert(::sk_is_trivially_relocatable::value); + + using sk_is_trivially_relocatable = std::true_type; +}; + +enum class GrSemaphoreWrapType { + kWillSignal, + kWillWait, +}; + +/** + * This enum is used to specify the load operation to be used when an OpsTask/GrOpsRenderPass + * begins execution. + */ +enum class GrLoadOp { + kLoad, + kClear, + kDiscard, +}; + +/** + * This enum is used to specify the store operation to be used when an OpsTask/GrOpsRenderPass + * ends execution. + */ +enum class GrStoreOp { + kStore, + kDiscard, +}; + +/** + * Used to control antialiasing in draw calls. + */ +enum class GrAA : bool { + kNo = false, + kYes = true +}; + +enum class GrFillRule : bool { + kNonzero, + kEvenOdd +}; + +inline GrFillRule GrFillRuleForPathFillType(SkPathFillType fillType) { + switch (fillType) { + case SkPathFillType::kWinding: + case SkPathFillType::kInverseWinding: + return GrFillRule::kNonzero; + case SkPathFillType::kEvenOdd: + case SkPathFillType::kInverseEvenOdd: + return GrFillRule::kEvenOdd; + } + SkUNREACHABLE; +} + +inline GrFillRule GrFillRuleForSkPath(const SkPath& path) { + return GrFillRuleForPathFillType(path.getFillType()); +} + +/** This enum indicates the type of antialiasing to be performed. */ +enum class GrAAType : unsigned { + /** No antialiasing */ + kNone, + /** Use fragment shader code to blend with a fractional pixel coverage. */ + kCoverage, + /** Use normal MSAA. */ + kMSAA, + + kLast = kMSAA +}; +static const int kGrAATypeCount = static_cast(GrAAType::kLast) + 1; + +static constexpr bool GrAATypeIsHW(GrAAType type) { + switch (type) { + case GrAAType::kNone: + return false; + case GrAAType::kCoverage: + return false; + case GrAAType::kMSAA: + return true; + } + SkUNREACHABLE; +} + +/** + * Some pixel configs are inherently clamped to [0,1], some are allowed to go outside that range, + * and some are FP but manually clamped in the XP. + */ +enum class GrClampType { + kAuto, // Normalized, fixed-point configs + kManual, // Clamped FP configs + kNone, // Normal (unclamped) FP configs +}; + +/** + * A number of rectangle/quadrilateral drawing APIs can control anti-aliasing on a per edge basis. + * These masks specify which edges are AA'ed. The intent for this is to support tiling with seamless + * boundaries, where the inner edges are non-AA and the outer edges are AA. Regular rectangle draws + * simply use kAll or kNone depending on if they want anti-aliasing or not. + * + * In APIs that support per-edge AA, GrQuadAAFlags is the only AA-control parameter that is + * provided (compared to the typical GrAA parameter). kNone is equivalent to GrAA::kNo, and any + * other set of edge flags would require GrAA::kYes (with rendering output dependent on how that + * maps to GrAAType for a given SurfaceDrawContext). + * + * These values are identical to SkCanvas::QuadAAFlags. + */ +enum class GrQuadAAFlags { + kLeft = 0b0001, + kTop = 0b0010, + kRight = 0b0100, + kBottom = 0b1000, + + kNone = 0b0000, + kAll = 0b1111, +}; + +GR_MAKE_BITFIELD_CLASS_OPS(GrQuadAAFlags) + +static inline GrQuadAAFlags SkToGrQuadAAFlags(unsigned flags) { + return static_cast(flags); +} + +/** + * The type of texture. Backends other than GL currently only use the 2D value but the type must + * still be known at the API-neutral layer as it used to determine whether MIP maps, renderability, + * and sampling parameters are legal for proxies that will be instantiated with wrapped textures. + */ +enum class GrTextureType { + kNone, + k2D, + /* Rectangle uses unnormalized texture coordinates. */ + kRectangle, + kExternal +}; + +enum GrShaderType { + kVertex_GrShaderType, + kFragment_GrShaderType, + + kLast_GrShaderType = kFragment_GrShaderType +}; +static const int kGrShaderTypeCount = kLast_GrShaderType + 1; + +enum GrShaderFlags { + kNone_GrShaderFlags = 0, + kVertex_GrShaderFlag = 1 << 0, + kFragment_GrShaderFlag = 1 << 1 +}; +SK_MAKE_BITFIELD_OPS(GrShaderFlags) + +/** Rectangle and external textures only support the clamp wrap mode and do not support + * MIP maps. + */ +static inline bool GrTextureTypeHasRestrictedSampling(GrTextureType type) { + switch (type) { + case GrTextureType::k2D: + return false; + case GrTextureType::kRectangle: + return true; + case GrTextureType::kExternal: + return true; + default: + SK_ABORT("Unexpected texture type"); + } +} + +////////////////////////////////////////////////////////////////////////////// + +/** + * Types used to describe format of vertices in arrays. + */ +enum GrVertexAttribType { + kFloat_GrVertexAttribType = 0, + kFloat2_GrVertexAttribType, + kFloat3_GrVertexAttribType, + kFloat4_GrVertexAttribType, + kHalf_GrVertexAttribType, + kHalf2_GrVertexAttribType, + kHalf4_GrVertexAttribType, + + kInt2_GrVertexAttribType, // vector of 2 32-bit ints + kInt3_GrVertexAttribType, // vector of 3 32-bit ints + kInt4_GrVertexAttribType, // vector of 4 32-bit ints + + + kByte_GrVertexAttribType, // signed byte + kByte2_GrVertexAttribType, // vector of 2 8-bit signed bytes + kByte4_GrVertexAttribType, // vector of 4 8-bit signed bytes + kUByte_GrVertexAttribType, // unsigned byte + kUByte2_GrVertexAttribType, // vector of 2 8-bit unsigned bytes + kUByte4_GrVertexAttribType, // vector of 4 8-bit unsigned bytes + + kUByte_norm_GrVertexAttribType, // unsigned byte, e.g. coverage, 0 -> 0.0f, 255 -> 1.0f. + kUByte4_norm_GrVertexAttribType, // vector of 4 unsigned bytes, e.g. colors, 0 -> 0.0f, + // 255 -> 1.0f. + + kShort2_GrVertexAttribType, // vector of 2 16-bit shorts. + kShort4_GrVertexAttribType, // vector of 4 16-bit shorts. + + kUShort2_GrVertexAttribType, // vector of 2 unsigned shorts. 0 -> 0, 65535 -> 65535. + kUShort2_norm_GrVertexAttribType, // vector of 2 unsigned shorts. 0 -> 0.0f, 65535 -> 1.0f. + + kInt_GrVertexAttribType, + kUInt_GrVertexAttribType, + + kUShort_norm_GrVertexAttribType, + + kUShort4_norm_GrVertexAttribType, // vector of 4 unsigned shorts. 0 -> 0.0f, 65535 -> 1.0f. + + kLast_GrVertexAttribType = kUShort4_norm_GrVertexAttribType +}; +static const int kGrVertexAttribTypeCount = kLast_GrVertexAttribType + 1; + +////////////////////////////////////////////////////////////////////////////// + +/** + * We have coverage effects that clip rendering to the edge of some geometric primitive. + * This enum specifies how that clipping is performed. Not all factories that take a + * GrClipEdgeType will succeed with all values and it is up to the caller to verify success. + */ +enum class GrClipEdgeType { + kFillBW, + kFillAA, + kInverseFillBW, + kInverseFillAA, + + kLast = kInverseFillAA +}; +static const int kGrClipEdgeTypeCnt = (int) GrClipEdgeType::kLast + 1; + +static constexpr bool GrClipEdgeTypeIsFill(const GrClipEdgeType edgeType) { + return (GrClipEdgeType::kFillAA == edgeType || GrClipEdgeType::kFillBW == edgeType); +} + +static constexpr bool GrClipEdgeTypeIsInverseFill(const GrClipEdgeType edgeType) { + return (GrClipEdgeType::kInverseFillAA == edgeType || + GrClipEdgeType::kInverseFillBW == edgeType); +} + +static constexpr bool GrClipEdgeTypeIsAA(const GrClipEdgeType edgeType) { + return (GrClipEdgeType::kFillBW != edgeType && + GrClipEdgeType::kInverseFillBW != edgeType); +} + +static inline GrClipEdgeType GrInvertClipEdgeType(const GrClipEdgeType edgeType) { + switch (edgeType) { + case GrClipEdgeType::kFillBW: + return GrClipEdgeType::kInverseFillBW; + case GrClipEdgeType::kFillAA: + return GrClipEdgeType::kInverseFillAA; + case GrClipEdgeType::kInverseFillBW: + return GrClipEdgeType::kFillBW; + case GrClipEdgeType::kInverseFillAA: + return GrClipEdgeType::kFillAA; + } + SkUNREACHABLE; +} + +/** + * Indicates the type of pending IO operations that can be recorded for gpu resources. + */ +enum GrIOType { + kRead_GrIOType, + kWrite_GrIOType, + kRW_GrIOType +}; + +/** + * Indicates the type of data that a GPU buffer will be used for. + */ +enum class GrGpuBufferType { + kVertex, + kIndex, + kDrawIndirect, + kXferCpuToGpu, + kXferGpuToCpu, + kUniform, +}; +static const constexpr int kGrGpuBufferTypeCount = static_cast(GrGpuBufferType::kUniform) + 1; + +/** + * Provides a performance hint regarding the frequency at which a data store will be accessed. + */ +enum GrAccessPattern { + /** Data store will be respecified repeatedly and used many times. */ + kDynamic_GrAccessPattern, + /** Data store will be specified once and used many times. (Thus disqualified from caching.) */ + kStatic_GrAccessPattern, + /** Data store will be specified once and used at most a few times. (Also can't be cached.) */ + kStream_GrAccessPattern, + + kLast_GrAccessPattern = kStream_GrAccessPattern +}; + +// Flags shared between the GrSurface & GrSurfaceProxy class hierarchies +enum class GrInternalSurfaceFlags { + kNone = 0, + + // Texture-level + + // Means the pixels in the texture are read-only. Cannot also be a GrRenderTarget[Proxy]. + kReadOnly = 1 << 0, + + // RT-level + + // This flag is for use with GL only. It tells us that the internal render target wraps FBO 0. + kGLRTFBOIDIs0 = 1 << 1, + + // This means the render target is multisampled, and internally holds a non-msaa texture for + // resolving into. The render target resolves itself by blitting into this internal texture. + // (asTexture() might or might not return the internal texture, but if it does, we always + // resolve the render target before accessing this texture's data.) + kRequiresManualMSAAResolve = 1 << 2, + + // This means the pixels in the render target are write-only. This is used for Dawn and Metal + // swap chain targets which can be rendered to, but not read or copied. + kFramebufferOnly = 1 << 3, + + // This is a Vulkan only flag. If set the surface can be used as an input attachment in a + // shader. This is used for doing in shader blending where we want to sample from the same + // image we are drawing to. + kVkRTSupportsInputAttachment = 1 << 4, +}; + +GR_MAKE_BITFIELD_CLASS_OPS(GrInternalSurfaceFlags) + +// 'GR_MAKE_BITFIELD_CLASS_OPS' defines the & operator on GrInternalSurfaceFlags to return bool. +// We want to find the bitwise & with these masks, so we declare them as ints. +constexpr static int kGrInternalTextureFlagsMask = static_cast( + GrInternalSurfaceFlags::kReadOnly); + +// We don't include kVkRTSupportsInputAttachment in this mask since we check it manually. We don't +// require that both the surface and proxy have matching values for this flag. Instead we require +// if the proxy has it set then the surface must also have it set. All other flags listed here must +// match on the proxy and surface. +// TODO: Add back kFramebufferOnly flag here once we update GrSurfaceCharacterization to take it +// as a flag. skbug.com/10672 +constexpr static int kGrInternalRenderTargetFlagsMask = static_cast( + GrInternalSurfaceFlags::kGLRTFBOIDIs0 | + GrInternalSurfaceFlags::kRequiresManualMSAAResolve/* | + GrInternalSurfaceFlags::kFramebufferOnly*/); + +constexpr static int kGrInternalTextureRenderTargetFlagsMask = + kGrInternalTextureFlagsMask | kGrInternalRenderTargetFlagsMask; + +#ifdef SK_DEBUG +// Takes a pointer to a GrCaps, and will suppress prints if required +#define GrCapsDebugf(caps, ...) if (!(caps)->suppressPrints()) SkDebugf(__VA_ARGS__) +#else +#define GrCapsDebugf(caps, ...) do {} while (0) +#endif + +/** + * Specifies if the holder owns the backend, OpenGL or Vulkan, object. + */ +enum class GrBackendObjectOwnership : bool { + /** Holder does not destroy the backend object. */ + kBorrowed = false, + /** Holder destroys the backend object. */ + kOwned = true +}; + +/** + * Used to include or exclude specific GPU path renderers for testing purposes. + */ +enum class GpuPathRenderers { + kNone = 0, // Always use software masks and/or DefaultPathRenderer. + kDashLine = 1 << 0, + kAtlas = 1 << 1, + kTessellation = 1 << 2, + kCoverageCounting = 1 << 3, + kAAHairline = 1 << 4, + kAAConvex = 1 << 5, + kAALinearizing = 1 << 6, + kSmall = 1 << 7, + kTriangulating = 1 << 8, + kDefault = ((1 << 9) - 1) // All path renderers. +}; + +/** + * Used to describe the current state of Mips on a GrTexture + */ +enum class GrMipmapStatus { + kNotAllocated, // Mips have not been allocated + kDirty, // Mips are allocated but the full mip tree does not have valid data + kValid, // All levels fully allocated and have valid data in them +}; + +GR_MAKE_BITFIELD_CLASS_OPS(GpuPathRenderers) + +/** + * Like SkColorType this describes a layout of pixel data in CPU memory. It specifies the channels, + * their type, and width. This exists so that the GPU backend can have private types that have no + * analog in the public facing SkColorType enum and omit types not implemented in the GPU backend. + * It does not refer to a texture format and the mapping to texture formats may be many-to-many. + * It does not specify the sRGB encoding of the stored values. The components are listed in order of + * where they appear in memory. In other words the first component listed is in the low bits and + * the last component in the high bits. + */ +enum class GrColorType { + kUnknown, + kAlpha_8, + kBGR_565, + kRGB_565, + kABGR_4444, // This name differs from SkColorType. kARGB_4444_SkColorType is misnamed. + kRGBA_8888, + kRGBA_8888_SRGB, + kRGB_888x, + kRG_88, + kBGRA_8888, + kRGBA_1010102, + kBGRA_1010102, + kRGBA_10x6, + kGray_8, + kGrayAlpha_88, + kAlpha_F16, + kRGBA_F16, + kRGBA_F16_Clamped, + kRGBA_F32, + + kAlpha_16, + kRG_1616, + kRG_F16, + kRGBA_16161616, + + // Unusual types that come up after reading back in cases where we are reassigning the meaning + // of a texture format's channels to use for a particular color format but have to read back the + // data to a full RGBA quadruple. (e.g. using a R8 texture format as A8 color type but the API + // only supports reading to RGBA8.) None of these have SkColorType equivalents. + kAlpha_8xxx, + kAlpha_F32xxx, + kGray_8xxx, + kR_8xxx, + + // Types used to initialize backend textures. + kRGB_888, + kR_8, + kR_16, + kR_F16, + kGray_F16, + kBGRA_4444, + kARGB_4444, + + kLast = kARGB_4444 +}; + +static const int kGrColorTypeCnt = static_cast(GrColorType::kLast) + 1; + +static constexpr SkColorType GrColorTypeToSkColorType(GrColorType ct) { + switch (ct) { + case GrColorType::kUnknown: return kUnknown_SkColorType; + case GrColorType::kAlpha_8: return kAlpha_8_SkColorType; + case GrColorType::kBGR_565: return kRGB_565_SkColorType; + case GrColorType::kRGB_565: return kUnknown_SkColorType; + case GrColorType::kABGR_4444: return kARGB_4444_SkColorType; + case GrColorType::kRGBA_8888: return kRGBA_8888_SkColorType; + case GrColorType::kRGBA_8888_SRGB: return kSRGBA_8888_SkColorType; + case GrColorType::kRGB_888x: return kRGB_888x_SkColorType; + case GrColorType::kRG_88: return kR8G8_unorm_SkColorType; + case GrColorType::kBGRA_8888: return kBGRA_8888_SkColorType; + case GrColorType::kRGBA_1010102: return kRGBA_1010102_SkColorType; + case GrColorType::kBGRA_1010102: return kBGRA_1010102_SkColorType; + case GrColorType::kRGBA_10x6: return kRGBA_10x6_SkColorType; + case GrColorType::kGray_8: return kGray_8_SkColorType; + case GrColorType::kGrayAlpha_88: return kUnknown_SkColorType; + case GrColorType::kAlpha_F16: return kA16_float_SkColorType; + case GrColorType::kRGBA_F16: return kRGBA_F16_SkColorType; + case GrColorType::kRGBA_F16_Clamped: return kRGBA_F16Norm_SkColorType; + case GrColorType::kRGBA_F32: return kRGBA_F32_SkColorType; + case GrColorType::kAlpha_8xxx: return kUnknown_SkColorType; + case GrColorType::kAlpha_F32xxx: return kUnknown_SkColorType; + case GrColorType::kGray_8xxx: return kUnknown_SkColorType; + case GrColorType::kR_8xxx: return kUnknown_SkColorType; + case GrColorType::kAlpha_16: return kA16_unorm_SkColorType; + case GrColorType::kRG_1616: return kR16G16_unorm_SkColorType; + case GrColorType::kRGBA_16161616: return kR16G16B16A16_unorm_SkColorType; + case GrColorType::kRG_F16: return kR16G16_float_SkColorType; + case GrColorType::kRGB_888: return kUnknown_SkColorType; + case GrColorType::kR_8: return kR8_unorm_SkColorType; + case GrColorType::kR_16: return kUnknown_SkColorType; + case GrColorType::kR_F16: return kUnknown_SkColorType; + case GrColorType::kGray_F16: return kUnknown_SkColorType; + case GrColorType::kARGB_4444: return kUnknown_SkColorType; + case GrColorType::kBGRA_4444: return kUnknown_SkColorType; + } + SkUNREACHABLE; +} + +static constexpr GrColorType SkColorTypeToGrColorType(SkColorType ct) { + switch (ct) { + case kUnknown_SkColorType: return GrColorType::kUnknown; + case kAlpha_8_SkColorType: return GrColorType::kAlpha_8; + case kRGB_565_SkColorType: return GrColorType::kBGR_565; + case kARGB_4444_SkColorType: return GrColorType::kABGR_4444; + case kRGBA_8888_SkColorType: return GrColorType::kRGBA_8888; + case kSRGBA_8888_SkColorType: return GrColorType::kRGBA_8888_SRGB; + case kRGB_888x_SkColorType: return GrColorType::kRGB_888x; + case kBGRA_8888_SkColorType: return GrColorType::kBGRA_8888; + case kGray_8_SkColorType: return GrColorType::kGray_8; + case kRGBA_F16Norm_SkColorType: return GrColorType::kRGBA_F16_Clamped; + case kRGBA_F16_SkColorType: return GrColorType::kRGBA_F16; + case kRGBA_1010102_SkColorType: return GrColorType::kRGBA_1010102; + case kRGB_101010x_SkColorType: return GrColorType::kUnknown; + case kBGRA_1010102_SkColorType: return GrColorType::kBGRA_1010102; + case kBGR_101010x_SkColorType: return GrColorType::kUnknown; + case kBGR_101010x_XR_SkColorType: return GrColorType::kUnknown; + case kBGRA_10101010_XR_SkColorType: return GrColorType::kUnknown; + case kRGBA_10x6_SkColorType: return GrColorType::kRGBA_10x6; + case kRGBA_F32_SkColorType: return GrColorType::kRGBA_F32; + case kR8G8_unorm_SkColorType: return GrColorType::kRG_88; + case kA16_unorm_SkColorType: return GrColorType::kAlpha_16; + case kR16G16_unorm_SkColorType: return GrColorType::kRG_1616; + case kA16_float_SkColorType: return GrColorType::kAlpha_F16; + case kR16G16_float_SkColorType: return GrColorType::kRG_F16; + case kR16G16B16A16_unorm_SkColorType: return GrColorType::kRGBA_16161616; + case kR8_unorm_SkColorType: return GrColorType::kR_8; + } + SkUNREACHABLE; +} + +static constexpr uint32_t GrColorTypeChannelFlags(GrColorType ct) { + switch (ct) { + case GrColorType::kUnknown: return 0; + case GrColorType::kAlpha_8: return kAlpha_SkColorChannelFlag; + case GrColorType::kBGR_565: return kRGB_SkColorChannelFlags; + case GrColorType::kRGB_565: return kRGB_SkColorChannelFlags; + case GrColorType::kABGR_4444: return kRGBA_SkColorChannelFlags; + case GrColorType::kRGBA_8888: return kRGBA_SkColorChannelFlags; + case GrColorType::kRGBA_8888_SRGB: return kRGBA_SkColorChannelFlags; + case GrColorType::kRGB_888x: return kRGB_SkColorChannelFlags; + case GrColorType::kRG_88: return kRG_SkColorChannelFlags; + case GrColorType::kBGRA_8888: return kRGBA_SkColorChannelFlags; + case GrColorType::kRGBA_1010102: return kRGBA_SkColorChannelFlags; + case GrColorType::kBGRA_1010102: return kRGBA_SkColorChannelFlags; + case GrColorType::kRGBA_10x6: return kRGBA_SkColorChannelFlags; + case GrColorType::kGray_8: return kGray_SkColorChannelFlag; + case GrColorType::kGrayAlpha_88: return kGrayAlpha_SkColorChannelFlags; + case GrColorType::kAlpha_F16: return kAlpha_SkColorChannelFlag; + case GrColorType::kRGBA_F16: return kRGBA_SkColorChannelFlags; + case GrColorType::kRGBA_F16_Clamped: return kRGBA_SkColorChannelFlags; + case GrColorType::kRGBA_F32: return kRGBA_SkColorChannelFlags; + case GrColorType::kAlpha_8xxx: return kAlpha_SkColorChannelFlag; + case GrColorType::kAlpha_F32xxx: return kAlpha_SkColorChannelFlag; + case GrColorType::kGray_8xxx: return kGray_SkColorChannelFlag; + case GrColorType::kR_8xxx: return kRed_SkColorChannelFlag; + case GrColorType::kAlpha_16: return kAlpha_SkColorChannelFlag; + case GrColorType::kRG_1616: return kRG_SkColorChannelFlags; + case GrColorType::kRGBA_16161616: return kRGBA_SkColorChannelFlags; + case GrColorType::kRG_F16: return kRG_SkColorChannelFlags; + case GrColorType::kRGB_888: return kRGB_SkColorChannelFlags; + case GrColorType::kR_8: return kRed_SkColorChannelFlag; + case GrColorType::kR_16: return kRed_SkColorChannelFlag; + case GrColorType::kR_F16: return kRed_SkColorChannelFlag; + case GrColorType::kGray_F16: return kGray_SkColorChannelFlag; + case GrColorType::kARGB_4444: return kRGBA_SkColorChannelFlags; + case GrColorType::kBGRA_4444: return kRGBA_SkColorChannelFlags; + } + SkUNREACHABLE; +} + +/** + * Describes the encoding of channel data in a GrColorType. + */ +enum class GrColorTypeEncoding { + kUnorm, + kSRGBUnorm, + // kSnorm, + kFloat, + // kSint + // kUint +}; + +/** + * Describes a GrColorType by how many bits are used for each color component and how they are + * encoded. Currently all the non-zero channels share a single GrColorTypeEncoding. This could be + * expanded to store separate encodings and to indicate which bits belong to which components. + */ +class GrColorFormatDesc { +public: + static constexpr GrColorFormatDesc MakeRGBA(int rgba, GrColorTypeEncoding e) { + return {rgba, rgba, rgba, rgba, 0, e}; + } + + static constexpr GrColorFormatDesc MakeRGBA(int rgb, int a, GrColorTypeEncoding e) { + return {rgb, rgb, rgb, a, 0, e}; + } + + static constexpr GrColorFormatDesc MakeRGB(int rgb, GrColorTypeEncoding e) { + return {rgb, rgb, rgb, 0, 0, e}; + } + + static constexpr GrColorFormatDesc MakeRGB(int r, int g, int b, GrColorTypeEncoding e) { + return {r, g, b, 0, 0, e}; + } + + static constexpr GrColorFormatDesc MakeAlpha(int a, GrColorTypeEncoding e) { + return {0, 0, 0, a, 0, e}; + } + + static constexpr GrColorFormatDesc MakeR(int r, GrColorTypeEncoding e) { + return {r, 0, 0, 0, 0, e}; + } + + static constexpr GrColorFormatDesc MakeRG(int rg, GrColorTypeEncoding e) { + return {rg, rg, 0, 0, 0, e}; + } + + static constexpr GrColorFormatDesc MakeGray(int grayBits, GrColorTypeEncoding e) { + return {0, 0, 0, 0, grayBits, e}; + } + + static constexpr GrColorFormatDesc MakeGrayAlpha(int grayAlpha, GrColorTypeEncoding e) { + return {0, 0, 0, 0, grayAlpha, e}; + } + + static constexpr GrColorFormatDesc MakeInvalid() { return {}; } + + constexpr int r() const { return fRBits; } + constexpr int g() const { return fGBits; } + constexpr int b() const { return fBBits; } + constexpr int a() const { return fABits; } + constexpr int operator[](int c) const { + switch (c) { + case 0: return this->r(); + case 1: return this->g(); + case 2: return this->b(); + case 3: return this->a(); + } + SkUNREACHABLE; + } + + constexpr int gray() const { return fGrayBits; } + + constexpr GrColorTypeEncoding encoding() const { return fEncoding; } + +private: + int fRBits = 0; + int fGBits = 0; + int fBBits = 0; + int fABits = 0; + int fGrayBits = 0; + GrColorTypeEncoding fEncoding = GrColorTypeEncoding::kUnorm; + + constexpr GrColorFormatDesc() = default; + + constexpr GrColorFormatDesc(int r, int g, int b, int a, int gray, GrColorTypeEncoding encoding) + : fRBits(r), fGBits(g), fBBits(b), fABits(a), fGrayBits(gray), fEncoding(encoding) { + SkASSERT(r >= 0 && g >= 0 && b >= 0 && a >= 0 && gray >= 0); + SkASSERT(!gray || (!r && !g && !b)); + SkASSERT(r || g || b || a || gray); + } +}; + +static constexpr GrColorFormatDesc GrGetColorTypeDesc(GrColorType ct) { + switch (ct) { + case GrColorType::kUnknown: + return GrColorFormatDesc::MakeInvalid(); + case GrColorType::kAlpha_8: + return GrColorFormatDesc::MakeAlpha(8, GrColorTypeEncoding::kUnorm); + case GrColorType::kBGR_565: + return GrColorFormatDesc::MakeRGB(5, 6, 5, GrColorTypeEncoding::kUnorm); + case GrColorType::kRGB_565: + return GrColorFormatDesc::MakeRGB(5, 6, 5, GrColorTypeEncoding::kUnorm); + case GrColorType::kABGR_4444: + return GrColorFormatDesc::MakeRGBA(4, GrColorTypeEncoding::kUnorm); + case GrColorType::kRGBA_8888: + return GrColorFormatDesc::MakeRGBA(8, GrColorTypeEncoding::kUnorm); + case GrColorType::kRGBA_8888_SRGB: + return GrColorFormatDesc::MakeRGBA(8, GrColorTypeEncoding::kSRGBUnorm); + case GrColorType::kRGB_888x: + return GrColorFormatDesc::MakeRGB(8, GrColorTypeEncoding::kUnorm); + case GrColorType::kRG_88: + return GrColorFormatDesc::MakeRG(8, GrColorTypeEncoding::kUnorm); + case GrColorType::kBGRA_8888: + return GrColorFormatDesc::MakeRGBA(8, GrColorTypeEncoding::kUnorm); + case GrColorType::kRGBA_1010102: + return GrColorFormatDesc::MakeRGBA(10, 2, GrColorTypeEncoding::kUnorm); + case GrColorType::kBGRA_1010102: + return GrColorFormatDesc::MakeRGBA(10, 2, GrColorTypeEncoding::kUnorm); + case GrColorType::kRGBA_10x6: + return GrColorFormatDesc::MakeRGBA(10, GrColorTypeEncoding::kUnorm); + case GrColorType::kGray_8: + return GrColorFormatDesc::MakeGray(8, GrColorTypeEncoding::kUnorm); + case GrColorType::kGrayAlpha_88: + return GrColorFormatDesc::MakeGrayAlpha(8, GrColorTypeEncoding::kUnorm); + case GrColorType::kAlpha_F16: + return GrColorFormatDesc::MakeAlpha(16, GrColorTypeEncoding::kFloat); + case GrColorType::kRGBA_F16: + return GrColorFormatDesc::MakeRGBA(16, GrColorTypeEncoding::kFloat); + case GrColorType::kRGBA_F16_Clamped: + return GrColorFormatDesc::MakeRGBA(16, GrColorTypeEncoding::kFloat); + case GrColorType::kRGBA_F32: + return GrColorFormatDesc::MakeRGBA(32, GrColorTypeEncoding::kFloat); + case GrColorType::kAlpha_8xxx: + return GrColorFormatDesc::MakeAlpha(8, GrColorTypeEncoding::kUnorm); + case GrColorType::kAlpha_F32xxx: + return GrColorFormatDesc::MakeAlpha(32, GrColorTypeEncoding::kFloat); + case GrColorType::kGray_8xxx: + return GrColorFormatDesc::MakeGray(8, GrColorTypeEncoding::kUnorm); + case GrColorType::kR_8xxx: + return GrColorFormatDesc::MakeR(8, GrColorTypeEncoding::kUnorm); + case GrColorType::kAlpha_16: + return GrColorFormatDesc::MakeAlpha(16, GrColorTypeEncoding::kUnorm); + case GrColorType::kRG_1616: + return GrColorFormatDesc::MakeRG(16, GrColorTypeEncoding::kUnorm); + case GrColorType::kRGBA_16161616: + return GrColorFormatDesc::MakeRGBA(16, GrColorTypeEncoding::kUnorm); + case GrColorType::kRG_F16: + return GrColorFormatDesc::MakeRG(16, GrColorTypeEncoding::kFloat); + case GrColorType::kRGB_888: + return GrColorFormatDesc::MakeRGB(8, GrColorTypeEncoding::kUnorm); + case GrColorType::kR_8: + return GrColorFormatDesc::MakeR(8, GrColorTypeEncoding::kUnorm); + case GrColorType::kR_16: + return GrColorFormatDesc::MakeR(16, GrColorTypeEncoding::kUnorm); + case GrColorType::kR_F16: + return GrColorFormatDesc::MakeR(16, GrColorTypeEncoding::kFloat); + case GrColorType::kGray_F16: + return GrColorFormatDesc::MakeGray(16, GrColorTypeEncoding::kFloat); + case GrColorType::kARGB_4444: + return GrColorFormatDesc::MakeRGBA(4, GrColorTypeEncoding::kUnorm); + case GrColorType::kBGRA_4444: + return GrColorFormatDesc::MakeRGBA(4, GrColorTypeEncoding::kUnorm); + } + SkUNREACHABLE; +} + +static constexpr GrClampType GrColorTypeClampType(GrColorType colorType) { + if (GrGetColorTypeDesc(colorType).encoding() == GrColorTypeEncoding::kUnorm || + GrGetColorTypeDesc(colorType).encoding() == GrColorTypeEncoding::kSRGBUnorm) { + return GrClampType::kAuto; + } + return GrColorType::kRGBA_F16_Clamped == colorType ? GrClampType::kManual : GrClampType::kNone; +} + +// Consider a color type "wider" than n if it has more than n bits for any its representable +// channels. +static constexpr bool GrColorTypeIsWiderThan(GrColorType colorType, int n) { + SkASSERT(n > 0); + auto desc = GrGetColorTypeDesc(colorType); + return (desc.r() && desc.r() > n )|| + (desc.g() && desc.g() > n) || + (desc.b() && desc.b() > n) || + (desc.a() && desc.a() > n) || + (desc.gray() && desc.gray() > n); +} + +static constexpr bool GrColorTypeIsAlphaOnly(GrColorType ct) { + return GrColorTypeChannelFlags(ct) == kAlpha_SkColorChannelFlag; +} + +static constexpr bool GrColorTypeHasAlpha(GrColorType ct) { + return GrColorTypeChannelFlags(ct) & kAlpha_SkColorChannelFlag; +} + +static constexpr size_t GrColorTypeBytesPerPixel(GrColorType ct) { + switch (ct) { + case GrColorType::kUnknown: return 0; + case GrColorType::kAlpha_8: return 1; + case GrColorType::kBGR_565: return 2; + case GrColorType::kRGB_565: return 2; + case GrColorType::kABGR_4444: return 2; + case GrColorType::kRGBA_8888: return 4; + case GrColorType::kRGBA_8888_SRGB: return 4; + case GrColorType::kRGB_888x: return 4; + case GrColorType::kRG_88: return 2; + case GrColorType::kBGRA_8888: return 4; + case GrColorType::kRGBA_1010102: return 4; + case GrColorType::kBGRA_1010102: return 4; + case GrColorType::kRGBA_10x6: return 8; + case GrColorType::kGray_8: return 1; + case GrColorType::kGrayAlpha_88: return 2; + case GrColorType::kAlpha_F16: return 2; + case GrColorType::kRGBA_F16: return 8; + case GrColorType::kRGBA_F16_Clamped: return 8; + case GrColorType::kRGBA_F32: return 16; + case GrColorType::kAlpha_8xxx: return 4; + case GrColorType::kAlpha_F32xxx: return 16; + case GrColorType::kGray_8xxx: return 4; + case GrColorType::kR_8xxx: return 4; + case GrColorType::kAlpha_16: return 2; + case GrColorType::kRG_1616: return 4; + case GrColorType::kRGBA_16161616: return 8; + case GrColorType::kRG_F16: return 4; + case GrColorType::kRGB_888: return 3; + case GrColorType::kR_8: return 1; + case GrColorType::kR_16: return 2; + case GrColorType::kR_F16: return 2; + case GrColorType::kGray_F16: return 2; + case GrColorType::kARGB_4444: return 2; + case GrColorType::kBGRA_4444: return 2; + } + SkUNREACHABLE; +} + +enum class GrDstSampleFlags { + kNone = 0, + kRequiresTextureBarrier = 1 << 0, + kAsInputAttachment = 1 << 1, +}; +GR_MAKE_BITFIELD_CLASS_OPS(GrDstSampleFlags) + +using GrVisitProxyFunc = std::function; + +#if defined(SK_DEBUG) || defined(GR_TEST_UTILS) || defined(SK_ENABLE_DUMP_GPU) +static constexpr const char* GrBackendApiToStr(GrBackendApi api) { + switch (api) { + case GrBackendApi::kOpenGL: return "OpenGL"; + case GrBackendApi::kVulkan: return "Vulkan"; + case GrBackendApi::kMetal: return "Metal"; + case GrBackendApi::kDirect3D: return "Direct3D"; + case GrBackendApi::kMock: return "Mock"; + case GrBackendApi::kUnsupported: return "Unsupported"; + } + SkUNREACHABLE; +} + +static constexpr const char* GrColorTypeToStr(GrColorType ct) { + switch (ct) { + case GrColorType::kUnknown: return "kUnknown"; + case GrColorType::kAlpha_8: return "kAlpha_8"; + case GrColorType::kBGR_565: return "kBGR_565"; + case GrColorType::kRGB_565: return "kRGB_565"; + case GrColorType::kABGR_4444: return "kABGR_4444"; + case GrColorType::kRGBA_8888: return "kRGBA_8888"; + case GrColorType::kRGBA_8888_SRGB: return "kRGBA_8888_SRGB"; + case GrColorType::kRGB_888x: return "kRGB_888x"; + case GrColorType::kRG_88: return "kRG_88"; + case GrColorType::kBGRA_8888: return "kBGRA_8888"; + case GrColorType::kRGBA_1010102: return "kRGBA_1010102"; + case GrColorType::kBGRA_1010102: return "kBGRA_1010102"; + case GrColorType::kRGBA_10x6: return "kBGRA_10x6"; + case GrColorType::kGray_8: return "kGray_8"; + case GrColorType::kGrayAlpha_88: return "kGrayAlpha_88"; + case GrColorType::kAlpha_F16: return "kAlpha_F16"; + case GrColorType::kRGBA_F16: return "kRGBA_F16"; + case GrColorType::kRGBA_F16_Clamped: return "kRGBA_F16_Clamped"; + case GrColorType::kRGBA_F32: return "kRGBA_F32"; + case GrColorType::kAlpha_8xxx: return "kAlpha_8xxx"; + case GrColorType::kAlpha_F32xxx: return "kAlpha_F32xxx"; + case GrColorType::kGray_8xxx: return "kGray_8xxx"; + case GrColorType::kR_8xxx: return "kR_8xxx"; + case GrColorType::kAlpha_16: return "kAlpha_16"; + case GrColorType::kRG_1616: return "kRG_1616"; + case GrColorType::kRGBA_16161616: return "kRGBA_16161616"; + case GrColorType::kRG_F16: return "kRG_F16"; + case GrColorType::kRGB_888: return "kRGB_888"; + case GrColorType::kR_8: return "kR_8"; + case GrColorType::kR_16: return "kR_16"; + case GrColorType::kR_F16: return "kR_F16"; + case GrColorType::kGray_F16: return "kGray_F16"; + case GrColorType::kARGB_4444: return "kARGB_4444"; + case GrColorType::kBGRA_4444: return "kBGRA_4444"; + } + SkUNREACHABLE; +} + +static constexpr const char* GrSurfaceOriginToStr(GrSurfaceOrigin origin) { + switch (origin) { + case kTopLeft_GrSurfaceOrigin: return "kTopLeft"; + case kBottomLeft_GrSurfaceOrigin: return "kBottomLeft"; + } + SkUNREACHABLE; +} +#endif + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/gpu/graphite/ContextOptionsPriv.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/gpu/graphite/ContextOptionsPriv.h new file mode 100644 index 0000000000..769af79497 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/gpu/graphite/ContextOptionsPriv.h @@ -0,0 +1,70 @@ +/* + * 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 skgpu_graphite_ContextOptionsPriv_DEFINED +#define skgpu_graphite_ContextOptionsPriv_DEFINED + +namespace skgpu::graphite { + +/** + * Used to include or exclude a specific path rendering technique for testing purposes. + */ +enum class PathRendererStrategy { + /** + * Graphite selects the best path rendering technique for each shape. This is the default + * behavior. + */ + kDefault, + + /** + * All paths are rasterized into coverage masks using a GPU compute approach. This method + * always uses analytic anti-aliasing. + */ + kComputeAnalyticAA, + + /** + * All paths are rasterized into coverage masks using a GPU compute approach. This method + * supports 16 and 8 sample multi-sampled anti-aliasing. + */ + kComputeMSAA16, + kComputeMSAA8, + + /** + * All paths are rasterized into coverage masks using the CPU raster backend. + */ + kRasterAA, + + /** + * Render paths using tessellation and stencil-and-cover. + */ + kTessellation, +}; + +/** + * Private options that are only meant for testing within Skia's tools. + */ +struct ContextOptionsPriv { + + int fMaxTextureSizeOverride = SK_MaxS32; + + /** + * Maximum width and height of internal texture atlases. + */ + int fMaxTextureAtlasSize = 2048; + + /** + * If true, will store a pointer in Recorder that points back to the Context + * that created it. Used by readPixels() and other methods that normally require a Context. + */ + bool fStoreContextRefInRecorder = false; + + PathRendererStrategy fPathRendererStrategy = PathRendererStrategy::kDefault; +}; + +} // namespace skgpu::graphite + +#endif // skgpu_graphite_ContextOptionsPriv_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/gpu/graphite/DawnTypesPriv.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/gpu/graphite/DawnTypesPriv.h new file mode 100644 index 0000000000..c3c4aa0bbb --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/gpu/graphite/DawnTypesPriv.h @@ -0,0 +1,61 @@ +/* + * 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 skgpu_graphite_DawnTypesPriv_DEFINED +#define skgpu_graphite_DawnTypesPriv_DEFINED + +#include "include/core/SkString.h" +#include "include/gpu/graphite/dawn/DawnTypes.h" + +namespace skgpu::graphite { + +struct DawnTextureSpec { + DawnTextureSpec() = default; + DawnTextureSpec(const DawnTextureInfo& info) + : fFormat(info.fFormat) + , fViewFormat(info.fViewFormat) + , fUsage(info.fUsage) + , fAspect(info.fAspect) + , fSlice(info.fSlice) {} + + bool operator==(const DawnTextureSpec& that) const { + return fUsage == that.fUsage && fFormat == that.fFormat && + fViewFormat == that.fViewFormat && fAspect == that.fAspect && + fSlice == that.fSlice; + } + + bool isCompatible(const DawnTextureSpec& that) const { + // The usages may match or the usage passed in may be a superset of the usage stored within. + // The aspect should either match the plane aspect or should be All. + return getViewFormat() == that.getViewFormat() && (fUsage & that.fUsage) == fUsage && + (fAspect == that.fAspect || fAspect == wgpu::TextureAspect::All); + } + + wgpu::TextureFormat getViewFormat() const { + return fViewFormat != wgpu::TextureFormat::Undefined ? fViewFormat : fFormat; + } + + SkString toString() const; + + wgpu::TextureFormat fFormat = wgpu::TextureFormat::Undefined; + // `fViewFormat` is always single plane format or plane view format for a multiplanar + // wgpu::Texture. + wgpu::TextureFormat fViewFormat = wgpu::TextureFormat::Undefined; + wgpu::TextureUsage fUsage = wgpu::TextureUsage::None; + wgpu::TextureAspect fAspect = wgpu::TextureAspect::All; + uint32_t fSlice = 0; +}; + +DawnTextureInfo DawnTextureSpecToTextureInfo(const DawnTextureSpec& dawnSpec, + uint32_t sampleCount, + Mipmapped mipmapped); + +DawnTextureInfo DawnTextureInfoFromWGPUTexture(WGPUTexture texture); + +} // namespace skgpu::graphite + +#endif // skgpu_graphite_DawnTypesPriv_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/gpu/graphite/MtlGraphiteTypesPriv.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/gpu/graphite/MtlGraphiteTypesPriv.h new file mode 100644 index 0000000000..56059b6a52 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/gpu/graphite/MtlGraphiteTypesPriv.h @@ -0,0 +1,95 @@ +/* + * Copyright 2021 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef skgpu_graphite_MtlGraphiteTypesPriv_DEFINED +#define skgpu_graphite_MtlGraphiteTypesPriv_DEFINED + +#include "include/core/SkString.h" +#include "include/gpu/graphite/GraphiteTypes.h" +#include "include/gpu/graphite/mtl/MtlGraphiteTypes.h" + +/////////////////////////////////////////////////////////////////////////////// + +#ifdef __APPLE__ + +#include + +// We're using the MSL version as shorthand for the Metal SDK version here +#if defined(SK_BUILD_FOR_MAC) +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 130000 +#define SKGPU_GRAPHITE_METAL_SDK_VERSION 300 +#elif __MAC_OS_X_VERSION_MAX_ALLOWED >= 120000 +#define SKGPU_GRAPHITE_METAL_SDK_VERSION 240 +#elif __MAC_OS_X_VERSION_MAX_ALLOWED >= 110000 +#define SKGPU_GRAPHITE_METAL_SDK_VERSION 230 +#else +#error Must use at least 11.00 SDK to build Metal backend for MacOS +#endif +#else +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 160000 || __TV_OS_VERSION_MAX_ALLOWED >= 160000 +#define SKGPU_GRAPHITE_METAL_SDK_VERSION 300 +#elif __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000 || __TV_OS_VERSION_MAX_ALLOWED >= 150000 +#define SKGPU_GRAPHITE_METAL_SDK_VERSION 240 +#elif __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 || __TV_OS_VERSION_MAX_ALLOWED >= 140000 +#define SKGPU_GRAPHITE_METAL_SDK_VERSION 230 +#else +#error Must use at least 14.00 SDK to build Metal backend for iOS +#endif +#endif + +#endif // __APPLE__ + +namespace skgpu::graphite { + +struct MtlTextureSpec { + MtlTextureSpec() + : fFormat(0) + , fUsage(0) + , fStorageMode(0) + , fFramebufferOnly(false) {} + MtlTextureSpec(const MtlTextureInfo& info) + : fFormat(info.fFormat) + , fUsage(info.fUsage) + , fStorageMode(info.fStorageMode) + , fFramebufferOnly(info.fFramebufferOnly) {} + + bool operator==(const MtlTextureSpec& that) const { + return fFormat == that.fFormat && + fUsage == that.fUsage && + fStorageMode == that.fStorageMode && + fFramebufferOnly == that.fFramebufferOnly; + } + + bool isCompatible(const MtlTextureSpec& that) const { + // The usages may match or the usage passed in may be a superset of the usage stored within. + return fFormat == that.fFormat && + fStorageMode == that.fStorageMode && + fFramebufferOnly == that.fFramebufferOnly && + (fUsage & that.fUsage) == fUsage; + } + + SkString toString() const { + return SkStringPrintf("format=%u,usage=0x%04X,storageMode=%u,framebufferOnly=%d", + fFormat, + fUsage, + fStorageMode, + fFramebufferOnly); + } + + MtlPixelFormat fFormat; + MtlTextureUsage fUsage; + MtlStorageMode fStorageMode; + bool fFramebufferOnly; +}; + +MtlTextureInfo MtlTextureSpecToTextureInfo(const MtlTextureSpec& mtlSpec, + uint32_t sampleCount, + Mipmapped mipmapped); + +} // namespace skgpu::graphite + +#endif // skgpu_graphite_MtlGraphiteTypesPriv_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/gpu/graphite/VulkanGraphiteTypesPriv.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/gpu/graphite/VulkanGraphiteTypesPriv.h new file mode 100644 index 0000000000..57019163b8 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/gpu/graphite/VulkanGraphiteTypesPriv.h @@ -0,0 +1,83 @@ +/* + * 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 skgpu_graphite_VulkanGraphiteTypesPriv_DEFINED +#define skgpu_graphite_VulkanGraphiteTypesPriv_DEFINED + +#include "include/core/SkString.h" +#include "include/gpu/graphite/vk/VulkanGraphiteTypes.h" +#include "include/private/gpu/vk/SkiaVulkan.h" + +namespace skgpu::graphite { + +struct VulkanTextureSpec { + VulkanTextureSpec() + : fFlags(0) + , fFormat(VK_FORMAT_UNDEFINED) + , fImageTiling(VK_IMAGE_TILING_OPTIMAL) + , fImageUsageFlags(0) + , fSharingMode(VK_SHARING_MODE_EXCLUSIVE) + , fAspectMask(VK_IMAGE_ASPECT_COLOR_BIT) + , fYcbcrConversionInfo({}) {} + VulkanTextureSpec(const VulkanTextureInfo& info) + : fFlags(info.fFlags) + , fFormat(info.fFormat) + , fImageTiling(info.fImageTiling) + , fImageUsageFlags(info.fImageUsageFlags) + , fSharingMode(info.fSharingMode) + , fAspectMask(info.fAspectMask) + , fYcbcrConversionInfo(info.fYcbcrConversionInfo) {} + + bool operator==(const VulkanTextureSpec& that) const { + return fFlags == that.fFlags && + fFormat == that.fFormat && + fImageTiling == that.fImageTiling && + fImageUsageFlags == that.fImageUsageFlags && + fSharingMode == that.fSharingMode && + fAspectMask == that.fAspectMask && + fYcbcrConversionInfo == that.fYcbcrConversionInfo; + } + + bool isCompatible(const VulkanTextureSpec& that) const { + // The usages may match or the usage passed in may be a superset of the usage stored within. + return fFlags == that.fFlags && + fFormat == that.fFormat && + fImageTiling == that.fImageTiling && + fSharingMode == that.fSharingMode && + fAspectMask == that.fAspectMask && + (fImageUsageFlags & that.fImageUsageFlags) == fImageUsageFlags && + fYcbcrConversionInfo == that.fYcbcrConversionInfo; + } + + SkString toString() const { + return SkStringPrintf( + "flags=0x%08X,format=%d,imageTiling=%d,imageUsageFlags=0x%08X,sharingMode=%d," + "aspectMask=%u", + fFlags, + fFormat, + fImageTiling, + fImageUsageFlags, + fSharingMode, + fAspectMask); + } + + VkImageCreateFlags fFlags; + VkFormat fFormat; + VkImageTiling fImageTiling; + VkImageUsageFlags fImageUsageFlags; + VkSharingMode fSharingMode; + VkImageAspectFlags fAspectMask; + VulkanYcbcrConversionInfo fYcbcrConversionInfo; +}; + +VulkanTextureInfo VulkanTextureSpecToTextureInfo(const VulkanTextureSpec& vkSpec, + uint32_t sampleCount, + Mipmapped mipmapped); + +} // namespace skgpu::graphite + +#endif // skgpu_graphite_VulkanGraphiteTypesPriv_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/gpu/vk/SkiaVulkan.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/gpu/vk/SkiaVulkan.h new file mode 100644 index 0000000000..412dbf535f --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/private/gpu/vk/SkiaVulkan.h @@ -0,0 +1,36 @@ +/* + * 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 SkiaVulkan_DEFINED +#define SkiaVulkan_DEFINED + +#include "include/core/SkTypes.h" + +// IWYU pragma: begin_exports + +#if (SKIA_IMPLEMENTATION || !defined(SK_VULKAN)) && !defined(SK_USE_EXTERNAL_VULKAN_HEADERS) +#include "include/third_party/vulkan/vulkan/vulkan_core.h" +#else +// For google3 builds we don't set SKIA_IMPLEMENTATION so we need to make sure that the vulkan +// headers stay up to date for our needs +#include +#endif + +#ifdef SK_BUILD_FOR_ANDROID +// This is needed to get android extensions for external memory +#if (SKIA_IMPLEMENTATION || !defined(SK_VULKAN)) && !defined(SK_USE_EXTERNAL_VULKAN_HEADERS) +#include "include/third_party/vulkan/vulkan/vulkan_android.h" +#else +// For google3 builds we don't set SKIA_IMPLEMENTATION so we need to make sure that the vulkan +// headers stay up to date for our needs +#include +#endif +#endif + +// IWYU pragma: end_exports + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/sksl/OWNERS b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/sksl/OWNERS new file mode 100644 index 0000000000..9e9d9bb906 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/sksl/OWNERS @@ -0,0 +1,3 @@ +# In addition to include/ owners, the following reviewers can approve changes to SkSL public API: +brianosman@google.com +johnstiles@google.com diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/sksl/SkSLDebugTrace.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/sksl/SkSLDebugTrace.h new file mode 100644 index 0000000000..9c5eafbc94 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/sksl/SkSLDebugTrace.h @@ -0,0 +1,28 @@ +/* + * 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 SKSL_DEBUG_TRACE +#define SKSL_DEBUG_TRACE + +#include "include/core/SkRefCnt.h" + +class SkWStream; + +namespace SkSL { + +class DebugTrace : public SkRefCnt { +public: + /** Serializes a debug trace to JSON which can be parsed by our debugger. */ + virtual void writeTrace(SkWStream* w) const = 0; + + /** Generates a human-readable dump of the debug trace. */ + virtual void dump(SkWStream* o) const = 0; +}; + +} // namespace SkSL + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/sksl/SkSLVersion.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/sksl/SkSLVersion.h new file mode 100644 index 0000000000..ad059d580e --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/sksl/SkSLVersion.h @@ -0,0 +1,27 @@ +/* + * 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 SkSLVersion_DEFINED +#define SkSLVersion_DEFINED + +namespace SkSL { + +enum class Version { + /** + * Desktop GLSL 1.10, GLSL ES 1.00, WebGL 1.0 + */ + k100, + + /** + * Desktop GLSL 3.30, GLSL ES 3.00, WebGL 2.0 + */ + k300, +}; + +} // namespace SkSL + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/svg/SkSVGCanvas.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/svg/SkSVGCanvas.h new file mode 100644 index 0000000000..d4c38ea017 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/svg/SkSVGCanvas.h @@ -0,0 +1,42 @@ +/* + * 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 SkSVGCanvas_DEFINED +#define SkSVGCanvas_DEFINED + +#include "include/core/SkTypes.h" + +#include +#include + +class SkCanvas; +class SkWStream; +struct SkRect; + +class SK_API SkSVGCanvas { +public: + enum { + kConvertTextToPaths_Flag = 0x01, // emit text as s + kNoPrettyXML_Flag = 0x02, // suppress newlines and tabs in output + kRelativePathEncoding_Flag = 0x04, // use relative commands for path encoding + }; + + /** + * Returns a new canvas that will generate SVG commands from its draw calls, and send + * them to the provided stream. Ownership of the stream is not transfered, and it must + * remain valid for the lifetime of the returned canvas. + * + * The canvas may buffer some drawing calls, so the output is not guaranteed to be valid + * or complete until the canvas instance is deleted. + * + * The 'bounds' parameter defines an initial SVG viewport (viewBox attribute on the root + * SVG element). + */ + static std::unique_ptr Make(const SkRect& bounds, SkWStream*, uint32_t flags = 0); +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkCamera.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkCamera.h new file mode 100644 index 0000000000..536691875e --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkCamera.h @@ -0,0 +1,109 @@ +/* + * 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. + */ + +// Inspired by Rob Johnson's most excellent QuickDraw GX sample code + +#ifndef SkCamera_DEFINED +#define SkCamera_DEFINED + +#include "include/core/SkM44.h" +#include "include/core/SkMatrix.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkNoncopyable.h" + +// NOTE -- This entire header / impl is deprecated, and will be removed from Skia soon. +// +// Skia now has support for a 4x matrix (SkM44) in SkCanvas. +// + +class SkCanvas; + +// DEPRECATED +class SkPatch3D { +public: + SkPatch3D(); + + void reset(); + void transform(const SkM44&, SkPatch3D* dst = nullptr) const; + + // dot a unit vector with the patch's normal + SkScalar dotWith(SkScalar dx, SkScalar dy, SkScalar dz) const; + SkScalar dotWith(const SkV3& v) const { + return this->dotWith(v.x, v.y, v.z); + } + + // deprecated, but still here for animator (for now) + void rotate(SkScalar /*x*/, SkScalar /*y*/, SkScalar /*z*/) {} + void rotateDegrees(SkScalar /*x*/, SkScalar /*y*/, SkScalar /*z*/) {} + +private: +public: // make public for SkDraw3D for now + SkV3 fU, fV; + SkV3 fOrigin; + + friend class SkCamera3D; +}; + +// DEPRECATED +class SkCamera3D { +public: + SkCamera3D(); + + void reset(); + void update(); + void patchToMatrix(const SkPatch3D&, SkMatrix* matrix) const; + + SkV3 fLocation; // origin of the camera's space + SkV3 fAxis; // view direction + SkV3 fZenith; // up direction + SkV3 fObserver; // eye position (may not be the same as the origin) + +private: + mutable SkMatrix fOrientation; + mutable bool fNeedToUpdate; + + void doUpdate() const; +}; + +// DEPRECATED +class SK_API Sk3DView : SkNoncopyable { +public: + Sk3DView(); + ~Sk3DView(); + + void save(); + void restore(); + + void translate(SkScalar x, SkScalar y, SkScalar z); + void rotateX(SkScalar deg); + void rotateY(SkScalar deg); + void rotateZ(SkScalar deg); + +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + void setCameraLocation(SkScalar x, SkScalar y, SkScalar z); + SkScalar getCameraLocationX() const; + SkScalar getCameraLocationY() const; + SkScalar getCameraLocationZ() const; +#endif + + void getMatrix(SkMatrix*) const; + void applyToCanvas(SkCanvas*) const; + + SkScalar dotWithNormal(SkScalar dx, SkScalar dy, SkScalar dz) const; + +private: + struct Rec { + Rec* fNext; + SkM44 fMatrix; + }; + Rec* fRec; + Rec fInitialRec; + SkCamera3D fCamera; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkCanvasStateUtils.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkCanvasStateUtils.h new file mode 100644 index 0000000000..0172e37931 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkCanvasStateUtils.h @@ -0,0 +1,81 @@ +/* + * 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 SkCanvasStateUtils_DEFINED +#define SkCanvasStateUtils_DEFINED + +#include "include/core/SkTypes.h" + +#include + +class SkCanvas; +class SkCanvasState; + +/** + * A set of functions that are useful for copying the state of an SkCanvas + * across a library boundary where the Skia library on the other side of the + * boundary may be newer. The expected usage is outline below... + * + * Lib Boundary + * CaptureCanvasState(...) ||| + * SkCanvas --> SkCanvasState ||| + * ||| CreateFromCanvasState(...) + * ||| SkCanvasState --> SkCanvas` + * ||| Draw into SkCanvas` + * ||| Unref SkCanvas` + * ReleaseCanvasState(...) ||| + * + */ +class SK_API SkCanvasStateUtils { +public: + /** + * Captures the current state of the canvas into an opaque ptr that is safe + * to pass to a different instance of Skia (which may be the same version, + * or may be newer). The function will return NULL in the event that one of the + * following conditions are true. + * 1) the canvas device type is not supported (currently only raster is supported) + * 2) the canvas clip type is not supported (currently only non-AA clips are supported) + * + * It is recommended that the original canvas also not be used until all + * canvases that have been created using its captured state have been dereferenced. + * + * Finally, it is important to note that any draw filters attached to the + * canvas are NOT currently captured. + * + * @param canvas The canvas you wish to capture the current state of. + * @return NULL or an opaque ptr that can be passed to CreateFromCanvasState + * to reconstruct the canvas. The caller is responsible for calling + * ReleaseCanvasState to free the memory associated with this state. + */ + static SkCanvasState* CaptureCanvasState(SkCanvas* canvas); + + /** + * Create a new SkCanvas from the captured state of another SkCanvas. The + * function will return NULL in the event that one of the + * following conditions are true. + * 1) the captured state is in an unrecognized format + * 2) the captured canvas device type is not supported + * + * @param state Opaque object created by CaptureCanvasState. + * @return NULL or an SkCanvas* whose devices and matrix/clip state are + * identical to the captured canvas. The caller is responsible for + * calling unref on the SkCanvas. + */ + static std::unique_ptr MakeFromCanvasState(const SkCanvasState* state); + + /** + * Free the memory associated with the captured canvas state. The state + * should not be released until all SkCanvas objects created using that + * state have been dereferenced. Must be called from the same library + * instance that created the state via CaptureCanvasState. + * + * @param state The captured state you wish to dispose of. + */ + static void ReleaseCanvasState(SkCanvasState* state); +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkCustomTypeface.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkCustomTypeface.h new file mode 100644 index 0000000000..d387fb24ca --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkCustomTypeface.h @@ -0,0 +1,69 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkCustomTypeface_DEFINED +#define SkCustomTypeface_DEFINED + +#include "include/core/SkDrawable.h" +#include "include/core/SkFontMetrics.h" +#include "include/core/SkFontStyle.h" +#include "include/core/SkPath.h" +#include "include/core/SkRect.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypeface.h" +#include "include/core/SkTypes.h" + +#include +#include + +class SkStream; +class SkStreamAsset; +struct SkFontArguments; + +class SK_API SkCustomTypefaceBuilder { +public: + SkCustomTypefaceBuilder(); + + void setGlyph(SkGlyphID, float advance, const SkPath&); + void setGlyph(SkGlyphID, float advance, sk_sp, const SkRect& bounds); + + void setMetrics(const SkFontMetrics& fm, float scale = 1); + void setFontStyle(SkFontStyle); + + sk_sp detach(); + + static constexpr SkTypeface::FactoryId FactoryId = SkSetFourByteTag('u','s','e','r'); + static sk_sp MakeFromStream(std::unique_ptr, const SkFontArguments&); + +private: + struct GlyphRec { + // logical union + SkPath fPath; + sk_sp fDrawable; + + SkRect fBounds = {0,0,0,0}; // only used for drawable glyphs atm + float fAdvance = 0; + + bool isDrawable() const { + SkASSERT(!fDrawable || fPath.isEmpty()); + return fDrawable != nullptr; + } + }; + + std::vector fGlyphRecs; + SkFontMetrics fMetrics; + SkFontStyle fStyle; + + GlyphRec& ensureStorage(SkGlyphID); + + static sk_sp Deserialize(SkStream*); + + friend class SkTypeface; + friend class SkUserTypeface; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkEventTracer.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkEventTracer.h new file mode 100644 index 0000000000..2ec0a3b355 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkEventTracer.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2014 Google Inc. All rights reserved. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkEventTracer_DEFINED +#define SkEventTracer_DEFINED + +// The class in this header defines the interface between Skia's internal +// tracing macros and an external entity (e.g., Chrome) that will consume them. +// Such an entity should subclass SkEventTracer and provide an instance of +// that event to SkEventTracer::SetInstance. + +// If you're looking for the tracing macros to instrument Skia itself, those +// live in src/core/SkTraceEvent.h + +#include "include/core/SkTypes.h" + +#include + +class SK_API SkEventTracer { +public: + + typedef uint64_t Handle; + + /** + * If this is the first call to SetInstance or GetInstance then the passed instance is + * installed and true is returned. Otherwise, false is returned. In either case ownership of the + * tracer is transferred and it will be deleted when no longer needed. + * + * Not deleting the tracer on process exit should not cause problems as + * the whole heap is about to go away with the process. This can also + * improve performance by reducing the amount of work needed. + * + * @param leakTracer Do not delete tracer on process exit. + */ + static bool SetInstance(SkEventTracer*, bool leakTracer = false); + + /** + * Gets the event tracer. If this is the first call to SetInstance or GetIntance then a default + * event tracer is installed and returned. + */ + static SkEventTracer* GetInstance(); + + virtual ~SkEventTracer() = default; + + // The pointer returned from GetCategoryGroupEnabled() points to a + // value with zero or more of the following bits. Used in this class only. + // The TRACE_EVENT macros should only use the value as a bool. + // These values must be in sync with macro values in trace_event.h in chromium. + enum CategoryGroupEnabledFlags { + // Category group enabled for the recording mode. + kEnabledForRecording_CategoryGroupEnabledFlags = 1 << 0, + // Category group enabled for the monitoring mode. + kEnabledForMonitoring_CategoryGroupEnabledFlags = 1 << 1, + // Category group enabled by SetEventCallbackEnabled(). + kEnabledForEventCallback_CategoryGroupEnabledFlags = 1 << 2, + }; + + virtual const uint8_t* getCategoryGroupEnabled(const char* name) = 0; + virtual const char* getCategoryGroupName(const uint8_t* categoryEnabledFlag) = 0; + + virtual SkEventTracer::Handle + addTraceEvent(char phase, + const uint8_t* categoryEnabledFlag, + const char* name, + uint64_t id, + int32_t numArgs, + const char** argNames, + const uint8_t* argTypes, + const uint64_t* argValues, + uint8_t flags) = 0; + + virtual void + updateTraceEventDuration(const uint8_t* categoryEnabledFlag, + const char* name, + SkEventTracer::Handle handle) = 0; + + // Optional method that can be implemented to allow splitting up traces into different sections. + virtual void newTracingSection(const char*) {} + +protected: + SkEventTracer() = default; + SkEventTracer(const SkEventTracer&) = delete; + SkEventTracer& operator=(const SkEventTracer&) = delete; +}; + +#endif // SkEventTracer_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkNWayCanvas.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkNWayCanvas.h new file mode 100644 index 0000000000..0332a1432b --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkNWayCanvas.h @@ -0,0 +1,123 @@ + +/* + * 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 SkNWayCanvas_DEFINED +#define SkNWayCanvas_DEFINED + +#include "include/core/SkCanvasVirtualEnforcer.h" +#include "include/core/SkColor.h" +#include "include/core/SkM44.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkSamplingOptions.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkTDArray.h" +#include "include/utils/SkNoDrawCanvas.h" + +#include + +namespace sktext { +class GlyphRunList; +} + +class SkCanvas; +class SkData; +class SkDrawable; +class SkImage; +class SkMatrix; +class SkPaint; +class SkPath; +class SkPicture; +class SkRRect; +class SkRegion; +class SkShader; +class SkTextBlob; +class SkVertices; +enum class SkBlendMode; +enum class SkClipOp; +struct SkDrawShadowRec; +struct SkPoint; +struct SkRSXform; +struct SkRect; + +namespace sktext::gpu { class Slug; } + +class SK_API SkNWayCanvas : public SkCanvasVirtualEnforcer { +public: + SkNWayCanvas(int width, int height); + ~SkNWayCanvas() override; + + virtual void addCanvas(SkCanvas*); + virtual void removeCanvas(SkCanvas*); + virtual void removeAll(); + +protected: + SkTDArray fList; + + void willSave() override; + SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override; + bool onDoSaveBehind(const SkRect*) override; + void willRestore() override; + + void didConcat44(const SkM44&) override; + void didSetM44(const SkM44&) override; + void didScale(SkScalar, SkScalar) override; + void didTranslate(SkScalar, SkScalar) override; + + void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override; + void onDrawGlyphRunList(const sktext::GlyphRunList&, const SkPaint&) override; + void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, + const SkPaint& paint) override; + void onDrawSlug(const sktext::gpu::Slug* slug, const SkPaint& paint) override; + void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], + const SkPoint texCoords[4], SkBlendMode, const SkPaint& paint) override; + + void onDrawPaint(const SkPaint&) override; + void onDrawBehind(const SkPaint&) override; + void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) 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 onDrawRRect(const SkRRect&, 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 onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override; + void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override; + + void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override; + void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override; + void onClipPath(const SkPath&, SkClipOp, ClipEdgeStyle) override; + void onClipShader(sk_sp, SkClipOp) override; + void onClipRegion(const SkRegion&, SkClipOp) override; + void onResetClip() override; + + void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override; + void onDrawDrawable(SkDrawable*, const SkMatrix*) override; + void onDrawAnnotation(const SkRect&, const char[], SkData*) override; + + void onDrawEdgeAAQuad(const SkRect&, const SkPoint[4], QuadAAFlags, const SkColor4f&, + SkBlendMode) override; + void onDrawEdgeAAImageSet2(const ImageSetEntry[], int count, const SkPoint[], const SkMatrix[], + const SkSamplingOptions&,const SkPaint*, SrcRectConstraint) override; + class Iter; +private: + using INHERITED = SkCanvasVirtualEnforcer; +}; + + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkNoDrawCanvas.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkNoDrawCanvas.h new file mode 100644 index 0000000000..bcf43bec3c --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkNoDrawCanvas.h @@ -0,0 +1,78 @@ +/* + * 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 SkNoDrawCanvas_DEFINED +#define SkNoDrawCanvas_DEFINED + +#include "include/core/SkCanvas.h" +#include "include/core/SkCanvasVirtualEnforcer.h" + +struct SkIRect; + +// SkNoDrawCanvas is a helper for SkCanvas subclasses which do not need to +// actually rasterize (e.g., analysis of the draw calls). +// +// It provides the following simplifications: +// +// * not backed by any device/pixels +// * conservative clipping (clipping calls only use rectangles) +// +class SK_API SkNoDrawCanvas : public SkCanvasVirtualEnforcer { +public: + SkNoDrawCanvas(int width, int height); + SkNoDrawCanvas(const SkIRect&); + + // Optimization to reset state to be the same as after construction. + void resetCanvas(int w, int h) { this->resetForNextPicture(SkIRect::MakeWH(w, h)); } + void resetCanvas(const SkIRect& rect) { this->resetForNextPicture(rect); } + +protected: + SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override; + bool onDoSaveBehind(const SkRect*) override; + + // No-op overrides for aborting rasterization earlier than SkNullBlitter. + void onDrawAnnotation(const SkRect&, const char[], SkData*) override {} + void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override {} + void onDrawDrawable(SkDrawable*, const SkMatrix*) override {} + void onDrawTextBlob(const SkTextBlob*, SkScalar, SkScalar, const SkPaint&) 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&) override {} + void onDrawPoints(PointMode, size_t, const SkPoint[], const SkPaint&) 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 onDrawRRect(const SkRRect&, 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 onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override {} + void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override {} + void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override {} + + void onDrawEdgeAAQuad(const SkRect&, const SkPoint[4], QuadAAFlags, const SkColor4f&, + SkBlendMode) override {} + void onDrawEdgeAAImageSet2(const ImageSetEntry[], int, const SkPoint[], const SkMatrix[], + const SkSamplingOptions&, const SkPaint*, + SrcRectConstraint) override {} + +private: + using INHERITED = SkCanvasVirtualEnforcer; +}; + +#endif // SkNoDrawCanvas_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkNullCanvas.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkNullCanvas.h new file mode 100644 index 0000000000..a77e3e3de9 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkNullCanvas.h @@ -0,0 +1,22 @@ +/* + * 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 SkNullCanvas_DEFINED +#define SkNullCanvas_DEFINED + +#include "include/core/SkTypes.h" + +#include + +class SkCanvas; + +/** + * Creates a canvas that draws nothing. This is useful for performance testing. + */ +SK_API std::unique_ptr SkMakeNullCanvas(); + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkOrderedFontMgr.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkOrderedFontMgr.h new file mode 100644 index 0000000000..0b686e5edc --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkOrderedFontMgr.h @@ -0,0 +1,66 @@ +/* + * Copyright 2021 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkOrderedFontMgr_DEFINED +#define SkOrderedFontMgr_DEFINED + +#include "include/core/SkFontMgr.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypes.h" + +#include +#include + +class SkData; +class SkFontStyle; +class SkStreamAsset; +class SkString; +class SkTypeface; +struct SkFontArguments; + +/** + * Collects an order list of other font managers, and visits them in order + * when a request to find or match is issued. + * + * Note: this explicitly fails on any attempt to Make a typeface: all of + * those requests will return null. + */ +class SK_API SkOrderedFontMgr : public SkFontMgr { +public: + SkOrderedFontMgr(); + ~SkOrderedFontMgr() override; + + void append(sk_sp); + +protected: + int onCountFamilies() const override; + void onGetFamilyName(int index, SkString* familyName) const override; + sk_sp onCreateStyleSet(int index)const override; + + sk_sp onMatchFamily(const char familyName[]) const override; + + sk_sp onMatchFamilyStyle(const char familyName[], + const SkFontStyle&) const override; + sk_sp onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&, + const char* bcp47[], int bcp47Count, + SkUnichar character) const override; + + // Note: all of these always return null + sk_sp onMakeFromData(sk_sp, int ttcIndex) const override; + sk_sp onMakeFromStreamIndex(std::unique_ptr, + int ttcIndex) const override; + sk_sp onMakeFromStreamArgs(std::unique_ptr, + const SkFontArguments&) const override; + sk_sp onMakeFromFile(const char path[], int ttcIndex) const override; + + sk_sp onLegacyMakeTypeface(const char familyName[], SkFontStyle) const override; + +private: + std::vector> fList; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkPaintFilterCanvas.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkPaintFilterCanvas.h new file mode 100644 index 0000000000..ce86d2ea3a --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkPaintFilterCanvas.h @@ -0,0 +1,140 @@ +/* + * 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 SkPaintFilterCanvas_DEFINED +#define SkPaintFilterCanvas_DEFINED + +#include "include/core/SkCanvas.h" +#include "include/core/SkCanvasVirtualEnforcer.h" +#include "include/core/SkColor.h" +#include "include/core/SkImageInfo.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkSamplingOptions.h" +#include "include/core/SkScalar.h" +#include "include/core/SkSize.h" +#include "include/core/SkTypes.h" +#include "include/private/base/SkTDArray.h" +#include "include/utils/SkNWayCanvas.h" + +#include + +namespace sktext { +class GlyphRunList; +} + +class GrRecordingContext; +class SkData; +class SkDrawable; +class SkImage; +class SkMatrix; +class SkPaint; +class SkPath; +class SkPicture; +class SkPixmap; +class SkRRect; +class SkRegion; +class SkSurface; +class SkSurfaceProps; +class SkTextBlob; +class SkVertices; +enum class SkBlendMode; +struct SkDrawShadowRec; +struct SkPoint; +struct SkRSXform; +struct SkRect; + +/** \class SkPaintFilterCanvas + + A utility proxy base class for implementing draw/paint filters. +*/ +class SK_API SkPaintFilterCanvas : public SkCanvasVirtualEnforcer { +public: + /** + * The new SkPaintFilterCanvas is configured for forwarding to the + * specified canvas. Also copies the target canvas matrix and clip bounds. + */ + SkPaintFilterCanvas(SkCanvas* canvas); + + enum Type { + kPicture_Type, + }; + + // Forwarded to the wrapped canvas. + SkISize getBaseLayerSize() const override { return proxy()->getBaseLayerSize(); } + GrRecordingContext* recordingContext() const override { return proxy()->recordingContext(); } +protected: + /** + * Called with the paint that will be used to draw the specified type. + * The implementation may modify the paint as they wish. + * + * The result bool is used to determine whether the draw op is to be + * executed (true) or skipped (false). + * + * Note: The base implementation calls onFilter() for top-level/explicit paints only. + * To also filter encapsulated paints (e.g. SkPicture, SkTextBlob), clients may need to + * override the relevant methods (i.e. drawPicture, drawTextBlob). + */ + virtual bool onFilter(SkPaint& paint) const = 0; + + void onDrawPaint(const SkPaint&) override; + void onDrawBehind(const SkPaint&) override; + void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override; + void onDrawRect(const SkRect&, const SkPaint&) override; + void onDrawRRect(const SkRRect&, const SkPaint&) override; + void onDrawDRRect(const SkRRect&, const SkRRect&, 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 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 onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override; + void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], + const SkPoint texCoords[4], SkBlendMode, + const SkPaint& paint) override; + void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override; + void onDrawDrawable(SkDrawable*, const SkMatrix*) override; + + void onDrawGlyphRunList(const sktext::GlyphRunList&, const SkPaint&) override; + void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, + const SkPaint& paint) override; + void onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) override; + void onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) override; + + void onDrawEdgeAAQuad(const SkRect&, const SkPoint[4], QuadAAFlags, const SkColor4f&, + SkBlendMode) override; + void onDrawEdgeAAImageSet2(const ImageSetEntry[], int count, const SkPoint[], const SkMatrix[], + const SkSamplingOptions&,const SkPaint*, SrcRectConstraint) override; + + // Forwarded to the wrapped canvas. + sk_sp onNewSurface(const SkImageInfo&, const SkSurfaceProps&) override; + bool onPeekPixels(SkPixmap* pixmap) override; + bool onAccessTopLayerPixels(SkPixmap* pixmap) override; + SkImageInfo onImageInfo() const override; + bool onGetProps(SkSurfaceProps* props, bool top) const override; + +private: + class AutoPaintFilter; + + SkCanvas* proxy() const { SkASSERT(fList.size() == 1); return fList[0]; } + + SkPaintFilterCanvas* internal_private_asPaintFilterCanvas() const override { + return const_cast(this); + } + + friend class SkAndroidFrameworkUtils; +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkParse.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkParse.h new file mode 100644 index 0000000000..bcabc3c793 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkParse.h @@ -0,0 +1,37 @@ + +/* + * 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 SkParse_DEFINED +#define SkParse_DEFINED + +#include "include/core/SkColor.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" + +#include +#include + +class SK_API SkParse { +public: + static int Count(const char str[]); // number of scalars or int values + static int Count(const char str[], char separator); + static const char* FindColor(const char str[], SkColor* value); + static const char* FindHex(const char str[], uint32_t* value); + static const char* FindMSec(const char str[], SkMSec* value); + static const char* FindNamedColor(const char str[], size_t len, SkColor* color); + static const char* FindS32(const char str[], int32_t* value); + static const char* FindScalar(const char str[], SkScalar* value); + static const char* FindScalars(const char str[], SkScalar value[], int count); + + static bool FindBool(const char str[], bool* value); + // return the index of str in list[], or -1 if not found + static int FindList(const char str[], const char list[]); +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkParsePath.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkParsePath.h new file mode 100644 index 0000000000..acd0ef2305 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkParsePath.h @@ -0,0 +1,25 @@ + +/* + * 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 SkParsePath_DEFINED +#define SkParsePath_DEFINED + +#include "include/core/SkPath.h" + +class SkString; + +class SK_API SkParsePath { +public: + static bool FromSVGString(const char str[], SkPath*); + + enum class PathEncoding { Absolute, Relative }; + static SkString ToSVGString(const SkPath&, PathEncoding = PathEncoding::Absolute); +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkShadowUtils.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkShadowUtils.h new file mode 100644 index 0000000000..0f77b11096 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkShadowUtils.h @@ -0,0 +1,102 @@ + +/* + * 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 SkShadowUtils_DEFINED +#define SkShadowUtils_DEFINED + +#include "include/core/SkColor.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" + +#include + +class SkCanvas; +class SkMatrix; +class SkPath; +struct SkPoint3; +struct SkRect; + +enum SkShadowFlags { + kNone_ShadowFlag = 0x00, + /** The occluding object is not opaque. Knowing that the occluder is opaque allows + * us to cull shadow geometry behind it and improve performance. */ + kTransparentOccluder_ShadowFlag = 0x01, + /** Don't try to use analytic shadows. */ + kGeometricOnly_ShadowFlag = 0x02, + /** Light position represents a direction, light radius is blur radius at elevation 1 */ + kDirectionalLight_ShadowFlag = 0x04, + /** Concave paths will only use blur to generate the shadow */ + kConcaveBlurOnly_ShadowFlag = 0x08, + /** mask for all shadow flags */ + kAll_ShadowFlag = 0x0F +}; + +class SK_API SkShadowUtils { +public: + /** + * Draw an offset spot shadow and outlining ambient shadow for the given path using a disc + * light. The shadow may be cached, depending on the path type and canvas matrix. If the + * matrix is perspective or the path is volatile, it will not be cached. + * + * @param canvas The canvas on which to draw the shadows. + * @param path The occluder used to generate the shadows. + * @param zPlaneParams Values for the plane function which returns the Z offset of the + * occluder from the canvas based on local x and y values (the current matrix is not applied). + * @param lightPos Generally, the 3D position of the light relative to the canvas plane. + * If kDirectionalLight_ShadowFlag is set, this specifies a vector pointing + * towards the light. + * @param lightRadius Generally, the radius of the disc light. + * If DirectionalLight_ShadowFlag is set, this specifies the amount of + * blur when the occluder is at Z offset == 1. The blur will grow linearly + * as the Z value increases. + * @param ambientColor The color of the ambient shadow. + * @param spotColor The color of the spot shadow. + * @param flags Options controlling opaque occluder optimizations, shadow appearance, + * and light position. See SkShadowFlags. + */ + static void DrawShadow(SkCanvas* canvas, const SkPath& path, const SkPoint3& zPlaneParams, + const SkPoint3& lightPos, SkScalar lightRadius, + SkColor ambientColor, SkColor spotColor, + uint32_t flags = SkShadowFlags::kNone_ShadowFlag); + + /** + * Generate bounding box for shadows relative to path. Includes both the ambient and spot + * shadow bounds. + * + * @param ctm Current transformation matrix to device space. + * @param path The occluder used to generate the shadows. + * @param zPlaneParams Values for the plane function which returns the Z offset of the + * occluder from the canvas based on local x and y values (the current matrix is not applied). + * @param lightPos Generally, the 3D position of the light relative to the canvas plane. + * If kDirectionalLight_ShadowFlag is set, this specifies a vector pointing + * towards the light. + * @param lightRadius Generally, the radius of the disc light. + * If DirectionalLight_ShadowFlag is set, this specifies the amount of + * blur when the occluder is at Z offset == 1. The blur will grow linearly + * as the Z value increases. + * @param flags Options controlling opaque occluder optimizations, shadow appearance, + * and light position. See SkShadowFlags. + * @param bounds Return value for shadow bounding box. + * @return Returns true if successful, false otherwise. + */ + static bool GetLocalBounds(const SkMatrix& ctm, const SkPath& path, + const SkPoint3& zPlaneParams, const SkPoint3& lightPos, + SkScalar lightRadius, uint32_t flags, SkRect* bounds); + + /** + * Helper routine to compute color values for one-pass tonal alpha. + * + * @param inAmbientColor Original ambient color + * @param inSpotColor Original spot color + * @param outAmbientColor Modified ambient color + * @param outSpotColor Modified spot color + */ + static void ComputeTonalColors(SkColor inAmbientColor, SkColor inSpotColor, + SkColor* outAmbientColor, SkColor* outSpotColor); +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkTextUtils.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkTextUtils.h new file mode 100644 index 0000000000..06f83b934f --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkTextUtils.h @@ -0,0 +1,43 @@ +/* + * 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 SkTextUtils_DEFINED +#define SkTextUtils_DEFINED + +#include "include/core/SkFontTypes.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" + +#include +#include + +class SkCanvas; +class SkFont; +class SkPaint; +class SkPath; + +class SK_API SkTextUtils { +public: + enum Align { + kLeft_Align, + kCenter_Align, + kRight_Align, + }; + + static void Draw(SkCanvas*, const void* text, size_t size, SkTextEncoding, + SkScalar x, SkScalar y, const SkFont&, const SkPaint&, Align = kLeft_Align); + + static void DrawString(SkCanvas* canvas, const char text[], SkScalar x, SkScalar y, + const SkFont& font, const SkPaint& paint, Align align = kLeft_Align) { + Draw(canvas, text, strlen(text), SkTextEncoding::kUTF8, x, y, font, paint, align); + } + + static void GetPath(const void* text, size_t length, SkTextEncoding, SkScalar x, SkScalar y, + const SkFont&, SkPath*); +}; + +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkTraceEventPhase.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkTraceEventPhase.h new file mode 100644 index 0000000000..38457be24b --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/SkTraceEventPhase.h @@ -0,0 +1,19 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#ifndef SkTraceEventPhase_DEFINED +#define SkTraceEventPhase_DEFINED + +// Phase indicates the nature of an event entry. E.g. part of a begin/end pair. +#define TRACE_EVENT_PHASE_BEGIN ('B') +#define TRACE_EVENT_PHASE_END ('E') +#define TRACE_EVENT_PHASE_COMPLETE ('X') +#define TRACE_EVENT_PHASE_INSTANT ('I') +#define TRACE_EVENT_PHASE_ASYNC_BEGIN ('S') +#define TRACE_EVENT_PHASE_ASYNC_END ('F') +#define TRACE_EVENT_PHASE_COUNTER ('C') +#define TRACE_EVENT_PHASE_CREATE_OBJECT ('N') +#define TRACE_EVENT_PHASE_SNAPSHOT_OBJECT ('O') +#define TRACE_EVENT_PHASE_DELETE_OBJECT ('D') + +#endif // SkTraceEventPhase_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/mac/SkCGUtils.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/mac/SkCGUtils.h new file mode 100644 index 0000000000..73d89c174a --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/include/utils/mac/SkCGUtils.h @@ -0,0 +1,90 @@ + +/* + * 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 SkCGUtils_DEFINED +#define SkCGUtils_DEFINED + +#include "include/core/SkImage.h" +#include "include/core/SkImageInfo.h" +#include "include/core/SkPixmap.h" +#include "include/core/SkSize.h" + +#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) + +#ifdef SK_BUILD_FOR_MAC +#include +#endif + +#ifdef SK_BUILD_FOR_IOS +#include +#endif + +class SkBitmap; +class SkColorSpace; +class SkData; +class SkPixmap; +class SkStreamRewindable; + +SK_API CGContextRef SkCreateCGContext(const SkPixmap&); + +/** + * Given a CGImage, allocate an SkBitmap and copy the image's pixels into it. If scaleToFit is not + * null, use it to determine the size of the bitmap, and scale the image to fill the bitmap. + * Otherwise use the image's width/height. + * + * On failure, return false, and leave bitmap unchanged. + */ +SK_API bool SkCreateBitmapFromCGImage(SkBitmap* dst, CGImageRef src); + +SK_API sk_sp SkMakeImageFromCGImage(CGImageRef); + +/** + * Given a CGColorSpace, return the closest matching SkColorSpace. If no conversion is possible + * or if the input CGColorSpace is nullptr then return nullptr. + */ +SK_API sk_sp SkMakeColorSpaceFromCGColorSpace(CGColorSpaceRef); + +/** + * Copy the pixels from src into the memory specified by info/rowBytes/dstPixels. On failure, + * return false (e.g. ImageInfo incompatible with src). + */ +SK_API bool SkCopyPixelsFromCGImage(const SkImageInfo& info, size_t rowBytes, void* dstPixels, + CGImageRef src); +static inline bool SkCopyPixelsFromCGImage(const SkPixmap& dst, CGImageRef src) { + return SkCopyPixelsFromCGImage(dst.info(), dst.rowBytes(), dst.writable_addr(), src); +} + +/** + * Create an imageref from the specified bitmap. The color space parameter is ignored. + */ +SK_API CGImageRef SkCreateCGImageRefWithColorspace(const SkBitmap& bm, + CGColorSpaceRef space); + +/** + * Create an imageref from the specified bitmap. + */ +SK_API CGImageRef SkCreateCGImageRef(const SkBitmap& bm); + +/** + * Given an SkColorSpace, create a CGColorSpace. This will return sRGB if the specified + * SkColorSpace is nullptr or on failure. This will not retain the specified SkColorSpace. + */ +SK_API CGColorSpaceRef SkCreateCGColorSpace(const SkColorSpace*); + +/** + * Given an SkData, create a CGDataProviderRef that refers to the and retains the specified data. + */ +SK_API CGDataProviderRef SkCreateCGDataProvider(sk_sp); + +/** + * Draw the bitmap into the specified CG context. (x,y) specifies the position of the top-left + * corner of the bitmap. + */ +void SkCGDrawBitmap(CGContextRef, const SkBitmap&, float x, float y); + +#endif // defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) +#endif // SkCGUtils_DEFINED diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/BUILD.gn b/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/BUILD.gn new file mode 100644 index 0000000000..5d037a94c9 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/BUILD.gn @@ -0,0 +1,100 @@ +# Copyright 2022 Google LLC +# +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("skcms.gni") + +# Use for CPU-specific skcms transform code that needs particular compiler flags. +# (This is patterned after `opts` in Skia's BUILD.gn.) +template("arch") { + if (invoker.enabled) { + source_set(target_name) { + visibility = [ ":*" ] + check_includes = false + forward_variables_from(invoker, "*") + } + } else { + # If not enabled, a phony empty target that swallows all otherwise unused variables. + source_set(target_name) { + visibility = [ ":*" ] + check_includes = false + forward_variables_from(invoker, + "*", + [ + "sources", + "cflags", + "defines", + ]) + } + } +} + +arch("skcms_TransformHsw") { + enabled = current_cpu == "x64" && target_os != "android" + sources = skcms_TransformHsw + if (is_win) { + if (is_clang) { + cflags = [ + "/clang:-mavx2", + "/clang:-mf16c", + "/clang:-ffp-contract=off", + ] + } else { + cflags = [ "/arch:AVX2" ] + } + } else { + cflags = [ + "-mavx2", + "-mf16c", + "-std=c11", + ] + } +} + +arch("skcms_TransformSkx") { + enabled = current_cpu == "x64" && target_os != "android" + sources = skcms_TransformSkx + if (is_win) { + if (is_clang) { + cflags = [ + "/clang:-mavx512f", + "/clang:-mavx512dq", + "/clang:-mavx512cd", + "/clang:-mavx512bw", + "/clang:-mavx512vl", + "/clang:-ffp-contract=off", + ] + } else { + cflags = [ "/arch:AVX512" ] + } + } else { + cflags = [ + "-mavx512f", + "-mavx512dq", + "-mavx512cd", + "-mavx512bw", + "-mavx512vl", + "-std=c11", + ] + } +} + +static_library("skcms") { + cflags = [] + if (!is_win || is_clang) { + cflags += [ "-std=c11" ] + } + if (target_cpu != "x64" || target_os == "android") { + defines = [ + "SKCMS_DISABLE_HSW", + "SKCMS_DISABLE_SKX", + ] + } + public = skcms_public_headers + sources = skcms_public + skcms_TransformBaseline + deps = [ + ":skcms_TransformHsw", + ":skcms_TransformSkx", + ] +} diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/OWNERS b/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/OWNERS new file mode 100644 index 0000000000..cc36d27e3d --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/OWNERS @@ -0,0 +1,2 @@ +# The auto-roller directly checks in skcms, so give it ownership as well: +skia-autoroll@skia-public.iam.gserviceaccount.com diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/README.chromium b/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/README.chromium new file mode 100644 index 0000000000..15543c64fd --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/README.chromium @@ -0,0 +1,6 @@ +Name: skcms +URL: https://skia.org/ +Version: unknown +Security Critical: yes +Shipped: yes +License: BSD diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/skcms.cc b/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/skcms.cc new file mode 100644 index 0000000000..047f21bed1 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/skcms.cc @@ -0,0 +1,2889 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "src/skcms_public.h" // NO_G3_REWRITE +#include "src/skcms_internals.h" // NO_G3_REWRITE +#include "src/skcms_Transform.h" // NO_G3_REWRITE +#include +#include +#include +#include +#include + +#if defined(__ARM_NEON) + #include +#elif defined(__SSE__) + #include + + #if defined(__clang__) + // That #include is usually enough, but Clang's headers + // "helpfully" skip including the whole kitchen sink when _MSC_VER is + // defined, because lots of programs on Windows would include that and + // it'd be a lot slower. But we want all those headers included so we + // can use their features after runtime checks later. + #include + #include + #include + #include + #include + #endif +#endif + +using namespace skcms_private; + +static bool sAllowRuntimeCPUDetection = true; + +void skcms_DisableRuntimeCPUDetection() { + sAllowRuntimeCPUDetection = false; +} + +static float log2f_(float x) { + // The first approximation of log2(x) is its exponent 'e', minus 127. + int32_t bits; + memcpy(&bits, &x, sizeof(bits)); + + float e = (float)bits * (1.0f / (1<<23)); + + // If we use the mantissa too we can refine the error signficantly. + int32_t m_bits = (bits & 0x007fffff) | 0x3f000000; + float m; + memcpy(&m, &m_bits, sizeof(m)); + + return (e - 124.225514990f + - 1.498030302f*m + - 1.725879990f/(0.3520887068f + m)); +} +static float logf_(float x) { + const float ln2 = 0.69314718f; + return ln2*log2f_(x); +} + +static float exp2f_(float x) { + if (x > 128.0f) { + return INFINITY_; + } else if (x < -127.0f) { + return 0.0f; + } + float fract = x - floorf_(x); + + float fbits = (1.0f * (1<<23)) * (x + 121.274057500f + - 1.490129070f*fract + + 27.728023300f/(4.84252568f - fract)); + + // Before we cast fbits to int32_t, check for out of range values to pacify UBSAN. + // INT_MAX is not exactly representable as a float, so exclude it as effectively infinite. + // Negative values are effectively underflow - we'll end up returning a (different) negative + // value, which makes no sense. So clamp to zero. + if (fbits >= (float)INT_MAX) { + return INFINITY_; + } else if (fbits < 0) { + return 0; + } + + int32_t bits = (int32_t)fbits; + memcpy(&x, &bits, sizeof(x)); + return x; +} + +// Not static, as it's used by some test tools. +float powf_(float x, float y) { + if (x <= 0.f) { + return 0.f; + } + if (x == 1.f) { + return 1.f; + } + return exp2f_(log2f_(x) * y); +} + +static float expf_(float x) { + const float log2_e = 1.4426950408889634074f; + return exp2f_(log2_e * x); +} + +static float fmaxf_(float x, float y) { return x > y ? x : y; } +static float fminf_(float x, float y) { return x < y ? x : y; } + +static bool isfinitef_(float x) { return 0 == x*0; } + +static float minus_1_ulp(float x) { + int32_t bits; + memcpy(&bits, &x, sizeof(bits)); + bits = bits - 1; + memcpy(&x, &bits, sizeof(bits)); + return x; +} + +// Most transfer functions we work with are sRGBish. +// For exotic HDR transfer functions, we encode them using a tf.g that makes no sense, +// and repurpose the other fields to hold the parameters of the HDR functions. +struct TF_PQish { float A,B,C,D,E,F; }; +struct TF_HLGish { float R,G,a,b,c,K_minus_1; }; +// We didn't originally support a scale factor K for HLG, and instead just stored 0 in +// the unused `f` field of skcms_TransferFunction for HLGish and HLGInvish transfer functions. +// By storing f=K-1, those old unusued f=0 values now mean K=1, a noop scale factor. + +static float TFKind_marker(skcms_TFType kind) { + // We'd use different NaNs, but those aren't guaranteed to be preserved by WASM. + return -(float)kind; +} + +static skcms_TFType classify(const skcms_TransferFunction& tf, TF_PQish* pq = nullptr + , TF_HLGish* hlg = nullptr) { + if (tf.g < 0) { + // Negative "g" is mapped to enum values; large negative are for sure invalid. + if (tf.g < -128) { + return skcms_TFType_Invalid; + } + int enum_g = -static_cast(tf.g); + // Non-whole "g" values are invalid as well. + if (static_cast(-enum_g) != tf.g) { + return skcms_TFType_Invalid; + } + // TODO: soundness checks for PQ/HLG like we do for sRGBish? + switch (enum_g) { + case skcms_TFType_PQish: + if (pq) { + memcpy(pq , &tf.a, sizeof(*pq )); + } + return skcms_TFType_PQish; + case skcms_TFType_HLGish: + if (hlg) { + memcpy(hlg, &tf.a, sizeof(*hlg)); + } + return skcms_TFType_HLGish; + case skcms_TFType_HLGinvish: + if (hlg) { + memcpy(hlg, &tf.a, sizeof(*hlg)); + } + return skcms_TFType_HLGinvish; + } + return skcms_TFType_Invalid; + } + + // Basic soundness checks for sRGBish transfer functions. + if (isfinitef_(tf.a + tf.b + tf.c + tf.d + tf.e + tf.f + tf.g) + // a,c,d,g should be non-negative to make any sense. + && tf.a >= 0 + && tf.c >= 0 + && tf.d >= 0 + && tf.g >= 0 + // Raising a negative value to a fractional tf->g produces complex numbers. + && tf.a * tf.d + tf.b >= 0) { + return skcms_TFType_sRGBish; + } + + return skcms_TFType_Invalid; +} + +skcms_TFType skcms_TransferFunction_getType(const skcms_TransferFunction* tf) { + return classify(*tf); +} +bool skcms_TransferFunction_isSRGBish(const skcms_TransferFunction* tf) { + return classify(*tf) == skcms_TFType_sRGBish; +} +bool skcms_TransferFunction_isPQish(const skcms_TransferFunction* tf) { + return classify(*tf) == skcms_TFType_PQish; +} +bool skcms_TransferFunction_isHLGish(const skcms_TransferFunction* tf) { + return classify(*tf) == skcms_TFType_HLGish; +} + +bool skcms_TransferFunction_makePQish(skcms_TransferFunction* tf, + float A, float B, float C, + float D, float E, float F) { + *tf = { TFKind_marker(skcms_TFType_PQish), A,B,C,D,E,F }; + assert(skcms_TransferFunction_isPQish(tf)); + return true; +} + +bool skcms_TransferFunction_makeScaledHLGish(skcms_TransferFunction* tf, + float K, float R, float G, + float a, float b, float c) { + *tf = { TFKind_marker(skcms_TFType_HLGish), R,G, a,b,c, K-1.0f }; + assert(skcms_TransferFunction_isHLGish(tf)); + return true; +} + +float skcms_TransferFunction_eval(const skcms_TransferFunction* tf, float x) { + float sign = x < 0 ? -1.0f : 1.0f; + x *= sign; + + TF_PQish pq; + TF_HLGish hlg; + switch (classify(*tf, &pq, &hlg)) { + case skcms_TFType_Invalid: break; + + case skcms_TFType_HLGish: { + const float K = hlg.K_minus_1 + 1.0f; + return K * sign * (x*hlg.R <= 1 ? powf_(x*hlg.R, hlg.G) + : expf_((x-hlg.c)*hlg.a) + hlg.b); + } + + // skcms_TransferFunction_invert() inverts R, G, and a for HLGinvish so this math is fast. + case skcms_TFType_HLGinvish: { + const float K = hlg.K_minus_1 + 1.0f; + x /= K; + return sign * (x <= 1 ? hlg.R * powf_(x, hlg.G) + : hlg.a * logf_(x - hlg.b) + hlg.c); + } + + case skcms_TFType_sRGBish: + return sign * (x < tf->d ? tf->c * x + tf->f + : powf_(tf->a * x + tf->b, tf->g) + tf->e); + + case skcms_TFType_PQish: + return sign * + powf_((pq.A + pq.B * powf_(x, pq.C)) / (pq.D + pq.E * powf_(x, pq.C)), pq.F); + } + return 0; +} + + +static float eval_curve(const skcms_Curve* curve, float x) { + if (curve->table_entries == 0) { + return skcms_TransferFunction_eval(&curve->parametric, x); + } + + float ix = fmaxf_(0, fminf_(x, 1)) * static_cast(curve->table_entries - 1); + int lo = (int) ix , + hi = (int)(float)minus_1_ulp(ix + 1.0f); + float t = ix - (float)lo; + + float l, h; + if (curve->table_8) { + l = curve->table_8[lo] * (1/255.0f); + h = curve->table_8[hi] * (1/255.0f); + } else { + uint16_t be_l, be_h; + memcpy(&be_l, curve->table_16 + 2*lo, 2); + memcpy(&be_h, curve->table_16 + 2*hi, 2); + uint16_t le_l = ((be_l << 8) | (be_l >> 8)) & 0xffff; + uint16_t le_h = ((be_h << 8) | (be_h >> 8)) & 0xffff; + l = le_l * (1/65535.0f); + h = le_h * (1/65535.0f); + } + return l + (h-l)*t; +} + +float skcms_MaxRoundtripError(const skcms_Curve* curve, const skcms_TransferFunction* inv_tf) { + uint32_t N = curve->table_entries > 256 ? curve->table_entries : 256; + const float dx = 1.0f / static_cast(N - 1); + float err = 0; + for (uint32_t i = 0; i < N; i++) { + float x = static_cast(i) * dx, + y = eval_curve(curve, x); + err = fmaxf_(err, fabsf_(x - skcms_TransferFunction_eval(inv_tf, y))); + } + return err; +} + +bool skcms_AreApproximateInverses(const skcms_Curve* curve, const skcms_TransferFunction* inv_tf) { + return skcms_MaxRoundtripError(curve, inv_tf) < (1/512.0f); +} + +// Additional ICC signature values that are only used internally +enum { + // File signature + skcms_Signature_acsp = 0x61637370, + + // Tag signatures + skcms_Signature_rTRC = 0x72545243, + skcms_Signature_gTRC = 0x67545243, + skcms_Signature_bTRC = 0x62545243, + skcms_Signature_kTRC = 0x6B545243, + + skcms_Signature_rXYZ = 0x7258595A, + skcms_Signature_gXYZ = 0x6758595A, + skcms_Signature_bXYZ = 0x6258595A, + + skcms_Signature_A2B0 = 0x41324230, + skcms_Signature_B2A0 = 0x42324130, + + skcms_Signature_CHAD = 0x63686164, + skcms_Signature_WTPT = 0x77747074, + + skcms_Signature_CICP = 0x63696370, + + // Type signatures + skcms_Signature_curv = 0x63757276, + skcms_Signature_mft1 = 0x6D667431, + skcms_Signature_mft2 = 0x6D667432, + skcms_Signature_mAB = 0x6D414220, + skcms_Signature_mBA = 0x6D424120, + skcms_Signature_para = 0x70617261, + skcms_Signature_sf32 = 0x73663332, + // XYZ is also a PCS signature, so it's defined in skcms.h + // skcms_Signature_XYZ = 0x58595A20, +}; + +static uint16_t read_big_u16(const uint8_t* ptr) { + uint16_t be; + memcpy(&be, ptr, sizeof(be)); +#if defined(_MSC_VER) + return _byteswap_ushort(be); +#else + return __builtin_bswap16(be); +#endif +} + +static uint32_t read_big_u32(const uint8_t* ptr) { + uint32_t be; + memcpy(&be, ptr, sizeof(be)); +#if defined(_MSC_VER) + return _byteswap_ulong(be); +#else + return __builtin_bswap32(be); +#endif +} + +static int32_t read_big_i32(const uint8_t* ptr) { + return (int32_t)read_big_u32(ptr); +} + +static float read_big_fixed(const uint8_t* ptr) { + return static_cast(read_big_i32(ptr)) * (1.0f / 65536.0f); +} + +// Maps to an in-memory profile so that fields line up to the locations specified +// in ICC.1:2010, section 7.2 +typedef struct { + uint8_t size [ 4]; + uint8_t cmm_type [ 4]; + uint8_t version [ 4]; + uint8_t profile_class [ 4]; + uint8_t data_color_space [ 4]; + uint8_t pcs [ 4]; + uint8_t creation_date_time [12]; + uint8_t signature [ 4]; + uint8_t platform [ 4]; + uint8_t flags [ 4]; + uint8_t device_manufacturer [ 4]; + uint8_t device_model [ 4]; + uint8_t device_attributes [ 8]; + uint8_t rendering_intent [ 4]; + uint8_t illuminant_X [ 4]; + uint8_t illuminant_Y [ 4]; + uint8_t illuminant_Z [ 4]; + uint8_t creator [ 4]; + uint8_t profile_id [16]; + uint8_t reserved [28]; + uint8_t tag_count [ 4]; // Technically not part of header, but required +} header_Layout; + +typedef struct { + uint8_t signature [4]; + uint8_t offset [4]; + uint8_t size [4]; +} tag_Layout; + +static const tag_Layout* get_tag_table(const skcms_ICCProfile* profile) { + return (const tag_Layout*)(profile->buffer + SAFE_SIZEOF(header_Layout)); +} + +// s15Fixed16ArrayType is technically variable sized, holding N values. However, the only valid +// use of the type is for the CHAD tag that stores exactly nine values. +typedef struct { + uint8_t type [ 4]; + uint8_t reserved [ 4]; + uint8_t values [36]; +} sf32_Layout; + +bool skcms_GetCHAD(const skcms_ICCProfile* profile, skcms_Matrix3x3* m) { + skcms_ICCTag tag; + if (!skcms_GetTagBySignature(profile, skcms_Signature_CHAD, &tag)) { + return false; + } + + if (tag.type != skcms_Signature_sf32 || tag.size < SAFE_SIZEOF(sf32_Layout)) { + return false; + } + + const sf32_Layout* sf32Tag = (const sf32_Layout*)tag.buf; + const uint8_t* values = sf32Tag->values; + for (int r = 0; r < 3; ++r) + for (int c = 0; c < 3; ++c, values += 4) { + m->vals[r][c] = read_big_fixed(values); + } + return true; +} + +// XYZType is technically variable sized, holding N XYZ triples. However, the only valid uses of +// the type are for tags/data that store exactly one triple. +typedef struct { + uint8_t type [4]; + uint8_t reserved [4]; + uint8_t X [4]; + uint8_t Y [4]; + uint8_t Z [4]; +} XYZ_Layout; + +static bool read_tag_xyz(const skcms_ICCTag* tag, float* x, float* y, float* z) { + if (tag->type != skcms_Signature_XYZ || tag->size < SAFE_SIZEOF(XYZ_Layout)) { + return false; + } + + const XYZ_Layout* xyzTag = (const XYZ_Layout*)tag->buf; + + *x = read_big_fixed(xyzTag->X); + *y = read_big_fixed(xyzTag->Y); + *z = read_big_fixed(xyzTag->Z); + return true; +} + +bool skcms_GetWTPT(const skcms_ICCProfile* profile, float xyz[3]) { + skcms_ICCTag tag; + return skcms_GetTagBySignature(profile, skcms_Signature_WTPT, &tag) && + read_tag_xyz(&tag, &xyz[0], &xyz[1], &xyz[2]); +} + +static bool read_to_XYZD50(const skcms_ICCTag* rXYZ, const skcms_ICCTag* gXYZ, + const skcms_ICCTag* bXYZ, skcms_Matrix3x3* toXYZ) { + return read_tag_xyz(rXYZ, &toXYZ->vals[0][0], &toXYZ->vals[1][0], &toXYZ->vals[2][0]) && + read_tag_xyz(gXYZ, &toXYZ->vals[0][1], &toXYZ->vals[1][1], &toXYZ->vals[2][1]) && + read_tag_xyz(bXYZ, &toXYZ->vals[0][2], &toXYZ->vals[1][2], &toXYZ->vals[2][2]); +} + +typedef struct { + uint8_t type [4]; + uint8_t reserved_a [4]; + uint8_t function_type [2]; + uint8_t reserved_b [2]; + uint8_t variable [1/*variable*/]; // 1, 3, 4, 5, or 7 s15.16, depending on function_type +} para_Layout; + +static bool read_curve_para(const uint8_t* buf, uint32_t size, + skcms_Curve* curve, uint32_t* curve_size) { + if (size < SAFE_FIXED_SIZE(para_Layout)) { + return false; + } + + const para_Layout* paraTag = (const para_Layout*)buf; + + enum { kG = 0, kGAB = 1, kGABC = 2, kGABCD = 3, kGABCDEF = 4 }; + uint16_t function_type = read_big_u16(paraTag->function_type); + if (function_type > kGABCDEF) { + return false; + } + + static const uint32_t curve_bytes[] = { 4, 12, 16, 20, 28 }; + if (size < SAFE_FIXED_SIZE(para_Layout) + curve_bytes[function_type]) { + return false; + } + + if (curve_size) { + *curve_size = SAFE_FIXED_SIZE(para_Layout) + curve_bytes[function_type]; + } + + curve->table_entries = 0; + curve->parametric.a = 1.0f; + curve->parametric.b = 0.0f; + curve->parametric.c = 0.0f; + curve->parametric.d = 0.0f; + curve->parametric.e = 0.0f; + curve->parametric.f = 0.0f; + curve->parametric.g = read_big_fixed(paraTag->variable); + + switch (function_type) { + case kGAB: + curve->parametric.a = read_big_fixed(paraTag->variable + 4); + curve->parametric.b = read_big_fixed(paraTag->variable + 8); + if (curve->parametric.a == 0) { + return false; + } + curve->parametric.d = -curve->parametric.b / curve->parametric.a; + break; + case kGABC: + curve->parametric.a = read_big_fixed(paraTag->variable + 4); + curve->parametric.b = read_big_fixed(paraTag->variable + 8); + curve->parametric.e = read_big_fixed(paraTag->variable + 12); + if (curve->parametric.a == 0) { + return false; + } + curve->parametric.d = -curve->parametric.b / curve->parametric.a; + curve->parametric.f = curve->parametric.e; + break; + case kGABCD: + curve->parametric.a = read_big_fixed(paraTag->variable + 4); + curve->parametric.b = read_big_fixed(paraTag->variable + 8); + curve->parametric.c = read_big_fixed(paraTag->variable + 12); + curve->parametric.d = read_big_fixed(paraTag->variable + 16); + break; + case kGABCDEF: + curve->parametric.a = read_big_fixed(paraTag->variable + 4); + curve->parametric.b = read_big_fixed(paraTag->variable + 8); + curve->parametric.c = read_big_fixed(paraTag->variable + 12); + curve->parametric.d = read_big_fixed(paraTag->variable + 16); + curve->parametric.e = read_big_fixed(paraTag->variable + 20); + curve->parametric.f = read_big_fixed(paraTag->variable + 24); + break; + } + return skcms_TransferFunction_isSRGBish(&curve->parametric); +} + +typedef struct { + uint8_t type [4]; + uint8_t reserved [4]; + uint8_t value_count [4]; + uint8_t variable [1/*variable*/]; // value_count, 8.8 if 1, uint16 (n*65535) if > 1 +} curv_Layout; + +static bool read_curve_curv(const uint8_t* buf, uint32_t size, + skcms_Curve* curve, uint32_t* curve_size) { + if (size < SAFE_FIXED_SIZE(curv_Layout)) { + return false; + } + + const curv_Layout* curvTag = (const curv_Layout*)buf; + + uint32_t value_count = read_big_u32(curvTag->value_count); + if (size < SAFE_FIXED_SIZE(curv_Layout) + value_count * SAFE_SIZEOF(uint16_t)) { + return false; + } + + if (curve_size) { + *curve_size = SAFE_FIXED_SIZE(curv_Layout) + value_count * SAFE_SIZEOF(uint16_t); + } + + if (value_count < 2) { + curve->table_entries = 0; + curve->parametric.a = 1.0f; + curve->parametric.b = 0.0f; + curve->parametric.c = 0.0f; + curve->parametric.d = 0.0f; + curve->parametric.e = 0.0f; + curve->parametric.f = 0.0f; + if (value_count == 0) { + // Empty tables are a shorthand for an identity curve + curve->parametric.g = 1.0f; + } else { + // Single entry tables are a shorthand for simple gamma + curve->parametric.g = read_big_u16(curvTag->variable) * (1.0f / 256.0f); + } + } else { + curve->table_8 = nullptr; + curve->table_16 = curvTag->variable; + curve->table_entries = value_count; + } + + return true; +} + +// Parses both curveType and parametricCurveType data. Ensures that at most 'size' bytes are read. +// If curve_size is not nullptr, writes the number of bytes used by the curve in (*curve_size). +static bool read_curve(const uint8_t* buf, uint32_t size, + skcms_Curve* curve, uint32_t* curve_size) { + if (!buf || size < 4 || !curve) { + return false; + } + + uint32_t type = read_big_u32(buf); + if (type == skcms_Signature_para) { + return read_curve_para(buf, size, curve, curve_size); + } else if (type == skcms_Signature_curv) { + return read_curve_curv(buf, size, curve, curve_size); + } + + return false; +} + +// mft1 and mft2 share a large chunk of data +typedef struct { + uint8_t type [ 4]; + uint8_t reserved_a [ 4]; + uint8_t input_channels [ 1]; + uint8_t output_channels [ 1]; + uint8_t grid_points [ 1]; + uint8_t reserved_b [ 1]; + uint8_t matrix [36]; +} mft_CommonLayout; + +typedef struct { + mft_CommonLayout common [1]; + + uint8_t variable [1/*variable*/]; +} mft1_Layout; + +typedef struct { + mft_CommonLayout common [1]; + + uint8_t input_table_entries [2]; + uint8_t output_table_entries [2]; + uint8_t variable [1/*variable*/]; +} mft2_Layout; + +static bool read_mft_common(const mft_CommonLayout* mftTag, skcms_A2B* a2b) { + // MFT matrices are applied before the first set of curves, but must be identity unless the + // input is PCSXYZ. We don't support PCSXYZ profiles, so we ignore this matrix. Note that the + // matrix in skcms_A2B is applied later in the pipe, so supporting this would require another + // field/flag. + a2b->matrix_channels = 0; + a2b-> input_channels = mftTag-> input_channels[0]; + a2b->output_channels = mftTag->output_channels[0]; + + // We require exactly three (ie XYZ/Lab/RGB) output channels + if (a2b->output_channels != ARRAY_COUNT(a2b->output_curves)) { + return false; + } + // We require at least one, and no more than four (ie CMYK) input channels + if (a2b->input_channels < 1 || a2b->input_channels > ARRAY_COUNT(a2b->input_curves)) { + return false; + } + + for (uint32_t i = 0; i < a2b->input_channels; ++i) { + a2b->grid_points[i] = mftTag->grid_points[0]; + } + // The grid only makes sense with at least two points along each axis + if (a2b->grid_points[0] < 2) { + return false; + } + return true; +} + +// All as the A2B version above, except where noted. +static bool read_mft_common(const mft_CommonLayout* mftTag, skcms_B2A* b2a) { + // Same as A2B. + b2a->matrix_channels = 0; + b2a-> input_channels = mftTag-> input_channels[0]; + b2a->output_channels = mftTag->output_channels[0]; + + + // For B2A, exactly 3 input channels (XYZ) and 3 (RGB) or 4 (CMYK) output channels. + if (b2a->input_channels != ARRAY_COUNT(b2a->input_curves)) { + return false; + } + if (b2a->output_channels < 3 || b2a->output_channels > ARRAY_COUNT(b2a->output_curves)) { + return false; + } + + // Same as A2B. + for (uint32_t i = 0; i < b2a->input_channels; ++i) { + b2a->grid_points[i] = mftTag->grid_points[0]; + } + if (b2a->grid_points[0] < 2) { + return false; + } + return true; +} + +template +static bool init_tables(const uint8_t* table_base, uint64_t max_tables_len, uint32_t byte_width, + uint32_t input_table_entries, uint32_t output_table_entries, + A2B_or_B2A* out) { + // byte_width is 1 or 2, [input|output]_table_entries are in [2, 4096], so no overflow + uint32_t byte_len_per_input_table = input_table_entries * byte_width; + uint32_t byte_len_per_output_table = output_table_entries * byte_width; + + // [input|output]_channels are <= 4, so still no overflow + uint32_t byte_len_all_input_tables = out->input_channels * byte_len_per_input_table; + uint32_t byte_len_all_output_tables = out->output_channels * byte_len_per_output_table; + + uint64_t grid_size = out->output_channels * byte_width; + for (uint32_t axis = 0; axis < out->input_channels; ++axis) { + grid_size *= out->grid_points[axis]; + } + + if (max_tables_len < byte_len_all_input_tables + grid_size + byte_len_all_output_tables) { + return false; + } + + for (uint32_t i = 0; i < out->input_channels; ++i) { + out->input_curves[i].table_entries = input_table_entries; + if (byte_width == 1) { + out->input_curves[i].table_8 = table_base + i * byte_len_per_input_table; + out->input_curves[i].table_16 = nullptr; + } else { + out->input_curves[i].table_8 = nullptr; + out->input_curves[i].table_16 = table_base + i * byte_len_per_input_table; + } + } + + if (byte_width == 1) { + out->grid_8 = table_base + byte_len_all_input_tables; + out->grid_16 = nullptr; + } else { + out->grid_8 = nullptr; + out->grid_16 = table_base + byte_len_all_input_tables; + } + + const uint8_t* output_table_base = table_base + byte_len_all_input_tables + grid_size; + for (uint32_t i = 0; i < out->output_channels; ++i) { + out->output_curves[i].table_entries = output_table_entries; + if (byte_width == 1) { + out->output_curves[i].table_8 = output_table_base + i * byte_len_per_output_table; + out->output_curves[i].table_16 = nullptr; + } else { + out->output_curves[i].table_8 = nullptr; + out->output_curves[i].table_16 = output_table_base + i * byte_len_per_output_table; + } + } + + return true; +} + +template +static bool read_tag_mft1(const skcms_ICCTag* tag, A2B_or_B2A* out) { + if (tag->size < SAFE_FIXED_SIZE(mft1_Layout)) { + return false; + } + + const mft1_Layout* mftTag = (const mft1_Layout*)tag->buf; + if (!read_mft_common(mftTag->common, out)) { + return false; + } + + uint32_t input_table_entries = 256; + uint32_t output_table_entries = 256; + + return init_tables(mftTag->variable, tag->size - SAFE_FIXED_SIZE(mft1_Layout), 1, + input_table_entries, output_table_entries, out); +} + +template +static bool read_tag_mft2(const skcms_ICCTag* tag, A2B_or_B2A* out) { + if (tag->size < SAFE_FIXED_SIZE(mft2_Layout)) { + return false; + } + + const mft2_Layout* mftTag = (const mft2_Layout*)tag->buf; + if (!read_mft_common(mftTag->common, out)) { + return false; + } + + uint32_t input_table_entries = read_big_u16(mftTag->input_table_entries); + uint32_t output_table_entries = read_big_u16(mftTag->output_table_entries); + + // ICC spec mandates that 2 <= table_entries <= 4096 + if (input_table_entries < 2 || input_table_entries > 4096 || + output_table_entries < 2 || output_table_entries > 4096) { + return false; + } + + return init_tables(mftTag->variable, tag->size - SAFE_FIXED_SIZE(mft2_Layout), 2, + input_table_entries, output_table_entries, out); +} + +static bool read_curves(const uint8_t* buf, uint32_t size, uint32_t curve_offset, + uint32_t num_curves, skcms_Curve* curves) { + for (uint32_t i = 0; i < num_curves; ++i) { + if (curve_offset > size) { + return false; + } + + uint32_t curve_bytes; + if (!read_curve(buf + curve_offset, size - curve_offset, &curves[i], &curve_bytes)) { + return false; + } + + if (curve_bytes > UINT32_MAX - 3) { + return false; + } + curve_bytes = (curve_bytes + 3) & ~3U; + + uint64_t new_offset_64 = (uint64_t)curve_offset + curve_bytes; + curve_offset = (uint32_t)new_offset_64; + if (new_offset_64 != curve_offset) { + return false; + } + } + + return true; +} + +// mAB and mBA tags use the same encoding, including color lookup tables. +typedef struct { + uint8_t type [ 4]; + uint8_t reserved_a [ 4]; + uint8_t input_channels [ 1]; + uint8_t output_channels [ 1]; + uint8_t reserved_b [ 2]; + uint8_t b_curve_offset [ 4]; + uint8_t matrix_offset [ 4]; + uint8_t m_curve_offset [ 4]; + uint8_t clut_offset [ 4]; + uint8_t a_curve_offset [ 4]; +} mAB_or_mBA_Layout; + +typedef struct { + uint8_t grid_points [16]; + uint8_t grid_byte_width [ 1]; + uint8_t reserved [ 3]; + uint8_t variable [1/*variable*/]; +} CLUT_Layout; + +static bool read_tag_mab(const skcms_ICCTag* tag, skcms_A2B* a2b, bool pcs_is_xyz) { + if (tag->size < SAFE_SIZEOF(mAB_or_mBA_Layout)) { + return false; + } + + const mAB_or_mBA_Layout* mABTag = (const mAB_or_mBA_Layout*)tag->buf; + + a2b->input_channels = mABTag->input_channels[0]; + a2b->output_channels = mABTag->output_channels[0]; + + // We require exactly three (ie XYZ/Lab/RGB) output channels + if (a2b->output_channels != ARRAY_COUNT(a2b->output_curves)) { + return false; + } + // We require no more than four (ie CMYK) input channels + if (a2b->input_channels > ARRAY_COUNT(a2b->input_curves)) { + return false; + } + + uint32_t b_curve_offset = read_big_u32(mABTag->b_curve_offset); + uint32_t matrix_offset = read_big_u32(mABTag->matrix_offset); + uint32_t m_curve_offset = read_big_u32(mABTag->m_curve_offset); + uint32_t clut_offset = read_big_u32(mABTag->clut_offset); + uint32_t a_curve_offset = read_big_u32(mABTag->a_curve_offset); + + // "B" curves must be present + if (0 == b_curve_offset) { + return false; + } + + if (!read_curves(tag->buf, tag->size, b_curve_offset, a2b->output_channels, + a2b->output_curves)) { + return false; + } + + // "M" curves and Matrix must be used together + if (0 != m_curve_offset) { + if (0 == matrix_offset) { + return false; + } + a2b->matrix_channels = a2b->output_channels; + if (!read_curves(tag->buf, tag->size, m_curve_offset, a2b->matrix_channels, + a2b->matrix_curves)) { + return false; + } + + // Read matrix, which is stored as a row-major 3x3, followed by the fourth column + if (tag->size < matrix_offset + 12 * SAFE_SIZEOF(uint32_t)) { + return false; + } + float encoding_factor = pcs_is_xyz ? (65535 / 32768.0f) : 1.0f; + const uint8_t* mtx_buf = tag->buf + matrix_offset; + a2b->matrix.vals[0][0] = encoding_factor * read_big_fixed(mtx_buf + 0); + a2b->matrix.vals[0][1] = encoding_factor * read_big_fixed(mtx_buf + 4); + a2b->matrix.vals[0][2] = encoding_factor * read_big_fixed(mtx_buf + 8); + a2b->matrix.vals[1][0] = encoding_factor * read_big_fixed(mtx_buf + 12); + a2b->matrix.vals[1][1] = encoding_factor * read_big_fixed(mtx_buf + 16); + a2b->matrix.vals[1][2] = encoding_factor * read_big_fixed(mtx_buf + 20); + a2b->matrix.vals[2][0] = encoding_factor * read_big_fixed(mtx_buf + 24); + a2b->matrix.vals[2][1] = encoding_factor * read_big_fixed(mtx_buf + 28); + a2b->matrix.vals[2][2] = encoding_factor * read_big_fixed(mtx_buf + 32); + a2b->matrix.vals[0][3] = encoding_factor * read_big_fixed(mtx_buf + 36); + a2b->matrix.vals[1][3] = encoding_factor * read_big_fixed(mtx_buf + 40); + a2b->matrix.vals[2][3] = encoding_factor * read_big_fixed(mtx_buf + 44); + } else { + if (0 != matrix_offset) { + return false; + } + a2b->matrix_channels = 0; + } + + // "A" curves and CLUT must be used together + if (0 != a_curve_offset) { + if (0 == clut_offset) { + return false; + } + if (!read_curves(tag->buf, tag->size, a_curve_offset, a2b->input_channels, + a2b->input_curves)) { + return false; + } + + if (tag->size < clut_offset + SAFE_FIXED_SIZE(CLUT_Layout)) { + return false; + } + const CLUT_Layout* clut = (const CLUT_Layout*)(tag->buf + clut_offset); + + if (clut->grid_byte_width[0] == 1) { + a2b->grid_8 = clut->variable; + a2b->grid_16 = nullptr; + } else if (clut->grid_byte_width[0] == 2) { + a2b->grid_8 = nullptr; + a2b->grid_16 = clut->variable; + } else { + return false; + } + + uint64_t grid_size = a2b->output_channels * clut->grid_byte_width[0]; // the payload + for (uint32_t i = 0; i < a2b->input_channels; ++i) { + a2b->grid_points[i] = clut->grid_points[i]; + // The grid only makes sense with at least two points along each axis + if (a2b->grid_points[i] < 2) { + return false; + } + grid_size *= a2b->grid_points[i]; + } + if (tag->size < clut_offset + SAFE_FIXED_SIZE(CLUT_Layout) + grid_size) { + return false; + } + } else { + if (0 != clut_offset) { + return false; + } + + // If there is no CLUT, the number of input and output channels must match + if (a2b->input_channels != a2b->output_channels) { + return false; + } + + // Zero out the number of input channels to signal that we're skipping this stage + a2b->input_channels = 0; + } + + return true; +} + +// Exactly the same as read_tag_mab(), except where there are comments. +// TODO: refactor the two to eliminate common code? +static bool read_tag_mba(const skcms_ICCTag* tag, skcms_B2A* b2a, bool pcs_is_xyz) { + if (tag->size < SAFE_SIZEOF(mAB_or_mBA_Layout)) { + return false; + } + + const mAB_or_mBA_Layout* mBATag = (const mAB_or_mBA_Layout*)tag->buf; + + b2a->input_channels = mBATag->input_channels[0]; + b2a->output_channels = mBATag->output_channels[0]; + + // Require exactly 3 inputs (XYZ) and 3 (RGB) or 4 (CMYK) outputs. + if (b2a->input_channels != ARRAY_COUNT(b2a->input_curves)) { + return false; + } + if (b2a->output_channels < 3 || b2a->output_channels > ARRAY_COUNT(b2a->output_curves)) { + return false; + } + + uint32_t b_curve_offset = read_big_u32(mBATag->b_curve_offset); + uint32_t matrix_offset = read_big_u32(mBATag->matrix_offset); + uint32_t m_curve_offset = read_big_u32(mBATag->m_curve_offset); + uint32_t clut_offset = read_big_u32(mBATag->clut_offset); + uint32_t a_curve_offset = read_big_u32(mBATag->a_curve_offset); + + if (0 == b_curve_offset) { + return false; + } + + // "B" curves are our inputs, not outputs. + if (!read_curves(tag->buf, tag->size, b_curve_offset, b2a->input_channels, + b2a->input_curves)) { + return false; + } + + if (0 != m_curve_offset) { + if (0 == matrix_offset) { + return false; + } + // Matrix channels is tied to input_channels (3), not output_channels. + b2a->matrix_channels = b2a->input_channels; + + if (!read_curves(tag->buf, tag->size, m_curve_offset, b2a->matrix_channels, + b2a->matrix_curves)) { + return false; + } + + if (tag->size < matrix_offset + 12 * SAFE_SIZEOF(uint32_t)) { + return false; + } + float encoding_factor = pcs_is_xyz ? (32768 / 65535.0f) : 1.0f; // TODO: understand + const uint8_t* mtx_buf = tag->buf + matrix_offset; + b2a->matrix.vals[0][0] = encoding_factor * read_big_fixed(mtx_buf + 0); + b2a->matrix.vals[0][1] = encoding_factor * read_big_fixed(mtx_buf + 4); + b2a->matrix.vals[0][2] = encoding_factor * read_big_fixed(mtx_buf + 8); + b2a->matrix.vals[1][0] = encoding_factor * read_big_fixed(mtx_buf + 12); + b2a->matrix.vals[1][1] = encoding_factor * read_big_fixed(mtx_buf + 16); + b2a->matrix.vals[1][2] = encoding_factor * read_big_fixed(mtx_buf + 20); + b2a->matrix.vals[2][0] = encoding_factor * read_big_fixed(mtx_buf + 24); + b2a->matrix.vals[2][1] = encoding_factor * read_big_fixed(mtx_buf + 28); + b2a->matrix.vals[2][2] = encoding_factor * read_big_fixed(mtx_buf + 32); + b2a->matrix.vals[0][3] = encoding_factor * read_big_fixed(mtx_buf + 36); + b2a->matrix.vals[1][3] = encoding_factor * read_big_fixed(mtx_buf + 40); + b2a->matrix.vals[2][3] = encoding_factor * read_big_fixed(mtx_buf + 44); + } else { + if (0 != matrix_offset) { + return false; + } + b2a->matrix_channels = 0; + } + + if (0 != a_curve_offset) { + if (0 == clut_offset) { + return false; + } + + // "A" curves are our output, not input. + if (!read_curves(tag->buf, tag->size, a_curve_offset, b2a->output_channels, + b2a->output_curves)) { + return false; + } + + if (tag->size < clut_offset + SAFE_FIXED_SIZE(CLUT_Layout)) { + return false; + } + const CLUT_Layout* clut = (const CLUT_Layout*)(tag->buf + clut_offset); + + if (clut->grid_byte_width[0] == 1) { + b2a->grid_8 = clut->variable; + b2a->grid_16 = nullptr; + } else if (clut->grid_byte_width[0] == 2) { + b2a->grid_8 = nullptr; + b2a->grid_16 = clut->variable; + } else { + return false; + } + + uint64_t grid_size = b2a->output_channels * clut->grid_byte_width[0]; + for (uint32_t i = 0; i < b2a->input_channels; ++i) { + b2a->grid_points[i] = clut->grid_points[i]; + if (b2a->grid_points[i] < 2) { + return false; + } + grid_size *= b2a->grid_points[i]; + } + if (tag->size < clut_offset + SAFE_FIXED_SIZE(CLUT_Layout) + grid_size) { + return false; + } + } else { + if (0 != clut_offset) { + return false; + } + + if (b2a->input_channels != b2a->output_channels) { + return false; + } + + // Zero out *output* channels to skip this stage. + b2a->output_channels = 0; + } + return true; +} + +// If you pass f, we'll fit a possibly-non-zero value for *f. +// If you pass nullptr, we'll assume you want *f to be treated as zero. +static int fit_linear(const skcms_Curve* curve, int N, float tol, + float* c, float* d, float* f = nullptr) { + assert(N > 1); + // We iteratively fit the first points to the TF's linear piece. + // We want the cx + f line to pass through the first and last points we fit exactly. + // + // As we walk along the points we find the minimum and maximum slope of the line before the + // error would exceed our tolerance. We stop when the range [slope_min, slope_max] becomes + // emtpy, when we definitely can't add any more points. + // + // Some points' error intervals may intersect the running interval but not lie fully + // within it. So we keep track of the last point we saw that is a valid end point candidate, + // and once the search is done, back up to build the line through *that* point. + const float dx = 1.0f / static_cast(N - 1); + + int lin_points = 1; + + float f_zero = 0.0f; + if (f) { + *f = eval_curve(curve, 0); + } else { + f = &f_zero; + } + + + float slope_min = -INFINITY_; + float slope_max = +INFINITY_; + for (int i = 1; i < N; ++i) { + float x = static_cast(i) * dx; + float y = eval_curve(curve, x); + + float slope_max_i = (y + tol - *f) / x, + slope_min_i = (y - tol - *f) / x; + if (slope_max_i < slope_min || slope_max < slope_min_i) { + // Slope intervals would no longer overlap. + break; + } + slope_max = fminf_(slope_max, slope_max_i); + slope_min = fmaxf_(slope_min, slope_min_i); + + float cur_slope = (y - *f) / x; + if (slope_min <= cur_slope && cur_slope <= slope_max) { + lin_points = i + 1; + *c = cur_slope; + } + } + + // Set D to the last point that met our tolerance. + *d = static_cast(lin_points - 1) * dx; + return lin_points; +} + +// If this skcms_Curve holds an identity table, rewrite it as an identity skcms_TransferFunction. +static void canonicalize_identity(skcms_Curve* curve) { + if (curve->table_entries && curve->table_entries <= (uint32_t)INT_MAX) { + int N = (int)curve->table_entries; + + float c = 0.0f, d = 0.0f, f = 0.0f; + if (N == fit_linear(curve, N, 1.0f/static_cast(2*N), &c,&d,&f) + && c == 1.0f + && f == 0.0f) { + curve->table_entries = 0; + curve->table_8 = nullptr; + curve->table_16 = nullptr; + curve->parametric = skcms_TransferFunction{1,1,0,0,0,0,0}; + } + } +} + +static bool read_a2b(const skcms_ICCTag* tag, skcms_A2B* a2b, bool pcs_is_xyz) { + bool ok = false; + if (tag->type == skcms_Signature_mft1) { ok = read_tag_mft1(tag, a2b); } + if (tag->type == skcms_Signature_mft2) { ok = read_tag_mft2(tag, a2b); } + if (tag->type == skcms_Signature_mAB ) { ok = read_tag_mab(tag, a2b, pcs_is_xyz); } + if (!ok) { + return false; + } + + if (a2b->input_channels > 0) { canonicalize_identity(a2b->input_curves + 0); } + if (a2b->input_channels > 1) { canonicalize_identity(a2b->input_curves + 1); } + if (a2b->input_channels > 2) { canonicalize_identity(a2b->input_curves + 2); } + if (a2b->input_channels > 3) { canonicalize_identity(a2b->input_curves + 3); } + + if (a2b->matrix_channels > 0) { canonicalize_identity(a2b->matrix_curves + 0); } + if (a2b->matrix_channels > 1) { canonicalize_identity(a2b->matrix_curves + 1); } + if (a2b->matrix_channels > 2) { canonicalize_identity(a2b->matrix_curves + 2); } + + if (a2b->output_channels > 0) { canonicalize_identity(a2b->output_curves + 0); } + if (a2b->output_channels > 1) { canonicalize_identity(a2b->output_curves + 1); } + if (a2b->output_channels > 2) { canonicalize_identity(a2b->output_curves + 2); } + + return true; +} + +static bool read_b2a(const skcms_ICCTag* tag, skcms_B2A* b2a, bool pcs_is_xyz) { + bool ok = false; + if (tag->type == skcms_Signature_mft1) { ok = read_tag_mft1(tag, b2a); } + if (tag->type == skcms_Signature_mft2) { ok = read_tag_mft2(tag, b2a); } + if (tag->type == skcms_Signature_mBA ) { ok = read_tag_mba(tag, b2a, pcs_is_xyz); } + if (!ok) { + return false; + } + + if (b2a->input_channels > 0) { canonicalize_identity(b2a->input_curves + 0); } + if (b2a->input_channels > 1) { canonicalize_identity(b2a->input_curves + 1); } + if (b2a->input_channels > 2) { canonicalize_identity(b2a->input_curves + 2); } + + if (b2a->matrix_channels > 0) { canonicalize_identity(b2a->matrix_curves + 0); } + if (b2a->matrix_channels > 1) { canonicalize_identity(b2a->matrix_curves + 1); } + if (b2a->matrix_channels > 2) { canonicalize_identity(b2a->matrix_curves + 2); } + + if (b2a->output_channels > 0) { canonicalize_identity(b2a->output_curves + 0); } + if (b2a->output_channels > 1) { canonicalize_identity(b2a->output_curves + 1); } + if (b2a->output_channels > 2) { canonicalize_identity(b2a->output_curves + 2); } + if (b2a->output_channels > 3) { canonicalize_identity(b2a->output_curves + 3); } + + return true; +} + +typedef struct { + uint8_t type [4]; + uint8_t reserved [4]; + uint8_t color_primaries [1]; + uint8_t transfer_characteristics [1]; + uint8_t matrix_coefficients [1]; + uint8_t video_full_range_flag [1]; +} CICP_Layout; + +static bool read_cicp(const skcms_ICCTag* tag, skcms_CICP* cicp) { + if (tag->type != skcms_Signature_CICP || tag->size < SAFE_SIZEOF(CICP_Layout)) { + return false; + } + + const CICP_Layout* cicpTag = (const CICP_Layout*)tag->buf; + + cicp->color_primaries = cicpTag->color_primaries[0]; + cicp->transfer_characteristics = cicpTag->transfer_characteristics[0]; + cicp->matrix_coefficients = cicpTag->matrix_coefficients[0]; + cicp->video_full_range_flag = cicpTag->video_full_range_flag[0]; + return true; +} + +void skcms_GetTagByIndex(const skcms_ICCProfile* profile, uint32_t idx, skcms_ICCTag* tag) { + if (!profile || !profile->buffer || !tag) { return; } + if (idx > profile->tag_count) { return; } + const tag_Layout* tags = get_tag_table(profile); + tag->signature = read_big_u32(tags[idx].signature); + tag->size = read_big_u32(tags[idx].size); + tag->buf = read_big_u32(tags[idx].offset) + profile->buffer; + tag->type = read_big_u32(tag->buf); +} + +bool skcms_GetTagBySignature(const skcms_ICCProfile* profile, uint32_t sig, skcms_ICCTag* tag) { + if (!profile || !profile->buffer || !tag) { return false; } + const tag_Layout* tags = get_tag_table(profile); + for (uint32_t i = 0; i < profile->tag_count; ++i) { + if (read_big_u32(tags[i].signature) == sig) { + tag->signature = sig; + tag->size = read_big_u32(tags[i].size); + tag->buf = read_big_u32(tags[i].offset) + profile->buffer; + tag->type = read_big_u32(tag->buf); + return true; + } + } + return false; +} + +static bool usable_as_src(const skcms_ICCProfile* profile) { + return profile->has_A2B + || (profile->has_trc && profile->has_toXYZD50); +} + +bool skcms_ParseWithA2BPriority(const void* buf, size_t len, + const int priority[], const int priorities, + skcms_ICCProfile* profile) { + static_assert(SAFE_SIZEOF(header_Layout) == 132, "need to update header code"); + + if (!profile) { + return false; + } + memset(profile, 0, SAFE_SIZEOF(*profile)); + + if (len < SAFE_SIZEOF(header_Layout)) { + return false; + } + + // Byte-swap all header fields + const header_Layout* header = (const header_Layout*)buf; + profile->buffer = (const uint8_t*)buf; + profile->size = read_big_u32(header->size); + uint32_t version = read_big_u32(header->version); + profile->data_color_space = read_big_u32(header->data_color_space); + profile->pcs = read_big_u32(header->pcs); + uint32_t signature = read_big_u32(header->signature); + float illuminant_X = read_big_fixed(header->illuminant_X); + float illuminant_Y = read_big_fixed(header->illuminant_Y); + float illuminant_Z = read_big_fixed(header->illuminant_Z); + profile->tag_count = read_big_u32(header->tag_count); + + // Validate signature, size (smaller than buffer, large enough to hold tag table), + // and major version + uint64_t tag_table_size = profile->tag_count * SAFE_SIZEOF(tag_Layout); + if (signature != skcms_Signature_acsp || + profile->size > len || + profile->size < SAFE_SIZEOF(header_Layout) + tag_table_size || + (version >> 24) > 4) { + return false; + } + + // Validate that illuminant is D50 white + if (fabsf_(illuminant_X - 0.9642f) > 0.0100f || + fabsf_(illuminant_Y - 1.0000f) > 0.0100f || + fabsf_(illuminant_Z - 0.8249f) > 0.0100f) { + return false; + } + + // Validate that all tag entries have sane offset + size + const tag_Layout* tags = get_tag_table(profile); + for (uint32_t i = 0; i < profile->tag_count; ++i) { + uint32_t tag_offset = read_big_u32(tags[i].offset); + uint32_t tag_size = read_big_u32(tags[i].size); + uint64_t tag_end = (uint64_t)tag_offset + (uint64_t)tag_size; + if (tag_size < 4 || tag_end > profile->size) { + return false; + } + } + + if (profile->pcs != skcms_Signature_XYZ && profile->pcs != skcms_Signature_Lab) { + return false; + } + + bool pcs_is_xyz = profile->pcs == skcms_Signature_XYZ; + + // Pre-parse commonly used tags. + skcms_ICCTag kTRC; + if (profile->data_color_space == skcms_Signature_Gray && + skcms_GetTagBySignature(profile, skcms_Signature_kTRC, &kTRC)) { + if (!read_curve(kTRC.buf, kTRC.size, &profile->trc[0], nullptr)) { + // Malformed tag + return false; + } + profile->trc[1] = profile->trc[0]; + profile->trc[2] = profile->trc[0]; + profile->has_trc = true; + + if (pcs_is_xyz) { + profile->toXYZD50.vals[0][0] = illuminant_X; + profile->toXYZD50.vals[1][1] = illuminant_Y; + profile->toXYZD50.vals[2][2] = illuminant_Z; + profile->has_toXYZD50 = true; + } + } else { + skcms_ICCTag rTRC, gTRC, bTRC; + if (skcms_GetTagBySignature(profile, skcms_Signature_rTRC, &rTRC) && + skcms_GetTagBySignature(profile, skcms_Signature_gTRC, &gTRC) && + skcms_GetTagBySignature(profile, skcms_Signature_bTRC, &bTRC)) { + if (!read_curve(rTRC.buf, rTRC.size, &profile->trc[0], nullptr) || + !read_curve(gTRC.buf, gTRC.size, &profile->trc[1], nullptr) || + !read_curve(bTRC.buf, bTRC.size, &profile->trc[2], nullptr)) { + // Malformed TRC tags + return false; + } + profile->has_trc = true; + } + + skcms_ICCTag rXYZ, gXYZ, bXYZ; + if (skcms_GetTagBySignature(profile, skcms_Signature_rXYZ, &rXYZ) && + skcms_GetTagBySignature(profile, skcms_Signature_gXYZ, &gXYZ) && + skcms_GetTagBySignature(profile, skcms_Signature_bXYZ, &bXYZ)) { + if (!read_to_XYZD50(&rXYZ, &gXYZ, &bXYZ, &profile->toXYZD50)) { + // Malformed XYZ tags + return false; + } + profile->has_toXYZD50 = true; + } + } + + for (int i = 0; i < priorities; i++) { + // enum { perceptual, relative_colormetric, saturation } + if (priority[i] < 0 || priority[i] > 2) { + return false; + } + uint32_t sig = skcms_Signature_A2B0 + static_cast(priority[i]); + skcms_ICCTag tag; + if (skcms_GetTagBySignature(profile, sig, &tag)) { + if (!read_a2b(&tag, &profile->A2B, pcs_is_xyz)) { + // Malformed A2B tag + return false; + } + profile->has_A2B = true; + break; + } + } + + for (int i = 0; i < priorities; i++) { + // enum { perceptual, relative_colormetric, saturation } + if (priority[i] < 0 || priority[i] > 2) { + return false; + } + uint32_t sig = skcms_Signature_B2A0 + static_cast(priority[i]); + skcms_ICCTag tag; + if (skcms_GetTagBySignature(profile, sig, &tag)) { + if (!read_b2a(&tag, &profile->B2A, pcs_is_xyz)) { + // Malformed B2A tag + return false; + } + profile->has_B2A = true; + break; + } + } + + skcms_ICCTag cicp_tag; + if (skcms_GetTagBySignature(profile, skcms_Signature_CICP, &cicp_tag)) { + if (!read_cicp(&cicp_tag, &profile->CICP)) { + // Malformed CICP tag + return false; + } + profile->has_CICP = true; + } + + return usable_as_src(profile); +} + + +const skcms_ICCProfile* skcms_sRGB_profile() { + static const skcms_ICCProfile sRGB_profile = { + nullptr, // buffer, moot here + + 0, // size, moot here + skcms_Signature_RGB, // data_color_space + skcms_Signature_XYZ, // pcs + 0, // tag count, moot here + + // We choose to represent sRGB with its canonical transfer function, + // and with its canonical XYZD50 gamut matrix. + true, // has_trc, followed by the 3 trc curves + { + {{0, {2.4f, (float)(1/1.055), (float)(0.055/1.055), (float)(1/12.92), 0.04045f, 0, 0}}}, + {{0, {2.4f, (float)(1/1.055), (float)(0.055/1.055), (float)(1/12.92), 0.04045f, 0, 0}}}, + {{0, {2.4f, (float)(1/1.055), (float)(0.055/1.055), (float)(1/12.92), 0.04045f, 0, 0}}}, + }, + + true, // has_toXYZD50, followed by 3x3 toXYZD50 matrix + {{ + { 0.436065674f, 0.385147095f, 0.143066406f }, + { 0.222488403f, 0.716873169f, 0.060607910f }, + { 0.013916016f, 0.097076416f, 0.714096069f }, + }}, + + false, // has_A2B, followed by A2B itself, which we don't care about. + { + 0, + { + {{0, {0,0, 0,0,0,0,0}}}, + {{0, {0,0, 0,0,0,0,0}}}, + {{0, {0,0, 0,0,0,0,0}}}, + {{0, {0,0, 0,0,0,0,0}}}, + }, + {0,0,0,0}, + nullptr, + nullptr, + + 0, + { + {{0, {0,0, 0,0,0,0,0}}}, + {{0, {0,0, 0,0,0,0,0}}}, + {{0, {0,0, 0,0,0,0,0}}}, + }, + {{ + { 0,0,0,0 }, + { 0,0,0,0 }, + { 0,0,0,0 }, + }}, + + 0, + { + {{0, {0,0, 0,0,0,0,0}}}, + {{0, {0,0, 0,0,0,0,0}}}, + {{0, {0,0, 0,0,0,0,0}}}, + }, + }, + + false, // has_B2A, followed by B2A itself, which we also don't care about. + { + 0, + { + {{0, {0,0, 0,0,0,0,0}}}, + {{0, {0,0, 0,0,0,0,0}}}, + {{0, {0,0, 0,0,0,0,0}}}, + }, + + 0, + {{ + { 0,0,0,0 }, + { 0,0,0,0 }, + { 0,0,0,0 }, + }}, + { + {{0, {0,0, 0,0,0,0,0}}}, + {{0, {0,0, 0,0,0,0,0}}}, + {{0, {0,0, 0,0,0,0,0}}}, + }, + + 0, + {0,0,0,0}, + nullptr, + nullptr, + { + {{0, {0,0, 0,0,0,0,0}}}, + {{0, {0,0, 0,0,0,0,0}}}, + {{0, {0,0, 0,0,0,0,0}}}, + {{0, {0,0, 0,0,0,0,0}}}, + }, + }, + + false, // has_CICP, followed by cicp itself which we don't care about. + { 0, 0, 0, 0 }, + }; + return &sRGB_profile; +} + +const skcms_ICCProfile* skcms_XYZD50_profile() { + // Just like sRGB above, but with identity transfer functions and toXYZD50 matrix. + static const skcms_ICCProfile XYZD50_profile = { + nullptr, // buffer, moot here + + 0, // size, moot here + skcms_Signature_RGB, // data_color_space + skcms_Signature_XYZ, // pcs + 0, // tag count, moot here + + true, // has_trc, followed by the 3 trc curves + { + {{0, {1,1, 0,0,0,0,0}}}, + {{0, {1,1, 0,0,0,0,0}}}, + {{0, {1,1, 0,0,0,0,0}}}, + }, + + true, // has_toXYZD50, followed by 3x3 toXYZD50 matrix + {{ + { 1,0,0 }, + { 0,1,0 }, + { 0,0,1 }, + }}, + + false, // has_A2B, followed by A2B itself, which we don't care about. + { + 0, + { + {{0, {0,0, 0,0,0,0,0}}}, + {{0, {0,0, 0,0,0,0,0}}}, + {{0, {0,0, 0,0,0,0,0}}}, + {{0, {0,0, 0,0,0,0,0}}}, + }, + {0,0,0,0}, + nullptr, + nullptr, + + 0, + { + {{0, {0,0, 0,0,0,0,0}}}, + {{0, {0,0, 0,0,0,0,0}}}, + {{0, {0,0, 0,0,0,0,0}}}, + }, + {{ + { 0,0,0,0 }, + { 0,0,0,0 }, + { 0,0,0,0 }, + }}, + + 0, + { + {{0, {0,0, 0,0,0,0,0}}}, + {{0, {0,0, 0,0,0,0,0}}}, + {{0, {0,0, 0,0,0,0,0}}}, + }, + }, + + false, // has_B2A, followed by B2A itself, which we also don't care about. + { + 0, + { + {{0, {0,0, 0,0,0,0,0}}}, + {{0, {0,0, 0,0,0,0,0}}}, + {{0, {0,0, 0,0,0,0,0}}}, + }, + + 0, + {{ + { 0,0,0,0 }, + { 0,0,0,0 }, + { 0,0,0,0 }, + }}, + { + {{0, {0,0, 0,0,0,0,0}}}, + {{0, {0,0, 0,0,0,0,0}}}, + {{0, {0,0, 0,0,0,0,0}}}, + }, + + 0, + {0,0,0,0}, + nullptr, + nullptr, + { + {{0, {0,0, 0,0,0,0,0}}}, + {{0, {0,0, 0,0,0,0,0}}}, + {{0, {0,0, 0,0,0,0,0}}}, + {{0, {0,0, 0,0,0,0,0}}}, + }, + }, + + false, // has_CICP, followed by cicp itself which we don't care about. + { 0, 0, 0, 0 }, + }; + + return &XYZD50_profile; +} + +const skcms_TransferFunction* skcms_sRGB_TransferFunction() { + return &skcms_sRGB_profile()->trc[0].parametric; +} + +const skcms_TransferFunction* skcms_sRGB_Inverse_TransferFunction() { + static const skcms_TransferFunction sRGB_inv = + {0.416666657f, 1.137283325f, -0.0f, 12.920000076f, 0.003130805f, -0.054969788f, -0.0f}; + return &sRGB_inv; +} + +const skcms_TransferFunction* skcms_Identity_TransferFunction() { + static const skcms_TransferFunction identity = {1,1,0,0,0,0,0}; + return &identity; +} + +const uint8_t skcms_252_random_bytes[] = { + 8, 179, 128, 204, 253, 38, 134, 184, 68, 102, 32, 138, 99, 39, 169, 215, + 119, 26, 3, 223, 95, 239, 52, 132, 114, 74, 81, 234, 97, 116, 244, 205, 30, + 154, 173, 12, 51, 159, 122, 153, 61, 226, 236, 178, 229, 55, 181, 220, 191, + 194, 160, 126, 168, 82, 131, 18, 180, 245, 163, 22, 246, 69, 235, 252, 57, + 108, 14, 6, 152, 240, 255, 171, 242, 20, 227, 177, 238, 96, 85, 16, 211, + 70, 200, 149, 155, 146, 127, 145, 100, 151, 109, 19, 165, 208, 195, 164, + 137, 254, 182, 248, 64, 201, 45, 209, 5, 147, 207, 210, 113, 162, 83, 225, + 9, 31, 15, 231, 115, 37, 58, 53, 24, 49, 197, 56, 120, 172, 48, 21, 214, + 129, 111, 11, 50, 187, 196, 34, 60, 103, 71, 144, 47, 203, 77, 80, 232, + 140, 222, 250, 206, 166, 247, 139, 249, 221, 72, 106, 27, 199, 117, 54, + 219, 135, 118, 40, 79, 41, 251, 46, 93, 212, 92, 233, 148, 28, 121, 63, + 123, 158, 105, 59, 29, 42, 143, 23, 0, 107, 176, 87, 104, 183, 156, 193, + 189, 90, 188, 65, 190, 17, 198, 7, 186, 161, 1, 124, 78, 125, 170, 133, + 174, 218, 67, 157, 75, 101, 89, 217, 62, 33, 141, 228, 25, 35, 91, 230, 4, + 2, 13, 73, 86, 167, 237, 84, 243, 44, 185, 66, 130, 110, 150, 142, 216, 88, + 112, 36, 224, 136, 202, 76, 94, 98, 175, 213 +}; + +bool skcms_ApproximatelyEqualProfiles(const skcms_ICCProfile* A, const skcms_ICCProfile* B) { + // Test for exactly equal profiles first. + if (A == B || 0 == memcmp(A,B, sizeof(skcms_ICCProfile))) { + return true; + } + + // For now this is the essentially the same strategy we use in test_only.c + // for our skcms_Transform() smoke tests: + // 1) transform A to XYZD50 + // 2) transform B to XYZD50 + // 3) return true if they're similar enough + // Our current criterion in 3) is maximum 1 bit error per XYZD50 byte. + + // skcms_252_random_bytes are 252 of a random shuffle of all possible bytes. + // 252 is evenly divisible by 3 and 4. Only 192, 10, 241, and 43 are missing. + + // We want to allow otherwise equivalent profiles tagged as grayscale and RGB + // to be treated as equal. But CMYK profiles are a totally different ballgame. + const auto CMYK = skcms_Signature_CMYK; + if ((A->data_color_space == CMYK) != (B->data_color_space == CMYK)) { + return false; + } + + // Interpret as RGB_888 if data color space is RGB or GRAY, RGBA_8888 if CMYK. + // TODO: working with RGBA_8888 either way is probably fastest. + skcms_PixelFormat fmt = skcms_PixelFormat_RGB_888; + size_t npixels = 84; + if (A->data_color_space == skcms_Signature_CMYK) { + fmt = skcms_PixelFormat_RGBA_8888; + npixels = 63; + } + + // TODO: if A or B is a known profile (skcms_sRGB_profile, skcms_XYZD50_profile), + // use pre-canned results and skip that skcms_Transform() call? + uint8_t dstA[252], + dstB[252]; + if (!skcms_Transform( + skcms_252_random_bytes, fmt, skcms_AlphaFormat_Unpremul, A, + dstA, skcms_PixelFormat_RGB_888, skcms_AlphaFormat_Unpremul, skcms_XYZD50_profile(), + npixels)) { + return false; + } + if (!skcms_Transform( + skcms_252_random_bytes, fmt, skcms_AlphaFormat_Unpremul, B, + dstB, skcms_PixelFormat_RGB_888, skcms_AlphaFormat_Unpremul, skcms_XYZD50_profile(), + npixels)) { + return false; + } + + // TODO: make sure this final check has reasonable codegen. + for (size_t i = 0; i < 252; i++) { + if (abs((int)dstA[i] - (int)dstB[i]) > 1) { + return false; + } + } + return true; +} + +bool skcms_TRCs_AreApproximateInverse(const skcms_ICCProfile* profile, + const skcms_TransferFunction* inv_tf) { + if (!profile || !profile->has_trc) { + return false; + } + + return skcms_AreApproximateInverses(&profile->trc[0], inv_tf) && + skcms_AreApproximateInverses(&profile->trc[1], inv_tf) && + skcms_AreApproximateInverses(&profile->trc[2], inv_tf); +} + +static bool is_zero_to_one(float x) { + return 0 <= x && x <= 1; +} + +typedef struct { float vals[3]; } skcms_Vector3; + +static skcms_Vector3 mv_mul(const skcms_Matrix3x3* m, const skcms_Vector3* v) { + skcms_Vector3 dst = {{0,0,0}}; + for (int row = 0; row < 3; ++row) { + dst.vals[row] = m->vals[row][0] * v->vals[0] + + m->vals[row][1] * v->vals[1] + + m->vals[row][2] * v->vals[2]; + } + return dst; +} + +bool skcms_AdaptToXYZD50(float wx, float wy, + skcms_Matrix3x3* toXYZD50) { + if (!is_zero_to_one(wx) || !is_zero_to_one(wy) || + !toXYZD50) { + return false; + } + + // Assumes that Y is 1.0f. + skcms_Vector3 wXYZ = { { wx / wy, 1, (1 - wx - wy) / wy } }; + + // Now convert toXYZ matrix to toXYZD50. + skcms_Vector3 wXYZD50 = { { 0.96422f, 1.0f, 0.82521f } }; + + // Calculate the chromatic adaptation matrix. We will use the Bradford method, thus + // the matrices below. The Bradford method is used by Adobe and is widely considered + // to be the best. + skcms_Matrix3x3 xyz_to_lms = {{ + { 0.8951f, 0.2664f, -0.1614f }, + { -0.7502f, 1.7135f, 0.0367f }, + { 0.0389f, -0.0685f, 1.0296f }, + }}; + skcms_Matrix3x3 lms_to_xyz = {{ + { 0.9869929f, -0.1470543f, 0.1599627f }, + { 0.4323053f, 0.5183603f, 0.0492912f }, + { -0.0085287f, 0.0400428f, 0.9684867f }, + }}; + + skcms_Vector3 srcCone = mv_mul(&xyz_to_lms, &wXYZ); + skcms_Vector3 dstCone = mv_mul(&xyz_to_lms, &wXYZD50); + + *toXYZD50 = {{ + { dstCone.vals[0] / srcCone.vals[0], 0, 0 }, + { 0, dstCone.vals[1] / srcCone.vals[1], 0 }, + { 0, 0, dstCone.vals[2] / srcCone.vals[2] }, + }}; + *toXYZD50 = skcms_Matrix3x3_concat(toXYZD50, &xyz_to_lms); + *toXYZD50 = skcms_Matrix3x3_concat(&lms_to_xyz, toXYZD50); + + return true; +} + +bool skcms_PrimariesToXYZD50(float rx, float ry, + float gx, float gy, + float bx, float by, + float wx, float wy, + skcms_Matrix3x3* toXYZD50) { + if (!is_zero_to_one(rx) || !is_zero_to_one(ry) || + !is_zero_to_one(gx) || !is_zero_to_one(gy) || + !is_zero_to_one(bx) || !is_zero_to_one(by) || + !is_zero_to_one(wx) || !is_zero_to_one(wy) || + !toXYZD50) { + return false; + } + + // First, we need to convert xy values (primaries) to XYZ. + skcms_Matrix3x3 primaries = {{ + { rx, gx, bx }, + { ry, gy, by }, + { 1 - rx - ry, 1 - gx - gy, 1 - bx - by }, + }}; + skcms_Matrix3x3 primaries_inv; + if (!skcms_Matrix3x3_invert(&primaries, &primaries_inv)) { + return false; + } + + // Assumes that Y is 1.0f. + skcms_Vector3 wXYZ = { { wx / wy, 1, (1 - wx - wy) / wy } }; + skcms_Vector3 XYZ = mv_mul(&primaries_inv, &wXYZ); + + skcms_Matrix3x3 toXYZ = {{ + { XYZ.vals[0], 0, 0 }, + { 0, XYZ.vals[1], 0 }, + { 0, 0, XYZ.vals[2] }, + }}; + toXYZ = skcms_Matrix3x3_concat(&primaries, &toXYZ); + + skcms_Matrix3x3 DXtoD50; + if (!skcms_AdaptToXYZD50(wx, wy, &DXtoD50)) { + return false; + } + + *toXYZD50 = skcms_Matrix3x3_concat(&DXtoD50, &toXYZ); + return true; +} + + +bool skcms_Matrix3x3_invert(const skcms_Matrix3x3* src, skcms_Matrix3x3* dst) { + double a00 = src->vals[0][0], + a01 = src->vals[1][0], + a02 = src->vals[2][0], + a10 = src->vals[0][1], + a11 = src->vals[1][1], + a12 = src->vals[2][1], + a20 = src->vals[0][2], + a21 = src->vals[1][2], + a22 = src->vals[2][2]; + + double b0 = a00*a11 - a01*a10, + b1 = a00*a12 - a02*a10, + b2 = a01*a12 - a02*a11, + b3 = a20, + b4 = a21, + b5 = a22; + + double determinant = b0*b5 + - b1*b4 + + b2*b3; + + if (determinant == 0) { + return false; + } + + double invdet = 1.0 / determinant; + if (invdet > +FLT_MAX || invdet < -FLT_MAX || !isfinitef_((float)invdet)) { + return false; + } + + b0 *= invdet; + b1 *= invdet; + b2 *= invdet; + b3 *= invdet; + b4 *= invdet; + b5 *= invdet; + + dst->vals[0][0] = (float)( a11*b5 - a12*b4 ); + dst->vals[1][0] = (float)( a02*b4 - a01*b5 ); + dst->vals[2][0] = (float)( + b2 ); + dst->vals[0][1] = (float)( a12*b3 - a10*b5 ); + dst->vals[1][1] = (float)( a00*b5 - a02*b3 ); + dst->vals[2][1] = (float)( - b1 ); + dst->vals[0][2] = (float)( a10*b4 - a11*b3 ); + dst->vals[1][2] = (float)( a01*b3 - a00*b4 ); + dst->vals[2][2] = (float)( + b0 ); + + for (int r = 0; r < 3; ++r) + for (int c = 0; c < 3; ++c) { + if (!isfinitef_(dst->vals[r][c])) { + return false; + } + } + return true; +} + +skcms_Matrix3x3 skcms_Matrix3x3_concat(const skcms_Matrix3x3* A, const skcms_Matrix3x3* B) { + skcms_Matrix3x3 m = { { { 0,0,0 },{ 0,0,0 },{ 0,0,0 } } }; + for (int r = 0; r < 3; r++) + for (int c = 0; c < 3; c++) { + m.vals[r][c] = A->vals[r][0] * B->vals[0][c] + + A->vals[r][1] * B->vals[1][c] + + A->vals[r][2] * B->vals[2][c]; + } + return m; +} + +#if defined(__clang__) + [[clang::no_sanitize("float-divide-by-zero")]] // Checked for by classify() on the way out. +#endif +bool skcms_TransferFunction_invert(const skcms_TransferFunction* src, skcms_TransferFunction* dst) { + TF_PQish pq; + TF_HLGish hlg; + switch (classify(*src, &pq, &hlg)) { + case skcms_TFType_Invalid: return false; + case skcms_TFType_sRGBish: break; // handled below + + case skcms_TFType_PQish: + *dst = { TFKind_marker(skcms_TFType_PQish), -pq.A, pq.D, 1.0f/pq.F + , pq.B, -pq.E, 1.0f/pq.C}; + return true; + + case skcms_TFType_HLGish: + *dst = { TFKind_marker(skcms_TFType_HLGinvish), 1.0f/hlg.R, 1.0f/hlg.G + , 1.0f/hlg.a, hlg.b, hlg.c + , hlg.K_minus_1 }; + return true; + + case skcms_TFType_HLGinvish: + *dst = { TFKind_marker(skcms_TFType_HLGish), 1.0f/hlg.R, 1.0f/hlg.G + , 1.0f/hlg.a, hlg.b, hlg.c + , hlg.K_minus_1 }; + return true; + } + + assert (classify(*src) == skcms_TFType_sRGBish); + + // We're inverting this function, solving for x in terms of y. + // y = (cx + f) x < d + // (ax + b)^g + e x ≥ d + // The inverse of this function can be expressed in the same piecewise form. + skcms_TransferFunction inv = {0,0,0,0,0,0,0}; + + // We'll start by finding the new threshold inv.d. + // In principle we should be able to find that by solving for y at x=d from either side. + // (If those two d values aren't the same, it's a discontinuous transfer function.) + float d_l = src->c * src->d + src->f, + d_r = powf_(src->a * src->d + src->b, src->g) + src->e; + if (fabsf_(d_l - d_r) > 1/512.0f) { + return false; + } + inv.d = d_l; // TODO(mtklein): better in practice to choose d_r? + + // When d=0, the linear section collapses to a point. We leave c,d,f all zero in that case. + if (inv.d > 0) { + // Inverting the linear section is pretty straightfoward: + // y = cx + f + // y - f = cx + // (1/c)y - f/c = x + inv.c = 1.0f/src->c; + inv.f = -src->f/src->c; + } + + // The interesting part is inverting the nonlinear section: + // y = (ax + b)^g + e. + // y - e = (ax + b)^g + // (y - e)^1/g = ax + b + // (y - e)^1/g - b = ax + // (1/a)(y - e)^1/g - b/a = x + // + // To make that fit our form, we need to move the (1/a) term inside the exponentiation: + // let k = (1/a)^g + // (1/a)( y - e)^1/g - b/a = x + // (ky - ke)^1/g - b/a = x + + float k = powf_(src->a, -src->g); // (1/a)^g == a^-g + inv.g = 1.0f / src->g; + inv.a = k; + inv.b = -k * src->e; + inv.e = -src->b / src->a; + + // We need to enforce the same constraints here that we do when fitting a curve, + // a >= 0 and ad+b >= 0. These constraints are checked by classify(), so they're true + // of the source function if we're here. + + // Just like when fitting the curve, there's really no way to rescue a < 0. + if (inv.a < 0) { + return false; + } + // On the other hand we can rescue an ad+b that's gone slightly negative here. + if (inv.a * inv.d + inv.b < 0) { + inv.b = -inv.a * inv.d; + } + + // That should usually make classify(inv) == sRGBish true, but there are a couple situations + // where we might still fail here, like non-finite parameter values. + if (classify(inv) != skcms_TFType_sRGBish) { + return false; + } + + assert (inv.a >= 0); + assert (inv.a * inv.d + inv.b >= 0); + + // Now in principle we're done. + // But to preserve the valuable invariant inv(src(1.0f)) == 1.0f, we'll tweak + // e or f of the inverse, depending on which segment contains src(1.0f). + float s = skcms_TransferFunction_eval(src, 1.0f); + if (!isfinitef_(s)) { + return false; + } + + float sign = s < 0 ? -1.0f : 1.0f; + s *= sign; + if (s < inv.d) { + inv.f = 1.0f - sign * inv.c * s; + } else { + inv.e = 1.0f - sign * powf_(inv.a * s + inv.b, inv.g); + } + + *dst = inv; + return classify(*dst) == skcms_TFType_sRGBish; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // + +// From here below we're approximating an skcms_Curve with an skcms_TransferFunction{g,a,b,c,d,e,f}: +// +// tf(x) = cx + f x < d +// tf(x) = (ax + b)^g + e x ≥ d +// +// When fitting, we add the additional constraint that both pieces meet at d: +// +// cd + f = (ad + b)^g + e +// +// Solving for e and folding it through gives an alternate formulation of the non-linear piece: +// +// tf(x) = cx + f x < d +// tf(x) = (ax + b)^g - (ad + b)^g + cd + f x ≥ d +// +// Our overall strategy is then: +// For a couple tolerances, +// - fit_linear(): fit c,d,f iteratively to as many points as our tolerance allows +// - invert c,d,f +// - fit_nonlinear(): fit g,a,b using Gauss-Newton given those inverted c,d,f +// (and by constraint, inverted e) to the inverse of the table. +// Return the parameters with least maximum error. +// +// To run Gauss-Newton to find g,a,b, we'll also need the gradient of the residuals +// of round-trip f_inv(x), the inverse of the non-linear piece of f(x). +// +// let y = Table(x) +// r(x) = x - f_inv(y) +// +// ∂r/∂g = ln(ay + b)*(ay + b)^g +// - ln(ad + b)*(ad + b)^g +// ∂r/∂a = yg(ay + b)^(g-1) +// - dg(ad + b)^(g-1) +// ∂r/∂b = g(ay + b)^(g-1) +// - g(ad + b)^(g-1) + +// Return the residual of roundtripping skcms_Curve(x) through f_inv(y) with parameters P, +// and fill out the gradient of the residual into dfdP. +static float rg_nonlinear(float x, + const skcms_Curve* curve, + const skcms_TransferFunction* tf, + float dfdP[3]) { + const float y = eval_curve(curve, x); + + const float g = tf->g, a = tf->a, b = tf->b, + c = tf->c, d = tf->d, f = tf->f; + + const float Y = fmaxf_(a*y + b, 0.0f), + D = a*d + b; + assert (D >= 0); + + // The gradient. + dfdP[0] = logf_(Y)*powf_(Y, g) + - logf_(D)*powf_(D, g); + dfdP[1] = y*g*powf_(Y, g-1) + - d*g*powf_(D, g-1); + dfdP[2] = g*powf_(Y, g-1) + - g*powf_(D, g-1); + + // The residual. + const float f_inv = powf_(Y, g) + - powf_(D, g) + + c*d + f; + return x - f_inv; +} + +static bool gauss_newton_step(const skcms_Curve* curve, + skcms_TransferFunction* tf, + float x0, float dx, int N) { + // We'll sample x from the range [x0,x1] (both inclusive) N times with even spacing. + // + // Let P = [ tf->g, tf->a, tf->b ] (the three terms that we're adjusting). + // + // We want to do P' = P + (Jf^T Jf)^-1 Jf^T r(P), + // where r(P) is the residual vector + // and Jf is the Jacobian matrix of f(), ∂r/∂P. + // + // Let's review the shape of each of these expressions: + // r(P) is [N x 1], a column vector with one entry per value of x tested + // Jf is [N x 3], a matrix with an entry for each (x,P) pair + // Jf^T is [3 x N], the transpose of Jf + // + // Jf^T Jf is [3 x N] * [N x 3] == [3 x 3], a 3x3 matrix, + // and so is its inverse (Jf^T Jf)^-1 + // Jf^T r(P) is [3 x N] * [N x 1] == [3 x 1], a column vector with the same shape as P + // + // Our implementation strategy to get to the final ∆P is + // 1) evaluate Jf^T Jf, call that lhs + // 2) evaluate Jf^T r(P), call that rhs + // 3) invert lhs + // 4) multiply inverse lhs by rhs + // + // This is a friendly implementation strategy because we don't have to have any + // buffers that scale with N, and equally nice don't have to perform any matrix + // operations that are variable size. + // + // Other implementation strategies could trade this off, e.g. evaluating the + // pseudoinverse of Jf ( (Jf^T Jf)^-1 Jf^T ) directly, then multiplying that by + // the residuals. That would probably require implementing singular value + // decomposition, and would create a [3 x N] matrix to be multiplied by the + // [N x 1] residual vector, but on the upside I think that'd eliminate the + // possibility of this gauss_newton_step() function ever failing. + + // 0) start off with lhs and rhs safely zeroed. + skcms_Matrix3x3 lhs = {{ {0,0,0}, {0,0,0}, {0,0,0} }}; + skcms_Vector3 rhs = { {0,0,0} }; + + // 1,2) evaluate lhs and evaluate rhs + // We want to evaluate Jf only once, but both lhs and rhs involve Jf^T, + // so we'll have to update lhs and rhs at the same time. + for (int i = 0; i < N; i++) { + float x = x0 + static_cast(i)*dx; + + float dfdP[3] = {0,0,0}; + float resid = rg_nonlinear(x,curve,tf, dfdP); + + for (int r = 0; r < 3; r++) { + for (int c = 0; c < 3; c++) { + lhs.vals[r][c] += dfdP[r] * dfdP[c]; + } + rhs.vals[r] += dfdP[r] * resid; + } + } + + // If any of the 3 P parameters are unused, this matrix will be singular. + // Detect those cases and fix them up to indentity instead, so we can invert. + for (int k = 0; k < 3; k++) { + if (lhs.vals[0][k]==0 && lhs.vals[1][k]==0 && lhs.vals[2][k]==0 && + lhs.vals[k][0]==0 && lhs.vals[k][1]==0 && lhs.vals[k][2]==0) { + lhs.vals[k][k] = 1; + } + } + + // 3) invert lhs + skcms_Matrix3x3 lhs_inv; + if (!skcms_Matrix3x3_invert(&lhs, &lhs_inv)) { + return false; + } + + // 4) multiply inverse lhs by rhs + skcms_Vector3 dP = mv_mul(&lhs_inv, &rhs); + tf->g += dP.vals[0]; + tf->a += dP.vals[1]; + tf->b += dP.vals[2]; + return isfinitef_(tf->g) && isfinitef_(tf->a) && isfinitef_(tf->b); +} + +static float max_roundtrip_error_checked(const skcms_Curve* curve, + const skcms_TransferFunction* tf_inv) { + skcms_TransferFunction tf; + if (!skcms_TransferFunction_invert(tf_inv, &tf) || skcms_TFType_sRGBish != classify(tf)) { + return INFINITY_; + } + + skcms_TransferFunction tf_inv_again; + if (!skcms_TransferFunction_invert(&tf, &tf_inv_again)) { + return INFINITY_; + } + + return skcms_MaxRoundtripError(curve, &tf_inv_again); +} + +// Fit the points in [L,N) to the non-linear piece of tf, or return false if we can't. +static bool fit_nonlinear(const skcms_Curve* curve, int L, int N, skcms_TransferFunction* tf) { + // This enforces a few constraints that are not modeled in gauss_newton_step()'s optimization. + auto fixup_tf = [tf]() { + // a must be non-negative. That ensures the function is monotonically increasing. + // We don't really know how to fix up a if it goes negative. + if (tf->a < 0) { + return false; + } + // ad+b must be non-negative. That ensures we don't end up with complex numbers in powf. + // We feel just barely not uneasy enough to tweak b so ad+b is zero in this case. + if (tf->a * tf->d + tf->b < 0) { + tf->b = -tf->a * tf->d; + } + assert (tf->a >= 0 && + tf->a * tf->d + tf->b >= 0); + + // cd+f must be ~= (ad+b)^g+e. That ensures the function is continuous. We keep e as a free + // parameter so we can guarantee this. + tf->e = tf->c*tf->d + tf->f + - powf_(tf->a*tf->d + tf->b, tf->g); + + return isfinitef_(tf->e); + }; + + if (!fixup_tf()) { + return false; + } + + // No matter where we start, dx should always represent N even steps from 0 to 1. + const float dx = 1.0f / static_cast(N-1); + + skcms_TransferFunction best_tf = *tf; + float best_max_error = INFINITY_; + + // Need this or several curves get worse... *sigh* + float init_error = max_roundtrip_error_checked(curve, tf); + if (init_error < best_max_error) { + best_max_error = init_error; + best_tf = *tf; + } + + // As far as we can tell, 1 Gauss-Newton step won't converge, and 3 steps is no better than 2. + for (int j = 0; j < 8; j++) { + if (!gauss_newton_step(curve, tf, static_cast(L)*dx, dx, N-L) || !fixup_tf()) { + *tf = best_tf; + return isfinitef_(best_max_error); + } + + float max_error = max_roundtrip_error_checked(curve, tf); + if (max_error < best_max_error) { + best_max_error = max_error; + best_tf = *tf; + } + } + + *tf = best_tf; + return isfinitef_(best_max_error); +} + +bool skcms_ApproximateCurve(const skcms_Curve* curve, + skcms_TransferFunction* approx, + float* max_error) { + if (!curve || !approx || !max_error) { + return false; + } + + if (curve->table_entries == 0) { + // No point approximating an skcms_TransferFunction with an skcms_TransferFunction! + return false; + } + + if (curve->table_entries == 1 || curve->table_entries > (uint32_t)INT_MAX) { + // We need at least two points, and must put some reasonable cap on the maximum number. + return false; + } + + int N = (int)curve->table_entries; + const float dx = 1.0f / static_cast(N - 1); + + *max_error = INFINITY_; + const float kTolerances[] = { 1.5f / 65535.0f, 1.0f / 512.0f }; + for (int t = 0; t < ARRAY_COUNT(kTolerances); t++) { + skcms_TransferFunction tf, + tf_inv; + + // It's problematic to fit curves with non-zero f, so always force it to zero explicitly. + tf.f = 0.0f; + int L = fit_linear(curve, N, kTolerances[t], &tf.c, &tf.d); + + if (L == N) { + // If the entire data set was linear, move the coefficients to the nonlinear portion + // with G == 1. This lets use a canonical representation with d == 0. + tf.g = 1; + tf.a = tf.c; + tf.b = tf.f; + tf.c = tf.d = tf.e = tf.f = 0; + } else if (L == N - 1) { + // Degenerate case with only two points in the nonlinear segment. Solve directly. + tf.g = 1; + tf.a = (eval_curve(curve, static_cast(N-1)*dx) - + eval_curve(curve, static_cast(N-2)*dx)) + / dx; + tf.b = eval_curve(curve, static_cast(N-2)*dx) + - tf.a * static_cast(N-2)*dx; + tf.e = 0; + } else { + // Start by guessing a gamma-only curve through the midpoint. + int mid = (L + N) / 2; + float mid_x = static_cast(mid) / static_cast(N - 1); + float mid_y = eval_curve(curve, mid_x); + tf.g = log2f_(mid_y) / log2f_(mid_x); + tf.a = 1; + tf.b = 0; + tf.e = tf.c*tf.d + tf.f + - powf_(tf.a*tf.d + tf.b, tf.g); + + + if (!skcms_TransferFunction_invert(&tf, &tf_inv) || + !fit_nonlinear(curve, L,N, &tf_inv)) { + continue; + } + + // We fit tf_inv, so calculate tf to keep in sync. + // fit_nonlinear() should guarantee invertibility. + if (!skcms_TransferFunction_invert(&tf_inv, &tf)) { + assert(false); + continue; + } + } + + // We'd better have a sane, sRGB-ish TF by now. + // Other non-Bad TFs would be fine, but we know we've only ever tried to fit sRGBish; + // anything else is just some accident of math and the way we pun tf.g as a type flag. + // fit_nonlinear() should guarantee this, but the special cases may fail this test. + if (skcms_TFType_sRGBish != classify(tf)) { + continue; + } + + // We find our error by roundtripping the table through tf_inv. + // + // (The most likely use case for this approximation is to be inverted and + // used as the transfer function for a destination color space.) + // + // We've kept tf and tf_inv in sync above, but we can't guarantee that tf is + // invertible, so re-verify that here (and use the new inverse for testing). + // fit_nonlinear() should guarantee this, but the special cases that don't use + // it may fail this test. + if (!skcms_TransferFunction_invert(&tf, &tf_inv)) { + continue; + } + + float err = skcms_MaxRoundtripError(curve, &tf_inv); + if (*max_error > err) { + *max_error = err; + *approx = tf; + } + } + return isfinitef_(*max_error); +} + +enum class CpuType { Baseline, HSW, SKX }; + +static CpuType cpu_type() { + #if defined(SKCMS_PORTABLE) || !defined(__x86_64__) || defined(SKCMS_FORCE_BASELINE) + return CpuType::Baseline; + #elif defined(SKCMS_FORCE_HSW) + return CpuType::HSW; + #elif defined(SKCMS_FORCE_SKX) + return CpuType::SKX; + #else + static const CpuType type = []{ + if (!sAllowRuntimeCPUDetection) { + return CpuType::Baseline; + } + // See http://www.sandpile.org/x86/cpuid.htm + + // First, a basic cpuid(1) lets us check prerequisites for HSW, SKX. + uint32_t eax, ebx, ecx, edx; + __asm__ __volatile__("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) + : "0"(1), "2"(0)); + if ((edx & (1u<<25)) && // SSE + (edx & (1u<<26)) && // SSE2 + (ecx & (1u<< 0)) && // SSE3 + (ecx & (1u<< 9)) && // SSSE3 + (ecx & (1u<<12)) && // FMA (N.B. not used, avoided even) + (ecx & (1u<<19)) && // SSE4.1 + (ecx & (1u<<20)) && // SSE4.2 + (ecx & (1u<<26)) && // XSAVE + (ecx & (1u<<27)) && // OSXSAVE + (ecx & (1u<<28)) && // AVX + (ecx & (1u<<29))) { // F16C + + // Call cpuid(7) to check for AVX2 and AVX-512 bits. + __asm__ __volatile__("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) + : "0"(7), "2"(0)); + // eax from xgetbv(0) will tell us whether XMM, YMM, and ZMM state is saved. + uint32_t xcr0, dont_need_edx; + __asm__ __volatile__("xgetbv" : "=a"(xcr0), "=d"(dont_need_edx) : "c"(0)); + + if ((xcr0 & (1u<<1)) && // XMM register state saved? + (xcr0 & (1u<<2)) && // YMM register state saved? + (ebx & (1u<<5))) { // AVX2 + // At this point we're at least HSW. Continue checking for SKX. + if ((xcr0 & (1u<< 5)) && // Opmasks state saved? + (xcr0 & (1u<< 6)) && // First 16 ZMM registers saved? + (xcr0 & (1u<< 7)) && // High 16 ZMM registers saved? + (ebx & (1u<<16)) && // AVX512F + (ebx & (1u<<17)) && // AVX512DQ + (ebx & (1u<<28)) && // AVX512CD + (ebx & (1u<<30)) && // AVX512BW + (ebx & (1u<<31))) { // AVX512VL + return CpuType::SKX; + } + return CpuType::HSW; + } + } + return CpuType::Baseline; + }(); + return type; + #endif +} + +static bool tf_is_gamma(const skcms_TransferFunction& tf) { + return tf.g > 0 && tf.a == 1 && + tf.b == 0 && tf.c == 0 && tf.d == 0 && tf.e == 0 && tf.f == 0; +} + +struct OpAndArg { + Op op; + const void* arg; +}; + +static OpAndArg select_curve_op(const skcms_Curve* curve, int channel) { + struct OpType { + Op sGamma, sRGBish, PQish, HLGish, HLGinvish, table; + }; + static constexpr OpType kOps[] = { + { Op::gamma_r, Op::tf_r, Op::pq_r, Op::hlg_r, Op::hlginv_r, Op::table_r }, + { Op::gamma_g, Op::tf_g, Op::pq_g, Op::hlg_g, Op::hlginv_g, Op::table_g }, + { Op::gamma_b, Op::tf_b, Op::pq_b, Op::hlg_b, Op::hlginv_b, Op::table_b }, + { Op::gamma_a, Op::tf_a, Op::pq_a, Op::hlg_a, Op::hlginv_a, Op::table_a }, + }; + const auto& op = kOps[channel]; + + if (curve->table_entries == 0) { + const OpAndArg noop = { Op::load_a8/*doesn't matter*/, nullptr }; + + const skcms_TransferFunction& tf = curve->parametric; + + if (tf_is_gamma(tf)) { + return tf.g != 1 ? OpAndArg{op.sGamma, &tf} + : noop; + } + + switch (classify(tf)) { + case skcms_TFType_Invalid: return noop; + case skcms_TFType_sRGBish: return OpAndArg{op.sRGBish, &tf}; + case skcms_TFType_PQish: return OpAndArg{op.PQish, &tf}; + case skcms_TFType_HLGish: return OpAndArg{op.HLGish, &tf}; + case skcms_TFType_HLGinvish: return OpAndArg{op.HLGinvish, &tf}; + } + } + return OpAndArg{op.table, curve}; +} + +static int select_curve_ops(const skcms_Curve* curves, int numChannels, OpAndArg* ops) { + // We process the channels in reverse order, yielding ops in ABGR order. + // (Working backwards allows us to fuse trailing B+G+R ops into a single RGB op.) + int cursor = 0; + for (int index = numChannels; index-- > 0; ) { + ops[cursor] = select_curve_op(&curves[index], index); + if (ops[cursor].arg) { + ++cursor; + } + } + + // Identify separate B+G+R ops and fuse them into a single RGB op. + if (cursor >= 3) { + struct FusableOps { + Op r, g, b, rgb; + }; + static constexpr FusableOps kFusableOps[] = { + {Op::gamma_r, Op::gamma_g, Op::gamma_b, Op::gamma_rgb}, + {Op::tf_r, Op::tf_g, Op::tf_b, Op::tf_rgb}, + {Op::pq_r, Op::pq_g, Op::pq_b, Op::pq_rgb}, + {Op::hlg_r, Op::hlg_g, Op::hlg_b, Op::hlg_rgb}, + {Op::hlginv_r, Op::hlginv_g, Op::hlginv_b, Op::hlginv_rgb}, + }; + + int posR = cursor - 1; + int posG = cursor - 2; + int posB = cursor - 3; + for (const FusableOps& fusableOp : kFusableOps) { + if (ops[posR].op == fusableOp.r && + ops[posG].op == fusableOp.g && + ops[posB].op == fusableOp.b && + (0 == memcmp(ops[posR].arg, ops[posG].arg, sizeof(skcms_TransferFunction))) && + (0 == memcmp(ops[posR].arg, ops[posB].arg, sizeof(skcms_TransferFunction)))) { + // Fuse the three matching ops into one. + ops[posB].op = fusableOp.rgb; + cursor -= 2; + break; + } + } + } + + return cursor; +} + +static size_t bytes_per_pixel(skcms_PixelFormat fmt) { + switch (fmt >> 1) { // ignore rgb/bgr + case skcms_PixelFormat_A_8 >> 1: return 1; + case skcms_PixelFormat_G_8 >> 1: return 1; + case skcms_PixelFormat_ABGR_4444 >> 1: return 2; + case skcms_PixelFormat_RGB_565 >> 1: return 2; + case skcms_PixelFormat_RGB_888 >> 1: return 3; + case skcms_PixelFormat_RGBA_8888 >> 1: return 4; + case skcms_PixelFormat_RGBA_8888_sRGB >> 1: return 4; + case skcms_PixelFormat_RGBA_1010102 >> 1: return 4; + case skcms_PixelFormat_RGB_101010x_XR >> 1: return 4; + case skcms_PixelFormat_RGB_161616LE >> 1: return 6; + case skcms_PixelFormat_RGBA_10101010_XR >> 1: return 8; + case skcms_PixelFormat_RGBA_16161616LE >> 1: return 8; + case skcms_PixelFormat_RGB_161616BE >> 1: return 6; + case skcms_PixelFormat_RGBA_16161616BE >> 1: return 8; + case skcms_PixelFormat_RGB_hhh_Norm >> 1: return 6; + case skcms_PixelFormat_RGBA_hhhh_Norm >> 1: return 8; + case skcms_PixelFormat_RGB_hhh >> 1: return 6; + case skcms_PixelFormat_RGBA_hhhh >> 1: return 8; + case skcms_PixelFormat_RGB_fff >> 1: return 12; + case skcms_PixelFormat_RGBA_ffff >> 1: return 16; + } + assert(false); + return 0; +} + +static bool prep_for_destination(const skcms_ICCProfile* profile, + skcms_Matrix3x3* fromXYZD50, + skcms_TransferFunction* invR, + skcms_TransferFunction* invG, + skcms_TransferFunction* invB) { + // skcms_Transform() supports B2A destinations... + if (profile->has_B2A) { return true; } + // ...and destinations with parametric transfer functions and an XYZD50 gamut matrix. + return profile->has_trc + && profile->has_toXYZD50 + && profile->trc[0].table_entries == 0 + && profile->trc[1].table_entries == 0 + && profile->trc[2].table_entries == 0 + && skcms_TransferFunction_invert(&profile->trc[0].parametric, invR) + && skcms_TransferFunction_invert(&profile->trc[1].parametric, invG) + && skcms_TransferFunction_invert(&profile->trc[2].parametric, invB) + && skcms_Matrix3x3_invert(&profile->toXYZD50, fromXYZD50); +} + +bool skcms_Transform(const void* src, + skcms_PixelFormat srcFmt, + skcms_AlphaFormat srcAlpha, + const skcms_ICCProfile* srcProfile, + void* dst, + skcms_PixelFormat dstFmt, + skcms_AlphaFormat dstAlpha, + const skcms_ICCProfile* dstProfile, + size_t nz) { + const size_t dst_bpp = bytes_per_pixel(dstFmt), + src_bpp = bytes_per_pixel(srcFmt); + // Let's just refuse if the request is absurdly big. + if (nz * dst_bpp > INT_MAX || nz * src_bpp > INT_MAX) { + return false; + } + int n = (int)nz; + + // Null profiles default to sRGB. Passing null for both is handy when doing format conversion. + if (!srcProfile) { + srcProfile = skcms_sRGB_profile(); + } + if (!dstProfile) { + dstProfile = skcms_sRGB_profile(); + } + + // We can't transform in place unless the PixelFormats are the same size. + if (dst == src && dst_bpp != src_bpp) { + return false; + } + // TODO: more careful alias rejection (like, dst == src + 1)? + + Op program[32]; + const void* context[32]; + + Op* ops = program; + const void** contexts = context; + + auto add_op = [&](Op o) { + *ops++ = o; + *contexts++ = nullptr; + }; + + auto add_op_ctx = [&](Op o, const void* c) { + *ops++ = o; + *contexts++ = c; + }; + + auto add_curve_ops = [&](const skcms_Curve* curves, int numChannels) { + OpAndArg oa[4]; + assert(numChannels <= ARRAY_COUNT(oa)); + + int numOps = select_curve_ops(curves, numChannels, oa); + + for (int i = 0; i < numOps; ++i) { + add_op_ctx(oa[i].op, oa[i].arg); + } + }; + + // These are always parametric curves of some sort. + skcms_Curve dst_curves[3]; + dst_curves[0].table_entries = + dst_curves[1].table_entries = + dst_curves[2].table_entries = 0; + + skcms_Matrix3x3 from_xyz; + + switch (srcFmt >> 1) { + default: return false; + case skcms_PixelFormat_A_8 >> 1: add_op(Op::load_a8); break; + case skcms_PixelFormat_G_8 >> 1: add_op(Op::load_g8); break; + case skcms_PixelFormat_ABGR_4444 >> 1: add_op(Op::load_4444); break; + case skcms_PixelFormat_RGB_565 >> 1: add_op(Op::load_565); break; + case skcms_PixelFormat_RGB_888 >> 1: add_op(Op::load_888); break; + case skcms_PixelFormat_RGBA_8888 >> 1: add_op(Op::load_8888); break; + case skcms_PixelFormat_RGBA_1010102 >> 1: add_op(Op::load_1010102); break; + case skcms_PixelFormat_RGB_101010x_XR >> 1: add_op(Op::load_101010x_XR); break; + case skcms_PixelFormat_RGBA_10101010_XR >> 1: add_op(Op::load_10101010_XR); break; + case skcms_PixelFormat_RGB_161616LE >> 1: add_op(Op::load_161616LE); break; + case skcms_PixelFormat_RGBA_16161616LE >> 1: add_op(Op::load_16161616LE); break; + case skcms_PixelFormat_RGB_161616BE >> 1: add_op(Op::load_161616BE); break; + case skcms_PixelFormat_RGBA_16161616BE >> 1: add_op(Op::load_16161616BE); break; + case skcms_PixelFormat_RGB_hhh_Norm >> 1: add_op(Op::load_hhh); break; + case skcms_PixelFormat_RGBA_hhhh_Norm >> 1: add_op(Op::load_hhhh); break; + case skcms_PixelFormat_RGB_hhh >> 1: add_op(Op::load_hhh); break; + case skcms_PixelFormat_RGBA_hhhh >> 1: add_op(Op::load_hhhh); break; + case skcms_PixelFormat_RGB_fff >> 1: add_op(Op::load_fff); break; + case skcms_PixelFormat_RGBA_ffff >> 1: add_op(Op::load_ffff); break; + + case skcms_PixelFormat_RGBA_8888_sRGB >> 1: + add_op(Op::load_8888); + add_op_ctx(Op::tf_rgb, skcms_sRGB_TransferFunction()); + break; + } + if (srcFmt == skcms_PixelFormat_RGB_hhh_Norm || + srcFmt == skcms_PixelFormat_RGBA_hhhh_Norm) { + add_op(Op::clamp); + } + if (srcFmt & 1) { + add_op(Op::swap_rb); + } + skcms_ICCProfile gray_dst_profile; + if ((dstFmt >> 1) == (skcms_PixelFormat_G_8 >> 1)) { + // When transforming to gray, stop at XYZ (by setting toXYZ to identity), then transform + // luminance (Y) by the destination transfer function. + gray_dst_profile = *dstProfile; + skcms_SetXYZD50(&gray_dst_profile, &skcms_XYZD50_profile()->toXYZD50); + dstProfile = &gray_dst_profile; + } + + if (srcProfile->data_color_space == skcms_Signature_CMYK) { + // Photoshop creates CMYK images as inverse CMYK. + // These happen to be the only ones we've _ever_ seen. + add_op(Op::invert); + // With CMYK, ignore the alpha type, to avoid changing K or conflating CMY with K. + srcAlpha = skcms_AlphaFormat_Unpremul; + } + + if (srcAlpha == skcms_AlphaFormat_Opaque) { + add_op(Op::force_opaque); + } else if (srcAlpha == skcms_AlphaFormat_PremulAsEncoded) { + add_op(Op::unpremul); + } + + if (dstProfile != srcProfile) { + + if (!prep_for_destination(dstProfile, + &from_xyz, + &dst_curves[0].parametric, + &dst_curves[1].parametric, + &dst_curves[2].parametric)) { + return false; + } + + if (srcProfile->has_A2B) { + if (srcProfile->A2B.input_channels) { + add_curve_ops(srcProfile->A2B.input_curves, + (int)srcProfile->A2B.input_channels); + add_op(Op::clamp); + add_op_ctx(Op::clut_A2B, &srcProfile->A2B); + } + + if (srcProfile->A2B.matrix_channels == 3) { + add_curve_ops(srcProfile->A2B.matrix_curves, /*numChannels=*/3); + + static const skcms_Matrix3x4 I = {{ + {1,0,0,0}, + {0,1,0,0}, + {0,0,1,0}, + }}; + if (0 != memcmp(&I, &srcProfile->A2B.matrix, sizeof(I))) { + add_op_ctx(Op::matrix_3x4, &srcProfile->A2B.matrix); + } + } + + if (srcProfile->A2B.output_channels == 3) { + add_curve_ops(srcProfile->A2B.output_curves, /*numChannels=*/3); + } + + if (srcProfile->pcs == skcms_Signature_Lab) { + add_op(Op::lab_to_xyz); + } + + } else if (srcProfile->has_trc && srcProfile->has_toXYZD50) { + add_curve_ops(srcProfile->trc, /*numChannels=*/3); + } else { + return false; + } + + // A2B sources are in XYZD50 by now, but TRC sources are still in their original gamut. + assert (srcProfile->has_A2B || srcProfile->has_toXYZD50); + + if (dstProfile->has_B2A) { + // B2A needs its input in XYZD50, so transform TRC sources now. + if (!srcProfile->has_A2B) { + add_op_ctx(Op::matrix_3x3, &srcProfile->toXYZD50); + } + + if (dstProfile->pcs == skcms_Signature_Lab) { + add_op(Op::xyz_to_lab); + } + + if (dstProfile->B2A.input_channels == 3) { + add_curve_ops(dstProfile->B2A.input_curves, /*numChannels=*/3); + } + + if (dstProfile->B2A.matrix_channels == 3) { + static const skcms_Matrix3x4 I = {{ + {1,0,0,0}, + {0,1,0,0}, + {0,0,1,0}, + }}; + if (0 != memcmp(&I, &dstProfile->B2A.matrix, sizeof(I))) { + add_op_ctx(Op::matrix_3x4, &dstProfile->B2A.matrix); + } + + add_curve_ops(dstProfile->B2A.matrix_curves, /*numChannels=*/3); + } + + if (dstProfile->B2A.output_channels) { + add_op(Op::clamp); + add_op_ctx(Op::clut_B2A, &dstProfile->B2A); + + add_curve_ops(dstProfile->B2A.output_curves, + (int)dstProfile->B2A.output_channels); + } + } else { + // This is a TRC destination. + // We'll concat any src->xyz matrix with our xyz->dst matrix into one src->dst matrix. + // (A2B sources are already in XYZD50, making that src->xyz matrix I.) + static const skcms_Matrix3x3 I = {{ + { 1.0f, 0.0f, 0.0f }, + { 0.0f, 1.0f, 0.0f }, + { 0.0f, 0.0f, 1.0f }, + }}; + const skcms_Matrix3x3* to_xyz = srcProfile->has_A2B ? &I : &srcProfile->toXYZD50; + + // There's a chance the source and destination gamuts are identical, + // in which case we can skip the gamut transform. + if (0 != memcmp(&dstProfile->toXYZD50, to_xyz, sizeof(skcms_Matrix3x3))) { + // Concat the entire gamut transform into from_xyz, + // now slightly misnamed but it's a handy spot to stash the result. + from_xyz = skcms_Matrix3x3_concat(&from_xyz, to_xyz); + add_op_ctx(Op::matrix_3x3, &from_xyz); + } + + // Encode back to dst RGB using its parametric transfer functions. + OpAndArg oa[3]; + int numOps = select_curve_ops(dst_curves, /*numChannels=*/3, oa); + for (int index = 0; index < numOps; ++index) { + assert(oa[index].op != Op::table_r && + oa[index].op != Op::table_g && + oa[index].op != Op::table_b && + oa[index].op != Op::table_a); + add_op_ctx(oa[index].op, oa[index].arg); + } + } + } + + // Clamp here before premul to make sure we're clamping to normalized values _and_ gamut, + // not just to values that fit in [0,1]. + // + // E.g. r = 1.1, a = 0.5 would fit fine in fixed point after premul (ra=0.55,a=0.5), + // but would be carrying r > 1, which is really unexpected for downstream consumers. + if (dstFmt < skcms_PixelFormat_RGB_hhh) { + add_op(Op::clamp); + } + + if (dstProfile->data_color_space == skcms_Signature_CMYK) { + // Photoshop creates CMYK images as inverse CMYK. + // These happen to be the only ones we've _ever_ seen. + add_op(Op::invert); + + // CMYK has no alpha channel, so make sure dstAlpha is a no-op. + dstAlpha = skcms_AlphaFormat_Unpremul; + } + + if (dstAlpha == skcms_AlphaFormat_Opaque) { + add_op(Op::force_opaque); + } else if (dstAlpha == skcms_AlphaFormat_PremulAsEncoded) { + add_op(Op::premul); + } + if (dstFmt & 1) { + add_op(Op::swap_rb); + } + switch (dstFmt >> 1) { + default: return false; + case skcms_PixelFormat_A_8 >> 1: add_op(Op::store_a8); break; + case skcms_PixelFormat_G_8 >> 1: add_op(Op::store_g8); break; + case skcms_PixelFormat_ABGR_4444 >> 1: add_op(Op::store_4444); break; + case skcms_PixelFormat_RGB_565 >> 1: add_op(Op::store_565); break; + case skcms_PixelFormat_RGB_888 >> 1: add_op(Op::store_888); break; + case skcms_PixelFormat_RGBA_8888 >> 1: add_op(Op::store_8888); break; + case skcms_PixelFormat_RGBA_1010102 >> 1: add_op(Op::store_1010102); break; + case skcms_PixelFormat_RGB_161616LE >> 1: add_op(Op::store_161616LE); break; + case skcms_PixelFormat_RGBA_16161616LE >> 1: add_op(Op::store_16161616LE); break; + case skcms_PixelFormat_RGB_161616BE >> 1: add_op(Op::store_161616BE); break; + case skcms_PixelFormat_RGBA_16161616BE >> 1: add_op(Op::store_16161616BE); break; + case skcms_PixelFormat_RGB_hhh_Norm >> 1: add_op(Op::store_hhh); break; + case skcms_PixelFormat_RGBA_hhhh_Norm >> 1: add_op(Op::store_hhhh); break; + case skcms_PixelFormat_RGB_101010x_XR >> 1: add_op(Op::store_101010x_XR); break; + case skcms_PixelFormat_RGB_hhh >> 1: add_op(Op::store_hhh); break; + case skcms_PixelFormat_RGBA_hhhh >> 1: add_op(Op::store_hhhh); break; + case skcms_PixelFormat_RGB_fff >> 1: add_op(Op::store_fff); break; + case skcms_PixelFormat_RGBA_ffff >> 1: add_op(Op::store_ffff); break; + + case skcms_PixelFormat_RGBA_8888_sRGB >> 1: + add_op_ctx(Op::tf_rgb, skcms_sRGB_Inverse_TransferFunction()); + add_op(Op::store_8888); + break; + } + + assert(ops <= program + ARRAY_COUNT(program)); + assert(contexts <= context + ARRAY_COUNT(context)); + + auto run = baseline::run_program; + switch (cpu_type()) { + case CpuType::SKX: + #if !defined(SKCMS_DISABLE_SKX) + run = skx::run_program; + break; + #endif + + case CpuType::HSW: + #if !defined(SKCMS_DISABLE_HSW) + run = hsw::run_program; + break; + #endif + + case CpuType::Baseline: + break; + } + + run(program, context, ops - program, (const char*)src, (char*)dst, n, src_bpp,dst_bpp); + return true; +} + +static void assert_usable_as_destination(const skcms_ICCProfile* profile) { +#if defined(NDEBUG) + (void)profile; +#else + skcms_Matrix3x3 fromXYZD50; + skcms_TransferFunction invR, invG, invB; + assert(prep_for_destination(profile, &fromXYZD50, &invR, &invG, &invB)); +#endif +} + +bool skcms_MakeUsableAsDestination(skcms_ICCProfile* profile) { + if (!profile->has_B2A) { + skcms_Matrix3x3 fromXYZD50; + if (!profile->has_trc || !profile->has_toXYZD50 + || !skcms_Matrix3x3_invert(&profile->toXYZD50, &fromXYZD50)) { + return false; + } + + skcms_TransferFunction tf[3]; + for (int i = 0; i < 3; i++) { + skcms_TransferFunction inv; + if (profile->trc[i].table_entries == 0 + && skcms_TransferFunction_invert(&profile->trc[i].parametric, &inv)) { + tf[i] = profile->trc[i].parametric; + continue; + } + + float max_error; + // Parametric curves from skcms_ApproximateCurve() are guaranteed to be invertible. + if (!skcms_ApproximateCurve(&profile->trc[i], &tf[i], &max_error)) { + return false; + } + } + + for (int i = 0; i < 3; ++i) { + profile->trc[i].table_entries = 0; + profile->trc[i].parametric = tf[i]; + } + } + assert_usable_as_destination(profile); + return true; +} + +bool skcms_MakeUsableAsDestinationWithSingleCurve(skcms_ICCProfile* profile) { + // Call skcms_MakeUsableAsDestination() with B2A disabled; + // on success that'll return a TRC/XYZ profile with three skcms_TransferFunctions. + skcms_ICCProfile result = *profile; + result.has_B2A = false; + if (!skcms_MakeUsableAsDestination(&result)) { + return false; + } + + // Of the three, pick the transfer function that best fits the other two. + int best_tf = 0; + float min_max_error = INFINITY_; + for (int i = 0; i < 3; i++) { + skcms_TransferFunction inv; + if (!skcms_TransferFunction_invert(&result.trc[i].parametric, &inv)) { + return false; + } + + float err = 0; + for (int j = 0; j < 3; ++j) { + err = fmaxf_(err, skcms_MaxRoundtripError(&profile->trc[j], &inv)); + } + if (min_max_error > err) { + min_max_error = err; + best_tf = i; + } + } + + for (int i = 0; i < 3; i++) { + result.trc[i].parametric = result.trc[best_tf].parametric; + } + + *profile = result; + assert_usable_as_destination(profile); + return true; +} diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/skcms.gni b/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/skcms.gni new file mode 100644 index 0000000000..62fe24873d --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/skcms.gni @@ -0,0 +1,57 @@ +# DO NOT EDIT: This is a generated file. +# See //bazel/exporter_tool/README.md for more information. +# +# The source of truth is //modules/skcms/BUILD.bazel + +# To update this file, run make -C bazel generate_gni + +_modules = get_path_info("../../modules", "abspath") + +# Generated by Bazel rule //modules/skcms:public_hdrs +skcms_public_headers = [ "$_modules/skcms/skcms.h" ] + +# List generated by Bazel rules: +# //modules/skcms:srcs +# //modules/skcms:textual_hdrs +skcms_sources = [ + "$_modules/skcms/skcms.cc", + "$_modules/skcms/src/Transform_inl.h", + "$_modules/skcms/src/skcms_Transform.h", + "$_modules/skcms/src/skcms_TransformBaseline.cc", + "$_modules/skcms/src/skcms_TransformHsw.cc", + "$_modules/skcms/src/skcms_TransformSkx.cc", + "$_modules/skcms/src/skcms_internals.h", + "$_modules/skcms/src/skcms_public.h", +] + +# Generated by Bazel rule //modules/skcms:skcms_public +skcms_public = [ + "$_modules/skcms/skcms.cc", + "$_modules/skcms/skcms.h", + "$_modules/skcms/src/skcms_internals.h", + "$_modules/skcms/src/skcms_public.h", +] + +# Generated by Bazel rule //modules/skcms:skcms_TransformBaseline +skcms_TransformBaseline = [ + "$_modules/skcms/src/skcms_Transform.h", + "$_modules/skcms/src/skcms_TransformBaseline.cc", + "$_modules/skcms/src/skcms_internals.h", + "$_modules/skcms/src/skcms_public.h", +] + +# Generated by Bazel rule //modules/skcms:skcms_TransformHsw +skcms_TransformHsw = [ + "$_modules/skcms/src/skcms_Transform.h", + "$_modules/skcms/src/skcms_TransformHsw.cc", + "$_modules/skcms/src/skcms_internals.h", + "$_modules/skcms/src/skcms_public.h", +] + +# Generated by Bazel rule //modules/skcms:skcms_TransformSkx +skcms_TransformSkx = [ + "$_modules/skcms/src/skcms_Transform.h", + "$_modules/skcms/src/skcms_TransformSkx.cc", + "$_modules/skcms/src/skcms_internals.h", + "$_modules/skcms/src/skcms_public.h", +] diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/skcms.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/skcms.h new file mode 100644 index 0000000000..7a9d4c1897 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/skcms.h @@ -0,0 +1,10 @@ +/* + * Copyright 2023 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#pragma once + +#include "src/skcms_public.h" // NO_G3_REWRITE diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/src/Transform_inl.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/src/Transform_inl.h new file mode 100644 index 0000000000..b9c27ac395 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/src/Transform_inl.h @@ -0,0 +1,1541 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +// Intentionally NO #pragma once... included multiple times. + +// This file is included from skcms.cc in a namespace with some pre-defines: +// - N: SIMD width of all vectors; 1, 4, 8 or 16 (preprocessor define) +// - V: a template to create a vector of N T's. + +using F = V; +using I32 = V; +using U64 = V; +using U32 = V; +using U16 = V; +using U8 = V; + +#if defined(__GNUC__) && !defined(__clang__) + // GCC is kind of weird, not allowing vector = scalar directly. + static constexpr F F0 = F() + 0.0f, + F1 = F() + 1.0f, + FInfBits = F() + 0x7f800000; // equals 2139095040, the bit pattern of +Inf +#else + static constexpr F F0 = 0.0f, + F1 = 1.0f, + FInfBits = 0x7f800000; // equals 2139095040, the bit pattern of +Inf +#endif + +// Instead of checking __AVX__ below, we'll check USING_AVX. +// This lets skcms.cc set USING_AVX to force us in even if the compiler's not set that way. +// Same deal for __F16C__ and __AVX2__ ~~~> USING_AVX_F16C, USING_AVX2. + +#if !defined(USING_AVX) && N == 8 && defined(__AVX__) + #define USING_AVX +#endif +#if !defined(USING_AVX_F16C) && defined(USING_AVX) && defined(__F16C__) + #define USING_AVX_F16C +#endif +#if !defined(USING_AVX2) && defined(USING_AVX) && defined(__AVX2__) + #define USING_AVX2 +#endif +#if !defined(USING_AVX512F) && N == 16 && defined(__AVX512F__) && defined(__AVX512DQ__) + #define USING_AVX512F +#endif + +// Similar to the AVX+ features, we define USING_NEON and USING_NEON_F16C. +// This is more for organizational clarity... skcms.cc doesn't force these. +#if N > 1 && defined(__ARM_NEON) + #define USING_NEON + + // We have to use two different mechanisms to enable the f16 conversion intrinsics: + #if defined(__clang__) + // Clang's arm_neon.h guards them with the FP hardware bit: + #if __ARM_FP & 2 + #define USING_NEON_F16C + #endif + #elif defined(__GNUC__) + // GCC's arm_neon.h guards them with the FP16 format macros (IEEE and ALTERNATIVE). + // We don't actually want the alternative format - we're reading/writing IEEE f16 values. + #if defined(__ARM_FP16_FORMAT_IEEE) + #define USING_NEON_F16C + #endif + #endif +#endif + +// These -Wvector-conversion warnings seem to trigger in very bogus situations, +// like vst3q_f32() expecting a 16x char rather than a 4x float vector. :/ +#if defined(USING_NEON) && defined(__clang__) + #pragma clang diagnostic ignored "-Wvector-conversion" +#endif + +// GCC & Clang (but not clang-cl) warn returning U64 on x86 is larger than a register. +// You'd see warnings like, "using AVX even though AVX is not enabled". +// We stifle these warnings; our helpers that return U64 are always inlined. +#if defined(__SSE__) && defined(__GNUC__) + #if !defined(__has_warning) + #pragma GCC diagnostic ignored "-Wpsabi" + #elif __has_warning("-Wpsabi") + #pragma GCC diagnostic ignored "-Wpsabi" + #endif +#endif + +// We tag most helper functions as SI, to enforce good code generation +// but also work around what we think is a bug in GCC: when targeting 32-bit +// x86, GCC tends to pass U16 (4x uint16_t vector) function arguments in the +// MMX mm0 register, which seems to mess with unrelated code that later uses +// x87 FP instructions (MMX's mm0 is an alias for x87's st0 register). +#if defined(__clang__) || defined(__GNUC__) + #define SI static inline __attribute__((always_inline)) +#else + #define SI static inline +#endif + +template +SI T load(const P* ptr) { + T val; + memcpy(&val, ptr, sizeof(val)); + return val; +} +template +SI void store(P* ptr, const T& val) { + memcpy(ptr, &val, sizeof(val)); +} + +// (T)v is a cast when N == 1 and a bit-pun when N>1, +// so we use cast(v) to actually cast or bit_pun(v) to bit-pun. +template +SI D cast(const S& v) { +#if N == 1 + return (D)v; +#elif defined(__clang__) + return __builtin_convertvector(v, D); +#else + D d; + for (int i = 0; i < N; i++) { + d[i] = v[i]; + } + return d; +#endif +} + +template +SI D bit_pun(const S& v) { + static_assert(sizeof(D) == sizeof(v), ""); + return load(&v); +} + +// When we convert from float to fixed point, it's very common to want to round, +// and for some reason compilers generate better code when converting to int32_t. +// To serve both those ends, we use this function to_fixed() instead of direct cast(). +SI U32 to_fixed(F f) { return (U32)cast(f + 0.5f); } + +// Sometimes we do something crazy on one branch of a conditonal, +// like divide by zero or convert a huge float to an integer, +// but then harmlessly select the other side. That trips up N==1 +// sanitizer builds, so we make if_then_else() a macro to avoid +// evaluating the unused side. + +#if N == 1 + #define if_then_else(cond, t, e) ((cond) ? (t) : (e)) +#else + template + SI T if_then_else(C cond, T t, T e) { + return bit_pun( ( cond & bit_pun(t)) | + (~cond & bit_pun(e)) ); + } +#endif + + +SI F F_from_Half(U16 half) { +#if defined(USING_NEON_F16C) + return vcvt_f32_f16((float16x4_t)half); +#elif defined(USING_AVX512F) + return (F)_mm512_cvtph_ps((__m256i)half); +#elif defined(USING_AVX_F16C) + typedef int16_t __attribute__((vector_size(16))) I16; + return __builtin_ia32_vcvtph2ps256((I16)half); +#else + U32 wide = cast(half); + // A half is 1-5-10 sign-exponent-mantissa, with 15 exponent bias. + U32 s = wide & 0x8000, + em = wide ^ s; + + // Constructing the float is easy if the half is not denormalized. + F norm = bit_pun( (s<<16) + (em<<13) + ((127-15)<<23) ); + + // Simply flush all denorm half floats to zero. + return if_then_else(em < 0x0400, F0, norm); +#endif +} + +#if defined(__clang__) + // The -((127-15)<<10) underflows that side of the math when + // we pass a denorm half float. It's harmless... we'll take the 0 side anyway. + __attribute__((no_sanitize("unsigned-integer-overflow"))) +#endif +SI U16 Half_from_F(F f) { +#if defined(USING_NEON_F16C) + return (U16)vcvt_f16_f32(f); +#elif defined(USING_AVX512F) + return (U16)_mm512_cvtps_ph((__m512 )f, _MM_FROUND_CUR_DIRECTION ); +#elif defined(USING_AVX_F16C) + return (U16)__builtin_ia32_vcvtps2ph256(f, 0x04/*_MM_FROUND_CUR_DIRECTION*/); +#else + // A float is 1-8-23 sign-exponent-mantissa, with 127 exponent bias. + U32 sem = bit_pun(f), + s = sem & 0x80000000, + em = sem ^ s; + + // For simplicity we flush denorm half floats (including all denorm floats) to zero. + return cast(if_then_else(em < 0x38800000, (U32)F0 + , (s>>16) + (em>>13) - ((127-15)<<10))); +#endif +} + +// Swap high and low bytes of 16-bit lanes, converting between big-endian and little-endian. +#if defined(USING_NEON) + SI U16 swap_endian_16(U16 v) { + return (U16)vrev16_u8((uint8x8_t) v); + } +#endif + +SI U64 swap_endian_16x4(const U64& rgba) { + return (rgba & 0x00ff00ff00ff00ff) << 8 + | (rgba & 0xff00ff00ff00ff00) >> 8; +} + +#if defined(USING_NEON) + SI F min_(F x, F y) { return (F)vminq_f32((float32x4_t)x, (float32x4_t)y); } + SI F max_(F x, F y) { return (F)vmaxq_f32((float32x4_t)x, (float32x4_t)y); } +#else + SI F min_(F x, F y) { return if_then_else(x > y, y, x); } + SI F max_(F x, F y) { return if_then_else(x < y, y, x); } +#endif + +SI F floor_(F x) { +#if N == 1 + return floorf_(x); +#elif defined(__aarch64__) + return vrndmq_f32(x); +#elif defined(USING_AVX512F) + // Clang's _mm512_floor_ps() passes its mask as -1, not (__mmask16)-1, + // and integer santizer catches that this implicit cast changes the + // value from -1 to 65535. We'll cast manually to work around it. + // Read this as `return _mm512_floor_ps(x)`. + return _mm512_mask_floor_ps(x, (__mmask16)-1, x); +#elif defined(USING_AVX) + return __builtin_ia32_roundps256(x, 0x01/*_MM_FROUND_FLOOR*/); +#elif defined(__SSE4_1__) + return _mm_floor_ps(x); +#else + // Round trip through integers with a truncating cast. + F roundtrip = cast(cast(x)); + // If x is negative, truncating gives the ceiling instead of the floor. + return roundtrip - if_then_else(roundtrip > x, F1, F0); + + // This implementation fails for values of x that are outside + // the range an integer can represent. We expect most x to be small. +#endif +} + +SI F approx_log2(F x) { + // The first approximation of log2(x) is its exponent 'e', minus 127. + I32 bits = bit_pun(x); + + F e = cast(bits) * (1.0f / (1<<23)); + + // If we use the mantissa too we can refine the error signficantly. + F m = bit_pun( (bits & 0x007fffff) | 0x3f000000 ); + + return e - 124.225514990f + - 1.498030302f*m + - 1.725879990f/(0.3520887068f + m); +} + +SI F approx_log(F x) { + const float ln2 = 0.69314718f; + return ln2 * approx_log2(x); +} + +SI F approx_exp2(F x) { + F fract = x - floor_(x); + + F fbits = (1.0f * (1<<23)) * (x + 121.274057500f + - 1.490129070f*fract + + 27.728023300f/(4.84252568f - fract)); + I32 bits = cast(min_(max_(fbits, F0), FInfBits)); + + return bit_pun(bits); +} + +SI F approx_pow(F x, float y) { + return if_then_else((x == F0) | (x == F1), x + , approx_exp2(approx_log2(x) * y)); +} + +SI F approx_exp(F x) { + const float log2_e = 1.4426950408889634074f; + return approx_exp2(log2_e * x); +} + +SI F strip_sign(F x, U32* sign) { + U32 bits = bit_pun(x); + *sign = bits & 0x80000000; + return bit_pun(bits ^ *sign); +} + +SI F apply_sign(F x, U32 sign) { + return bit_pun(sign | bit_pun(x)); +} + +// Return tf(x). +SI F apply_tf(const skcms_TransferFunction* tf, F x) { + // Peel off the sign bit and set x = |x|. + U32 sign; + x = strip_sign(x, &sign); + + // The transfer function has a linear part up to d, exponential at d and after. + F v = if_then_else(x < tf->d, tf->c*x + tf->f + , approx_pow(tf->a*x + tf->b, tf->g) + tf->e); + + // Tack the sign bit back on. + return apply_sign(v, sign); +} + +// Return the gamma function (|x|^G with the original sign re-applied to x). +SI F apply_gamma(const skcms_TransferFunction* tf, F x) { + U32 sign; + x = strip_sign(x, &sign); + return apply_sign(approx_pow(x, tf->g), sign); +} + +SI F apply_pq(const skcms_TransferFunction* tf, F x) { + U32 bits = bit_pun(x), + sign = bits & 0x80000000; + x = bit_pun(bits ^ sign); + + F v = approx_pow(max_(tf->a + tf->b * approx_pow(x, tf->c), F0) + / (tf->d + tf->e * approx_pow(x, tf->c)), + tf->f); + + return bit_pun(sign | bit_pun(v)); +} + +SI F apply_hlg(const skcms_TransferFunction* tf, F x) { + const float R = tf->a, G = tf->b, + a = tf->c, b = tf->d, c = tf->e, + K = tf->f + 1; + U32 bits = bit_pun(x), + sign = bits & 0x80000000; + x = bit_pun(bits ^ sign); + + F v = if_then_else(x*R <= 1, approx_pow(x*R, G) + , approx_exp((x-c)*a) + b); + + return K*bit_pun(sign | bit_pun(v)); +} + +SI F apply_hlginv(const skcms_TransferFunction* tf, F x) { + const float R = tf->a, G = tf->b, + a = tf->c, b = tf->d, c = tf->e, + K = tf->f + 1; + U32 bits = bit_pun(x), + sign = bits & 0x80000000; + x = bit_pun(bits ^ sign); + x /= K; + + F v = if_then_else(x <= 1, R * approx_pow(x, G) + , a * approx_log(x - b) + c); + + return bit_pun(sign | bit_pun(v)); +} + + +// Strided loads and stores of N values, starting from p. +template +SI T load_3(const P* p) { +#if N == 1 + return (T)p[0]; +#elif N == 4 + return T{p[ 0],p[ 3],p[ 6],p[ 9]}; +#elif N == 8 + return T{p[ 0],p[ 3],p[ 6],p[ 9], p[12],p[15],p[18],p[21]}; +#elif N == 16 + return T{p[ 0],p[ 3],p[ 6],p[ 9], p[12],p[15],p[18],p[21], + p[24],p[27],p[30],p[33], p[36],p[39],p[42],p[45]}; +#endif +} + +template +SI T load_4(const P* p) { +#if N == 1 + return (T)p[0]; +#elif N == 4 + return T{p[ 0],p[ 4],p[ 8],p[12]}; +#elif N == 8 + return T{p[ 0],p[ 4],p[ 8],p[12], p[16],p[20],p[24],p[28]}; +#elif N == 16 + return T{p[ 0],p[ 4],p[ 8],p[12], p[16],p[20],p[24],p[28], + p[32],p[36],p[40],p[44], p[48],p[52],p[56],p[60]}; +#endif +} + +template +SI void store_3(P* p, const T& v) { +#if N == 1 + p[0] = v; +#elif N == 4 + p[ 0] = v[ 0]; p[ 3] = v[ 1]; p[ 6] = v[ 2]; p[ 9] = v[ 3]; +#elif N == 8 + p[ 0] = v[ 0]; p[ 3] = v[ 1]; p[ 6] = v[ 2]; p[ 9] = v[ 3]; + p[12] = v[ 4]; p[15] = v[ 5]; p[18] = v[ 6]; p[21] = v[ 7]; +#elif N == 16 + p[ 0] = v[ 0]; p[ 3] = v[ 1]; p[ 6] = v[ 2]; p[ 9] = v[ 3]; + p[12] = v[ 4]; p[15] = v[ 5]; p[18] = v[ 6]; p[21] = v[ 7]; + p[24] = v[ 8]; p[27] = v[ 9]; p[30] = v[10]; p[33] = v[11]; + p[36] = v[12]; p[39] = v[13]; p[42] = v[14]; p[45] = v[15]; +#endif +} + +template +SI void store_4(P* p, const T& v) { +#if N == 1 + p[0] = v; +#elif N == 4 + p[ 0] = v[ 0]; p[ 4] = v[ 1]; p[ 8] = v[ 2]; p[12] = v[ 3]; +#elif N == 8 + p[ 0] = v[ 0]; p[ 4] = v[ 1]; p[ 8] = v[ 2]; p[12] = v[ 3]; + p[16] = v[ 4]; p[20] = v[ 5]; p[24] = v[ 6]; p[28] = v[ 7]; +#elif N == 16 + p[ 0] = v[ 0]; p[ 4] = v[ 1]; p[ 8] = v[ 2]; p[12] = v[ 3]; + p[16] = v[ 4]; p[20] = v[ 5]; p[24] = v[ 6]; p[28] = v[ 7]; + p[32] = v[ 8]; p[36] = v[ 9]; p[40] = v[10]; p[44] = v[11]; + p[48] = v[12]; p[52] = v[13]; p[56] = v[14]; p[60] = v[15]; +#endif +} + + +SI U8 gather_8(const uint8_t* p, I32 ix) { +#if N == 1 + U8 v = p[ix]; +#elif N == 4 + U8 v = { p[ix[0]], p[ix[1]], p[ix[2]], p[ix[3]] }; +#elif N == 8 + U8 v = { p[ix[0]], p[ix[1]], p[ix[2]], p[ix[3]], + p[ix[4]], p[ix[5]], p[ix[6]], p[ix[7]] }; +#elif N == 16 + U8 v = { p[ix[ 0]], p[ix[ 1]], p[ix[ 2]], p[ix[ 3]], + p[ix[ 4]], p[ix[ 5]], p[ix[ 6]], p[ix[ 7]], + p[ix[ 8]], p[ix[ 9]], p[ix[10]], p[ix[11]], + p[ix[12]], p[ix[13]], p[ix[14]], p[ix[15]] }; +#endif + return v; +} + +SI U16 gather_16(const uint8_t* p, I32 ix) { + // Load the i'th 16-bit value from p. + auto load_16 = [p](int i) { + return load(p + 2*i); + }; +#if N == 1 + U16 v = load_16(ix); +#elif N == 4 + U16 v = { load_16(ix[0]), load_16(ix[1]), load_16(ix[2]), load_16(ix[3]) }; +#elif N == 8 + U16 v = { load_16(ix[0]), load_16(ix[1]), load_16(ix[2]), load_16(ix[3]), + load_16(ix[4]), load_16(ix[5]), load_16(ix[6]), load_16(ix[7]) }; +#elif N == 16 + U16 v = { load_16(ix[ 0]), load_16(ix[ 1]), load_16(ix[ 2]), load_16(ix[ 3]), + load_16(ix[ 4]), load_16(ix[ 5]), load_16(ix[ 6]), load_16(ix[ 7]), + load_16(ix[ 8]), load_16(ix[ 9]), load_16(ix[10]), load_16(ix[11]), + load_16(ix[12]), load_16(ix[13]), load_16(ix[14]), load_16(ix[15]) }; +#endif + return v; +} + +SI U32 gather_32(const uint8_t* p, I32 ix) { + // Load the i'th 32-bit value from p. + auto load_32 = [p](int i) { + return load(p + 4*i); + }; +#if N == 1 + U32 v = load_32(ix); +#elif N == 4 + U32 v = { load_32(ix[0]), load_32(ix[1]), load_32(ix[2]), load_32(ix[3]) }; +#elif N == 8 + U32 v = { load_32(ix[0]), load_32(ix[1]), load_32(ix[2]), load_32(ix[3]), + load_32(ix[4]), load_32(ix[5]), load_32(ix[6]), load_32(ix[7]) }; +#elif N == 16 + U32 v = { load_32(ix[ 0]), load_32(ix[ 1]), load_32(ix[ 2]), load_32(ix[ 3]), + load_32(ix[ 4]), load_32(ix[ 5]), load_32(ix[ 6]), load_32(ix[ 7]), + load_32(ix[ 8]), load_32(ix[ 9]), load_32(ix[10]), load_32(ix[11]), + load_32(ix[12]), load_32(ix[13]), load_32(ix[14]), load_32(ix[15]) }; +#endif + // TODO: AVX2 and AVX-512 gathers (c.f. gather_24). + return v; +} + +SI U32 gather_24(const uint8_t* p, I32 ix) { + // First, back up a byte. Any place we're gathering from has a safe junk byte to read + // in front of it, either a previous table value, or some tag metadata. + p -= 1; + + // Load the i'th 24-bit value from p, and 1 extra byte. + auto load_24_32 = [p](int i) { + return load(p + 3*i); + }; + + // Now load multiples of 4 bytes (a junk byte, then r,g,b). +#if N == 1 + U32 v = load_24_32(ix); +#elif N == 4 + U32 v = { load_24_32(ix[0]), load_24_32(ix[1]), load_24_32(ix[2]), load_24_32(ix[3]) }; +#elif N == 8 && !defined(USING_AVX2) + U32 v = { load_24_32(ix[0]), load_24_32(ix[1]), load_24_32(ix[2]), load_24_32(ix[3]), + load_24_32(ix[4]), load_24_32(ix[5]), load_24_32(ix[6]), load_24_32(ix[7]) }; +#elif N == 8 + (void)load_24_32; + // The gather instruction here doesn't need any particular alignment, + // but the intrinsic takes a const int*. + const int* p4 = bit_pun(p); + I32 zero = { 0, 0, 0, 0, 0, 0, 0, 0}, + mask = {-1,-1,-1,-1, -1,-1,-1,-1}; + #if defined(__clang__) + U32 v = (U32)__builtin_ia32_gatherd_d256(zero, p4, 3*ix, mask, 1); + #elif defined(__GNUC__) + U32 v = (U32)__builtin_ia32_gathersiv8si(zero, p4, 3*ix, mask, 1); + #endif +#elif N == 16 + (void)load_24_32; + // The intrinsic is supposed to take const void* now, but it takes const int*, just like AVX2. + // And AVX-512 swapped the order of arguments. :/ + const int* p4 = bit_pun(p); + U32 v = (U32)_mm512_i32gather_epi32((__m512i)(3*ix), p4, 1); +#endif + + // Shift off the junk byte, leaving r,g,b in low 24 bits (and zero in the top 8). + return v >> 8; +} + +#if !defined(__arm__) + SI void gather_48(const uint8_t* p, I32 ix, U64* v) { + // As in gather_24(), with everything doubled. + p -= 2; + + // Load the i'th 48-bit value from p, and 2 extra bytes. + auto load_48_64 = [p](int i) { + return load(p + 6*i); + }; + + #if N == 1 + *v = load_48_64(ix); + #elif N == 4 + *v = U64{ + load_48_64(ix[0]), load_48_64(ix[1]), load_48_64(ix[2]), load_48_64(ix[3]), + }; + #elif N == 8 && !defined(USING_AVX2) + *v = U64{ + load_48_64(ix[0]), load_48_64(ix[1]), load_48_64(ix[2]), load_48_64(ix[3]), + load_48_64(ix[4]), load_48_64(ix[5]), load_48_64(ix[6]), load_48_64(ix[7]), + }; + #elif N == 8 + (void)load_48_64; + typedef int32_t __attribute__((vector_size(16))) Half_I32; + typedef long long __attribute__((vector_size(32))) Half_I64; + + // The gather instruction here doesn't need any particular alignment, + // but the intrinsic takes a const long long*. + const long long int* p8 = bit_pun(p); + + Half_I64 zero = { 0, 0, 0, 0}, + mask = {-1,-1,-1,-1}; + + ix *= 6; + Half_I32 ix_lo = { ix[0], ix[1], ix[2], ix[3] }, + ix_hi = { ix[4], ix[5], ix[6], ix[7] }; + + #if defined(__clang__) + Half_I64 lo = (Half_I64)__builtin_ia32_gatherd_q256(zero, p8, ix_lo, mask, 1), + hi = (Half_I64)__builtin_ia32_gatherd_q256(zero, p8, ix_hi, mask, 1); + #elif defined(__GNUC__) + Half_I64 lo = (Half_I64)__builtin_ia32_gathersiv4di(zero, p8, ix_lo, mask, 1), + hi = (Half_I64)__builtin_ia32_gathersiv4di(zero, p8, ix_hi, mask, 1); + #endif + store((char*)v + 0, lo); + store((char*)v + 32, hi); + #elif N == 16 + (void)load_48_64; + const long long int* p8 = bit_pun(p); + __m512i lo = _mm512_i32gather_epi64(_mm512_extracti32x8_epi32((__m512i)(6*ix), 0), p8, 1), + hi = _mm512_i32gather_epi64(_mm512_extracti32x8_epi32((__m512i)(6*ix), 1), p8, 1); + store((char*)v + 0, lo); + store((char*)v + 64, hi); + #endif + + *v >>= 16; + } +#endif + +SI F F_from_U8(U8 v) { + return cast(v) * (1/255.0f); +} + +SI F F_from_U16_BE(U16 v) { + // All 16-bit ICC values are big-endian, so we byte swap before converting to float. + // MSVC catches the "loss" of data here in the portable path, so we also make sure to mask. + U16 lo = (v >> 8), + hi = (v << 8) & 0xffff; + return cast(lo|hi) * (1/65535.0f); +} + +SI U16 U16_from_F(F v) { + // 65535 == inf in FP16, so promote to FP32 before converting. + return cast(cast>(v) * 65535 + 0.5f); +} + +SI F minus_1_ulp(F v) { + return bit_pun( bit_pun(v) - 1 ); +} + +SI F table(const skcms_Curve* curve, F v) { + // Clamp the input to [0,1], then scale to a table index. + F ix = max_(F0, min_(v, F1)) * (float)(curve->table_entries - 1); + + // We'll look up (equal or adjacent) entries at lo and hi, then lerp by t between the two. + I32 lo = cast( ix ), + hi = cast(minus_1_ulp(ix+1.0f)); + F t = ix - cast(lo); // i.e. the fractional part of ix. + + // TODO: can we load l and h simultaneously? Each entry in 'h' is either + // the same as in 'l' or adjacent. We have a rough idea that's it'd always be safe + // to read adjacent entries and perhaps underflow the table by a byte or two + // (it'd be junk, but always safe to read). Not sure how to lerp yet. + F l,h; + if (curve->table_8) { + l = F_from_U8(gather_8(curve->table_8, lo)); + h = F_from_U8(gather_8(curve->table_8, hi)); + } else { + l = F_from_U16_BE(gather_16(curve->table_16, lo)); + h = F_from_U16_BE(gather_16(curve->table_16, hi)); + } + return l + (h-l)*t; +} + +SI void sample_clut_8(const uint8_t* grid_8, I32 ix, F* r, F* g, F* b) { + U32 rgb = gather_24(grid_8, ix); + + *r = cast((rgb >> 0) & 0xff) * (1/255.0f); + *g = cast((rgb >> 8) & 0xff) * (1/255.0f); + *b = cast((rgb >> 16) & 0xff) * (1/255.0f); +} + +SI void sample_clut_8(const uint8_t* grid_8, I32 ix, F* r, F* g, F* b, F* a) { + // TODO: don't forget to optimize gather_32(). + U32 rgba = gather_32(grid_8, ix); + + *r = cast((rgba >> 0) & 0xff) * (1/255.0f); + *g = cast((rgba >> 8) & 0xff) * (1/255.0f); + *b = cast((rgba >> 16) & 0xff) * (1/255.0f); + *a = cast((rgba >> 24) & 0xff) * (1/255.0f); +} + +SI void sample_clut_16(const uint8_t* grid_16, I32 ix, F* r, F* g, F* b) { +#if defined(__arm__) + // This is up to 2x faster on 32-bit ARM than the #else-case fast path. + *r = F_from_U16_BE(gather_16(grid_16, 3*ix+0)); + *g = F_from_U16_BE(gather_16(grid_16, 3*ix+1)); + *b = F_from_U16_BE(gather_16(grid_16, 3*ix+2)); +#else + // This strategy is much faster for 64-bit builds, and fine for 32-bit x86 too. + U64 rgb; + gather_48(grid_16, ix, &rgb); + rgb = swap_endian_16x4(rgb); + + *r = cast((rgb >> 0) & 0xffff) * (1/65535.0f); + *g = cast((rgb >> 16) & 0xffff) * (1/65535.0f); + *b = cast((rgb >> 32) & 0xffff) * (1/65535.0f); +#endif +} + +SI void sample_clut_16(const uint8_t* grid_16, I32 ix, F* r, F* g, F* b, F* a) { + // TODO: gather_64()-based fast path? + *r = F_from_U16_BE(gather_16(grid_16, 4*ix+0)); + *g = F_from_U16_BE(gather_16(grid_16, 4*ix+1)); + *b = F_from_U16_BE(gather_16(grid_16, 4*ix+2)); + *a = F_from_U16_BE(gather_16(grid_16, 4*ix+3)); +} + +static void clut(uint32_t input_channels, uint32_t output_channels, + const uint8_t grid_points[4], const uint8_t* grid_8, const uint8_t* grid_16, + F* r, F* g, F* b, F* a) { + + const int dim = (int)input_channels; + assert (0 < dim && dim <= 4); + assert (output_channels == 3 || + output_channels == 4); + + // For each of these arrays, think foo[2*dim], but we use foo[8] since we know dim <= 4. + I32 index [8]; // Index contribution by dimension, first low from 0, then high from 4. + F weight[8]; // Weight for each contribution, again first low, then high. + + // O(dim) work first: calculate index,weight from r,g,b,a. + const F inputs[] = { *r,*g,*b,*a }; + for (int i = dim-1, stride = 1; i >= 0; i--) { + // x is where we logically want to sample the grid in the i-th dimension. + F x = inputs[i] * (float)(grid_points[i] - 1); + + // But we can't index at floats. lo and hi are the two integer grid points surrounding x. + I32 lo = cast( x ), // i.e. trunc(x) == floor(x) here. + hi = cast(minus_1_ulp(x+1.0f)); + // Notice how we fold in the accumulated stride across previous dimensions here. + index[i+0] = lo * stride; + index[i+4] = hi * stride; + stride *= grid_points[i]; + + // We'll interpolate between those two integer grid points by t. + F t = x - cast(lo); // i.e. fract(x) + weight[i+0] = 1-t; + weight[i+4] = t; + } + + *r = *g = *b = F0; + if (output_channels == 4) { + *a = F0; + } + + // We'll sample 2^dim == 1<input_channels, a2b->output_channels, + a2b->grid_points, a2b->grid_8, a2b->grid_16, + r,g,b,&a); +} +static void clut(const skcms_B2A* b2a, F* r, F* g, F* b, F* a) { + clut(b2a->input_channels, b2a->output_channels, + b2a->grid_points, b2a->grid_8, b2a->grid_16, + r,g,b,a); +} + +struct NoCtx {}; + +struct Ctx { + const void* fArg; + operator NoCtx() { return NoCtx{}; } + template operator T*() { return (const T*)fArg; } +}; + +#define STAGE_PARAMS(MAYBE_REF) SKCMS_MAYBE_UNUSED const char* src, \ + SKCMS_MAYBE_UNUSED char* dst, \ + SKCMS_MAYBE_UNUSED F MAYBE_REF r, \ + SKCMS_MAYBE_UNUSED F MAYBE_REF g, \ + SKCMS_MAYBE_UNUSED F MAYBE_REF b, \ + SKCMS_MAYBE_UNUSED F MAYBE_REF a, \ + SKCMS_MAYBE_UNUSED int i + +#if SKCMS_HAS_MUSTTAIL + + // Stages take a stage list, and each stage is responsible for tail-calling the next one. + // + // Unfortunately, we can't declare a StageFn as a function pointer which takes a pointer to + // another StageFn; declaring this leads to a circular dependency. To avoid this, StageFn is + // wrapped in a single-element `struct StageList` which we are able to forward-declare. + struct StageList; + using StageFn = void (*)(StageList stages, const void** ctx, STAGE_PARAMS()); + struct StageList { + const StageFn* fn; + }; + + #define DECLARE_STAGE(name, arg, CALL_NEXT) \ + SI void Exec_##name##_k(arg, STAGE_PARAMS(&)); \ + \ + SI void Exec_##name(StageList list, const void** ctx, STAGE_PARAMS()) { \ + Exec_##name##_k(Ctx{*ctx}, src, dst, r, g, b, a, i); \ + ++list.fn; ++ctx; \ + CALL_NEXT; \ + } \ + \ + SI void Exec_##name##_k(arg, STAGE_PARAMS(&)) + + #define STAGE(name, arg) \ + DECLARE_STAGE(name, arg, [[clang::musttail]] return (*list.fn)(list, ctx, src, dst, \ + r, g, b, a, i)) + + #define FINAL_STAGE(name, arg) \ + DECLARE_STAGE(name, arg, /* Stop executing stages and return to the caller. */) + +#else + + #define DECLARE_STAGE(name, arg) \ + SI void Exec_##name##_k(arg, STAGE_PARAMS(&)); \ + \ + SI void Exec_##name(const void* ctx, STAGE_PARAMS(&)) { \ + Exec_##name##_k(Ctx{ctx}, src, dst, r, g, b, a, i); \ + } \ + \ + SI void Exec_##name##_k(arg, STAGE_PARAMS(&)) + + #define STAGE(name, arg) DECLARE_STAGE(name, arg) + #define FINAL_STAGE(name, arg) DECLARE_STAGE(name, arg) + +#endif + +STAGE(load_a8, NoCtx) { + a = F_from_U8(load(src + 1*i)); +} + +STAGE(load_g8, NoCtx) { + r = g = b = F_from_U8(load(src + 1*i)); +} + +STAGE(load_4444, NoCtx) { + U16 abgr = load(src + 2*i); + + r = cast((abgr >> 12) & 0xf) * (1/15.0f); + g = cast((abgr >> 8) & 0xf) * (1/15.0f); + b = cast((abgr >> 4) & 0xf) * (1/15.0f); + a = cast((abgr >> 0) & 0xf) * (1/15.0f); +} + +STAGE(load_565, NoCtx) { + U16 rgb = load(src + 2*i); + + r = cast(rgb & (uint16_t)(31<< 0)) * (1.0f / (31<< 0)); + g = cast(rgb & (uint16_t)(63<< 5)) * (1.0f / (63<< 5)); + b = cast(rgb & (uint16_t)(31<<11)) * (1.0f / (31<<11)); +} + +STAGE(load_888, NoCtx) { + const uint8_t* rgb = (const uint8_t*)(src + 3*i); +#if defined(USING_NEON) + // There's no uint8x4x3_t or vld3 load for it, so we'll load each rgb pixel one at + // a time. Since we're doing that, we might as well load them into 16-bit lanes. + // (We'd even load into 32-bit lanes, but that's not possible on ARMv7.) + uint8x8x3_t v = {{ vdup_n_u8(0), vdup_n_u8(0), vdup_n_u8(0) }}; + v = vld3_lane_u8(rgb+0, v, 0); + v = vld3_lane_u8(rgb+3, v, 2); + v = vld3_lane_u8(rgb+6, v, 4); + v = vld3_lane_u8(rgb+9, v, 6); + + // Now if we squint, those 3 uint8x8_t we constructed are really U16s, easy to + // convert to F. (Again, U32 would be even better here if drop ARMv7 or split + // ARMv7 and ARMv8 impls.) + r = cast((U16)v.val[0]) * (1/255.0f); + g = cast((U16)v.val[1]) * (1/255.0f); + b = cast((U16)v.val[2]) * (1/255.0f); +#else + r = cast(load_3(rgb+0) ) * (1/255.0f); + g = cast(load_3(rgb+1) ) * (1/255.0f); + b = cast(load_3(rgb+2) ) * (1/255.0f); +#endif +} + +STAGE(load_8888, NoCtx) { + U32 rgba = load(src + 4*i); + + r = cast((rgba >> 0) & 0xff) * (1/255.0f); + g = cast((rgba >> 8) & 0xff) * (1/255.0f); + b = cast((rgba >> 16) & 0xff) * (1/255.0f); + a = cast((rgba >> 24) & 0xff) * (1/255.0f); +} + +STAGE(load_1010102, NoCtx) { + U32 rgba = load(src + 4*i); + + r = cast((rgba >> 0) & 0x3ff) * (1/1023.0f); + g = cast((rgba >> 10) & 0x3ff) * (1/1023.0f); + b = cast((rgba >> 20) & 0x3ff) * (1/1023.0f); + a = cast((rgba >> 30) & 0x3 ) * (1/ 3.0f); +} + +STAGE(load_101010x_XR, NoCtx) { + static constexpr float min = -0.752941f; + static constexpr float max = 1.25098f; + static constexpr float range = max - min; + U32 rgba = load(src + 4*i); + r = cast((rgba >> 0) & 0x3ff) * (1/1023.0f) * range + min; + g = cast((rgba >> 10) & 0x3ff) * (1/1023.0f) * range + min; + b = cast((rgba >> 20) & 0x3ff) * (1/1023.0f) * range + min; +} + +STAGE(load_10101010_XR, NoCtx) { + static constexpr float min = -0.752941f; + static constexpr float max = 1.25098f; + static constexpr float range = max - min; + U64 rgba = load(src + 8*i); + r = cast((rgba >> 0) & 0x3ff) * (1/1023.0f) * range + min; + g = cast((rgba >> 16) & 0x3ff) * (1/1023.0f) * range + min; + b = cast((rgba >> 32) & 0x3ff) * (1/1023.0f) * range + min; + a = cast((rgba >> 48) & 0x3ff) * (1/1023.0f) * range + min; +} + +STAGE(load_161616LE, NoCtx) { + uintptr_t ptr = (uintptr_t)(src + 6*i); + assert( (ptr & 1) == 0 ); // src must be 2-byte aligned for this + const uint16_t* rgb = (const uint16_t*)ptr; // cast to const uint16_t* to be safe. +#if defined(USING_NEON) + uint16x4x3_t v = vld3_u16(rgb); + r = cast((U16)v.val[0]) * (1/65535.0f); + g = cast((U16)v.val[1]) * (1/65535.0f); + b = cast((U16)v.val[2]) * (1/65535.0f); +#else + r = cast(load_3(rgb+0)) * (1/65535.0f); + g = cast(load_3(rgb+1)) * (1/65535.0f); + b = cast(load_3(rgb+2)) * (1/65535.0f); +#endif +} + +STAGE(load_16161616LE, NoCtx) { + uintptr_t ptr = (uintptr_t)(src + 8*i); + assert( (ptr & 1) == 0 ); // src must be 2-byte aligned for this + const uint16_t* rgba = (const uint16_t*)ptr; // cast to const uint16_t* to be safe. +#if defined(USING_NEON) + uint16x4x4_t v = vld4_u16(rgba); + r = cast((U16)v.val[0]) * (1/65535.0f); + g = cast((U16)v.val[1]) * (1/65535.0f); + b = cast((U16)v.val[2]) * (1/65535.0f); + a = cast((U16)v.val[3]) * (1/65535.0f); +#else + U64 px = load(rgba); + + r = cast((px >> 0) & 0xffff) * (1/65535.0f); + g = cast((px >> 16) & 0xffff) * (1/65535.0f); + b = cast((px >> 32) & 0xffff) * (1/65535.0f); + a = cast((px >> 48) & 0xffff) * (1/65535.0f); +#endif +} + +STAGE(load_161616BE, NoCtx) { + uintptr_t ptr = (uintptr_t)(src + 6*i); + assert( (ptr & 1) == 0 ); // src must be 2-byte aligned for this + const uint16_t* rgb = (const uint16_t*)ptr; // cast to const uint16_t* to be safe. +#if defined(USING_NEON) + uint16x4x3_t v = vld3_u16(rgb); + r = cast(swap_endian_16((U16)v.val[0])) * (1/65535.0f); + g = cast(swap_endian_16((U16)v.val[1])) * (1/65535.0f); + b = cast(swap_endian_16((U16)v.val[2])) * (1/65535.0f); +#else + U32 R = load_3(rgb+0), + G = load_3(rgb+1), + B = load_3(rgb+2); + // R,G,B are big-endian 16-bit, so byte swap them before converting to float. + r = cast((R & 0x00ff)<<8 | (R & 0xff00)>>8) * (1/65535.0f); + g = cast((G & 0x00ff)<<8 | (G & 0xff00)>>8) * (1/65535.0f); + b = cast((B & 0x00ff)<<8 | (B & 0xff00)>>8) * (1/65535.0f); +#endif +} + +STAGE(load_16161616BE, NoCtx) { + uintptr_t ptr = (uintptr_t)(src + 8*i); + assert( (ptr & 1) == 0 ); // src must be 2-byte aligned for this + const uint16_t* rgba = (const uint16_t*)ptr; // cast to const uint16_t* to be safe. +#if defined(USING_NEON) + uint16x4x4_t v = vld4_u16(rgba); + r = cast(swap_endian_16((U16)v.val[0])) * (1/65535.0f); + g = cast(swap_endian_16((U16)v.val[1])) * (1/65535.0f); + b = cast(swap_endian_16((U16)v.val[2])) * (1/65535.0f); + a = cast(swap_endian_16((U16)v.val[3])) * (1/65535.0f); +#else + U64 px = swap_endian_16x4(load(rgba)); + + r = cast((px >> 0) & 0xffff) * (1/65535.0f); + g = cast((px >> 16) & 0xffff) * (1/65535.0f); + b = cast((px >> 32) & 0xffff) * (1/65535.0f); + a = cast((px >> 48) & 0xffff) * (1/65535.0f); +#endif +} + +STAGE(load_hhh, NoCtx) { + uintptr_t ptr = (uintptr_t)(src + 6*i); + assert( (ptr & 1) == 0 ); // src must be 2-byte aligned for this + const uint16_t* rgb = (const uint16_t*)ptr; // cast to const uint16_t* to be safe. +#if defined(USING_NEON) + uint16x4x3_t v = vld3_u16(rgb); + U16 R = (U16)v.val[0], + G = (U16)v.val[1], + B = (U16)v.val[2]; +#else + U16 R = load_3(rgb+0), + G = load_3(rgb+1), + B = load_3(rgb+2); +#endif + r = F_from_Half(R); + g = F_from_Half(G); + b = F_from_Half(B); +} + +STAGE(load_hhhh, NoCtx) { + uintptr_t ptr = (uintptr_t)(src + 8*i); + assert( (ptr & 1) == 0 ); // src must be 2-byte aligned for this + const uint16_t* rgba = (const uint16_t*)ptr; // cast to const uint16_t* to be safe. +#if defined(USING_NEON) + uint16x4x4_t v = vld4_u16(rgba); + U16 R = (U16)v.val[0], + G = (U16)v.val[1], + B = (U16)v.val[2], + A = (U16)v.val[3]; +#else + U64 px = load(rgba); + U16 R = cast((px >> 0) & 0xffff), + G = cast((px >> 16) & 0xffff), + B = cast((px >> 32) & 0xffff), + A = cast((px >> 48) & 0xffff); +#endif + r = F_from_Half(R); + g = F_from_Half(G); + b = F_from_Half(B); + a = F_from_Half(A); +} + +STAGE(load_fff, NoCtx) { + uintptr_t ptr = (uintptr_t)(src + 12*i); + assert( (ptr & 3) == 0 ); // src must be 4-byte aligned for this + const float* rgb = (const float*)ptr; // cast to const float* to be safe. +#if defined(USING_NEON) + float32x4x3_t v = vld3q_f32(rgb); + r = (F)v.val[0]; + g = (F)v.val[1]; + b = (F)v.val[2]; +#else + r = load_3(rgb+0); + g = load_3(rgb+1); + b = load_3(rgb+2); +#endif +} + +STAGE(load_ffff, NoCtx) { + uintptr_t ptr = (uintptr_t)(src + 16*i); + assert( (ptr & 3) == 0 ); // src must be 4-byte aligned for this + const float* rgba = (const float*)ptr; // cast to const float* to be safe. +#if defined(USING_NEON) + float32x4x4_t v = vld4q_f32(rgba); + r = (F)v.val[0]; + g = (F)v.val[1]; + b = (F)v.val[2]; + a = (F)v.val[3]; +#else + r = load_4(rgba+0); + g = load_4(rgba+1); + b = load_4(rgba+2); + a = load_4(rgba+3); +#endif +} + +STAGE(swap_rb, NoCtx) { + F t = r; + r = b; + b = t; +} + +STAGE(clamp, NoCtx) { + r = max_(F0, min_(r, F1)); + g = max_(F0, min_(g, F1)); + b = max_(F0, min_(b, F1)); + a = max_(F0, min_(a, F1)); +} + +STAGE(invert, NoCtx) { + r = F1 - r; + g = F1 - g; + b = F1 - b; + a = F1 - a; +} + +STAGE(force_opaque, NoCtx) { + a = F1; +} + +STAGE(premul, NoCtx) { + r *= a; + g *= a; + b *= a; +} + +STAGE(unpremul, NoCtx) { + F scale = if_then_else(F1 / a < INFINITY_, F1 / a, F0); + r *= scale; + g *= scale; + b *= scale; +} + +STAGE(matrix_3x3, const skcms_Matrix3x3* matrix) { + const float* m = &matrix->vals[0][0]; + + F R = m[0]*r + m[1]*g + m[2]*b, + G = m[3]*r + m[4]*g + m[5]*b, + B = m[6]*r + m[7]*g + m[8]*b; + + r = R; + g = G; + b = B; +} + +STAGE(matrix_3x4, const skcms_Matrix3x4* matrix) { + const float* m = &matrix->vals[0][0]; + + F R = m[0]*r + m[1]*g + m[ 2]*b + m[ 3], + G = m[4]*r + m[5]*g + m[ 6]*b + m[ 7], + B = m[8]*r + m[9]*g + m[10]*b + m[11]; + + r = R; + g = G; + b = B; +} + +STAGE(lab_to_xyz, NoCtx) { + // The L*a*b values are in r,g,b, but normalized to [0,1]. Reconstruct them: + F L = r * 100.0f, + A = g * 255.0f - 128.0f, + B = b * 255.0f - 128.0f; + + // Convert to CIE XYZ. + F Y = (L + 16.0f) * (1/116.0f), + X = Y + A*(1/500.0f), + Z = Y - B*(1/200.0f); + + X = if_then_else(X*X*X > 0.008856f, X*X*X, (X - (16/116.0f)) * (1/7.787f)); + Y = if_then_else(Y*Y*Y > 0.008856f, Y*Y*Y, (Y - (16/116.0f)) * (1/7.787f)); + Z = if_then_else(Z*Z*Z > 0.008856f, Z*Z*Z, (Z - (16/116.0f)) * (1/7.787f)); + + // Adjust to XYZD50 illuminant, and stuff back into r,g,b for the next op. + r = X * 0.9642f; + g = Y ; + b = Z * 0.8249f; +} + +// As above, in reverse. +STAGE(xyz_to_lab, NoCtx) { + F X = r * (1/0.9642f), + Y = g, + Z = b * (1/0.8249f); + + X = if_then_else(X > 0.008856f, approx_pow(X, 1/3.0f), X*7.787f + (16/116.0f)); + Y = if_then_else(Y > 0.008856f, approx_pow(Y, 1/3.0f), Y*7.787f + (16/116.0f)); + Z = if_then_else(Z > 0.008856f, approx_pow(Z, 1/3.0f), Z*7.787f + (16/116.0f)); + + F L = Y*116.0f - 16.0f, + A = (X-Y)*500.0f, + B = (Y-Z)*200.0f; + + r = L * (1/100.f); + g = (A + 128.0f) * (1/255.0f); + b = (B + 128.0f) * (1/255.0f); +} + +STAGE(gamma_r, const skcms_TransferFunction* tf) { r = apply_gamma(tf, r); } +STAGE(gamma_g, const skcms_TransferFunction* tf) { g = apply_gamma(tf, g); } +STAGE(gamma_b, const skcms_TransferFunction* tf) { b = apply_gamma(tf, b); } +STAGE(gamma_a, const skcms_TransferFunction* tf) { a = apply_gamma(tf, a); } + +STAGE(gamma_rgb, const skcms_TransferFunction* tf) { + r = apply_gamma(tf, r); + g = apply_gamma(tf, g); + b = apply_gamma(tf, b); +} + +STAGE(tf_r, const skcms_TransferFunction* tf) { r = apply_tf(tf, r); } +STAGE(tf_g, const skcms_TransferFunction* tf) { g = apply_tf(tf, g); } +STAGE(tf_b, const skcms_TransferFunction* tf) { b = apply_tf(tf, b); } +STAGE(tf_a, const skcms_TransferFunction* tf) { a = apply_tf(tf, a); } + +STAGE(tf_rgb, const skcms_TransferFunction* tf) { + r = apply_tf(tf, r); + g = apply_tf(tf, g); + b = apply_tf(tf, b); +} + +STAGE(pq_r, const skcms_TransferFunction* tf) { r = apply_pq(tf, r); } +STAGE(pq_g, const skcms_TransferFunction* tf) { g = apply_pq(tf, g); } +STAGE(pq_b, const skcms_TransferFunction* tf) { b = apply_pq(tf, b); } +STAGE(pq_a, const skcms_TransferFunction* tf) { a = apply_pq(tf, a); } + +STAGE(pq_rgb, const skcms_TransferFunction* tf) { + r = apply_pq(tf, r); + g = apply_pq(tf, g); + b = apply_pq(tf, b); +} + +STAGE(hlg_r, const skcms_TransferFunction* tf) { r = apply_hlg(tf, r); } +STAGE(hlg_g, const skcms_TransferFunction* tf) { g = apply_hlg(tf, g); } +STAGE(hlg_b, const skcms_TransferFunction* tf) { b = apply_hlg(tf, b); } +STAGE(hlg_a, const skcms_TransferFunction* tf) { a = apply_hlg(tf, a); } + +STAGE(hlg_rgb, const skcms_TransferFunction* tf) { + r = apply_hlg(tf, r); + g = apply_hlg(tf, g); + b = apply_hlg(tf, b); +} + +STAGE(hlginv_r, const skcms_TransferFunction* tf) { r = apply_hlginv(tf, r); } +STAGE(hlginv_g, const skcms_TransferFunction* tf) { g = apply_hlginv(tf, g); } +STAGE(hlginv_b, const skcms_TransferFunction* tf) { b = apply_hlginv(tf, b); } +STAGE(hlginv_a, const skcms_TransferFunction* tf) { a = apply_hlginv(tf, a); } + +STAGE(hlginv_rgb, const skcms_TransferFunction* tf) { + r = apply_hlginv(tf, r); + g = apply_hlginv(tf, g); + b = apply_hlginv(tf, b); +} + +STAGE(table_r, const skcms_Curve* curve) { r = table(curve, r); } +STAGE(table_g, const skcms_Curve* curve) { g = table(curve, g); } +STAGE(table_b, const skcms_Curve* curve) { b = table(curve, b); } +STAGE(table_a, const skcms_Curve* curve) { a = table(curve, a); } + +STAGE(clut_A2B, const skcms_A2B* a2b) { + clut(a2b, &r,&g,&b,a); + + if (a2b->input_channels == 4) { + // CMYK is opaque. + a = F1; + } +} + +STAGE(clut_B2A, const skcms_B2A* b2a) { + clut(b2a, &r,&g,&b,&a); +} + +// From here on down, the store_ ops are all "final stages," terminating processing of this group. + +FINAL_STAGE(store_a8, NoCtx) { + store(dst + 1*i, cast(to_fixed(a * 255))); +} + +FINAL_STAGE(store_g8, NoCtx) { + // g should be holding luminance (Y) (r,g,b ~~~> X,Y,Z) + store(dst + 1*i, cast(to_fixed(g * 255))); +} + +FINAL_STAGE(store_4444, NoCtx) { + store(dst + 2*i, cast(to_fixed(r * 15) << 12) + | cast(to_fixed(g * 15) << 8) + | cast(to_fixed(b * 15) << 4) + | cast(to_fixed(a * 15) << 0)); +} + +FINAL_STAGE(store_565, NoCtx) { + store(dst + 2*i, cast(to_fixed(r * 31) << 0 ) + | cast(to_fixed(g * 63) << 5 ) + | cast(to_fixed(b * 31) << 11 )); +} + +FINAL_STAGE(store_888, NoCtx) { + uint8_t* rgb = (uint8_t*)dst + 3*i; +#if defined(USING_NEON) + // Same deal as load_888 but in reverse... we'll store using uint8x8x3_t, but + // get there via U16 to save some instructions converting to float. And just + // like load_888, we'd prefer to go via U32 but for ARMv7 support. + U16 R = cast(to_fixed(r * 255)), + G = cast(to_fixed(g * 255)), + B = cast(to_fixed(b * 255)); + + uint8x8x3_t v = {{ (uint8x8_t)R, (uint8x8_t)G, (uint8x8_t)B }}; + vst3_lane_u8(rgb+0, v, 0); + vst3_lane_u8(rgb+3, v, 2); + vst3_lane_u8(rgb+6, v, 4); + vst3_lane_u8(rgb+9, v, 6); +#else + store_3(rgb+0, cast(to_fixed(r * 255)) ); + store_3(rgb+1, cast(to_fixed(g * 255)) ); + store_3(rgb+2, cast(to_fixed(b * 255)) ); +#endif +} + +FINAL_STAGE(store_8888, NoCtx) { + store(dst + 4*i, cast(to_fixed(r * 255)) << 0 + | cast(to_fixed(g * 255)) << 8 + | cast(to_fixed(b * 255)) << 16 + | cast(to_fixed(a * 255)) << 24); +} + +FINAL_STAGE(store_101010x_XR, NoCtx) { + static constexpr float min = -0.752941f; + static constexpr float max = 1.25098f; + static constexpr float range = max - min; + store(dst + 4*i, cast(to_fixed(((r - min) / range) * 1023)) << 0 + | cast(to_fixed(((g - min) / range) * 1023)) << 10 + | cast(to_fixed(((b - min) / range) * 1023)) << 20); +} + +FINAL_STAGE(store_1010102, NoCtx) { + store(dst + 4*i, cast(to_fixed(r * 1023)) << 0 + | cast(to_fixed(g * 1023)) << 10 + | cast(to_fixed(b * 1023)) << 20 + | cast(to_fixed(a * 3)) << 30); +} + +FINAL_STAGE(store_161616LE, NoCtx) { + uintptr_t ptr = (uintptr_t)(dst + 6*i); + assert( (ptr & 1) == 0 ); // The dst pointer must be 2-byte aligned + uint16_t* rgb = (uint16_t*)ptr; // for this cast to uint16_t* to be safe. +#if defined(USING_NEON) + uint16x4x3_t v = {{ + (uint16x4_t)U16_from_F(r), + (uint16x4_t)U16_from_F(g), + (uint16x4_t)U16_from_F(b), + }}; + vst3_u16(rgb, v); +#else + store_3(rgb+0, U16_from_F(r)); + store_3(rgb+1, U16_from_F(g)); + store_3(rgb+2, U16_from_F(b)); +#endif + +} + +FINAL_STAGE(store_16161616LE, NoCtx) { + uintptr_t ptr = (uintptr_t)(dst + 8*i); + assert( (ptr & 1) == 0 ); // The dst pointer must be 2-byte aligned + uint16_t* rgba = (uint16_t*)ptr; // for this cast to uint16_t* to be safe. +#if defined(USING_NEON) + uint16x4x4_t v = {{ + (uint16x4_t)U16_from_F(r), + (uint16x4_t)U16_from_F(g), + (uint16x4_t)U16_from_F(b), + (uint16x4_t)U16_from_F(a), + }}; + vst4_u16(rgba, v); +#else + U64 px = cast(to_fixed(r * 65535)) << 0 + | cast(to_fixed(g * 65535)) << 16 + | cast(to_fixed(b * 65535)) << 32 + | cast(to_fixed(a * 65535)) << 48; + store(rgba, px); +#endif +} + +FINAL_STAGE(store_161616BE, NoCtx) { + uintptr_t ptr = (uintptr_t)(dst + 6*i); + assert( (ptr & 1) == 0 ); // The dst pointer must be 2-byte aligned + uint16_t* rgb = (uint16_t*)ptr; // for this cast to uint16_t* to be safe. +#if defined(USING_NEON) + uint16x4x3_t v = {{ + (uint16x4_t)swap_endian_16(cast(U16_from_F(r))), + (uint16x4_t)swap_endian_16(cast(U16_from_F(g))), + (uint16x4_t)swap_endian_16(cast(U16_from_F(b))), + }}; + vst3_u16(rgb, v); +#else + U32 R = to_fixed(r * 65535), + G = to_fixed(g * 65535), + B = to_fixed(b * 65535); + store_3(rgb+0, cast((R & 0x00ff) << 8 | (R & 0xff00) >> 8) ); + store_3(rgb+1, cast((G & 0x00ff) << 8 | (G & 0xff00) >> 8) ); + store_3(rgb+2, cast((B & 0x00ff) << 8 | (B & 0xff00) >> 8) ); +#endif + +} + +FINAL_STAGE(store_16161616BE, NoCtx) { + uintptr_t ptr = (uintptr_t)(dst + 8*i); + assert( (ptr & 1) == 0 ); // The dst pointer must be 2-byte aligned + uint16_t* rgba = (uint16_t*)ptr; // for this cast to uint16_t* to be safe. +#if defined(USING_NEON) + uint16x4x4_t v = {{ + (uint16x4_t)swap_endian_16(cast(U16_from_F(r))), + (uint16x4_t)swap_endian_16(cast(U16_from_F(g))), + (uint16x4_t)swap_endian_16(cast(U16_from_F(b))), + (uint16x4_t)swap_endian_16(cast(U16_from_F(a))), + }}; + vst4_u16(rgba, v); +#else + U64 px = cast(to_fixed(r * 65535)) << 0 + | cast(to_fixed(g * 65535)) << 16 + | cast(to_fixed(b * 65535)) << 32 + | cast(to_fixed(a * 65535)) << 48; + store(rgba, swap_endian_16x4(px)); +#endif +} + +FINAL_STAGE(store_hhh, NoCtx) { + uintptr_t ptr = (uintptr_t)(dst + 6*i); + assert( (ptr & 1) == 0 ); // The dst pointer must be 2-byte aligned + uint16_t* rgb = (uint16_t*)ptr; // for this cast to uint16_t* to be safe. + + U16 R = Half_from_F(r), + G = Half_from_F(g), + B = Half_from_F(b); +#if defined(USING_NEON) + uint16x4x3_t v = {{ + (uint16x4_t)R, + (uint16x4_t)G, + (uint16x4_t)B, + }}; + vst3_u16(rgb, v); +#else + store_3(rgb+0, R); + store_3(rgb+1, G); + store_3(rgb+2, B); +#endif +} + +FINAL_STAGE(store_hhhh, NoCtx) { + uintptr_t ptr = (uintptr_t)(dst + 8*i); + assert( (ptr & 1) == 0 ); // The dst pointer must be 2-byte aligned + uint16_t* rgba = (uint16_t*)ptr; // for this cast to uint16_t* to be safe. + + U16 R = Half_from_F(r), + G = Half_from_F(g), + B = Half_from_F(b), + A = Half_from_F(a); +#if defined(USING_NEON) + uint16x4x4_t v = {{ + (uint16x4_t)R, + (uint16x4_t)G, + (uint16x4_t)B, + (uint16x4_t)A, + }}; + vst4_u16(rgba, v); +#else + store(rgba, cast(R) << 0 + | cast(G) << 16 + | cast(B) << 32 + | cast(A) << 48); +#endif +} + +FINAL_STAGE(store_fff, NoCtx) { + uintptr_t ptr = (uintptr_t)(dst + 12*i); + assert( (ptr & 3) == 0 ); // The dst pointer must be 4-byte aligned + float* rgb = (float*)ptr; // for this cast to float* to be safe. +#if defined(USING_NEON) + float32x4x3_t v = {{ + (float32x4_t)r, + (float32x4_t)g, + (float32x4_t)b, + }}; + vst3q_f32(rgb, v); +#else + store_3(rgb+0, r); + store_3(rgb+1, g); + store_3(rgb+2, b); +#endif +} + +FINAL_STAGE(store_ffff, NoCtx) { + uintptr_t ptr = (uintptr_t)(dst + 16*i); + assert( (ptr & 3) == 0 ); // The dst pointer must be 4-byte aligned + float* rgba = (float*)ptr; // for this cast to float* to be safe. +#if defined(USING_NEON) + float32x4x4_t v = {{ + (float32x4_t)r, + (float32x4_t)g, + (float32x4_t)b, + (float32x4_t)a, + }}; + vst4q_f32(rgba, v); +#else + store_4(rgba+0, r); + store_4(rgba+1, g); + store_4(rgba+2, b); + store_4(rgba+3, a); +#endif +} + +#if SKCMS_HAS_MUSTTAIL + + SI void exec_stages(StageFn* stages, const void** contexts, const char* src, char* dst, int i) { + (*stages)({stages}, contexts, src, dst, F0, F0, F0, F1, i); + } + +#else + + static void exec_stages(const Op* ops, const void** contexts, + const char* src, char* dst, int i) { + F r = F0, g = F0, b = F0, a = F1; + while (true) { + switch (*ops++) { +#define M(name) case Op::name: Exec_##name(*contexts++, src, dst, r, g, b, a, i); break; + SKCMS_WORK_OPS(M) +#undef M +#define M(name) case Op::name: Exec_##name(*contexts++, src, dst, r, g, b, a, i); return; + SKCMS_STORE_OPS(M) +#undef M + } + } + } + +#endif + +// NOLINTNEXTLINE(misc-definitions-in-headers) +void run_program(const Op* program, const void** contexts, SKCMS_MAYBE_UNUSED ptrdiff_t programSize, + const char* src, char* dst, int n, + const size_t src_bpp, const size_t dst_bpp) { +#if SKCMS_HAS_MUSTTAIL + // Convert the program into an array of tailcall stages. + StageFn stages[32]; + assert(programSize <= ARRAY_COUNT(stages)); + + static constexpr StageFn kStageFns[] = { +#define M(name) &Exec_##name, + SKCMS_WORK_OPS(M) + SKCMS_STORE_OPS(M) +#undef M + }; + + for (ptrdiff_t index = 0; index < programSize; ++index) { + stages[index] = kStageFns[(int)program[index]]; + } +#else + // Use the op array as-is. + const Op* stages = program; +#endif + + int i = 0; + while (n >= N) { + exec_stages(stages, contexts, src, dst, i); + i += N; + n -= N; + } + if (n > 0) { + char tmp[4*4*N] = {0}; + + memcpy(tmp, (const char*)src + (size_t)i*src_bpp, (size_t)n*src_bpp); + exec_stages(stages, contexts, tmp, tmp, 0); + memcpy((char*)dst + (size_t)i*dst_bpp, tmp, (size_t)n*dst_bpp); + } +} diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/src/skcms_Transform.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/src/skcms_Transform.h new file mode 100644 index 0000000000..9f02e792fb --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/src/skcms_Transform.h @@ -0,0 +1,162 @@ +/* + * Copyright 2018 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#pragma once + +#include +#include + +// skcms_Transform.h contains skcms implementation details. +// Please don't use this header from outside the skcms repo. + +namespace skcms_private { + +/** All transform ops */ + +#define SKCMS_WORK_OPS(M) \ + M(load_a8) \ + M(load_g8) \ + M(load_4444) \ + M(load_565) \ + M(load_888) \ + M(load_8888) \ + M(load_1010102) \ + M(load_101010x_XR) \ + M(load_10101010_XR) \ + M(load_161616LE) \ + M(load_16161616LE) \ + M(load_161616BE) \ + M(load_16161616BE) \ + M(load_hhh) \ + M(load_hhhh) \ + M(load_fff) \ + M(load_ffff) \ + \ + M(swap_rb) \ + M(clamp) \ + M(invert) \ + M(force_opaque) \ + M(premul) \ + M(unpremul) \ + M(matrix_3x3) \ + M(matrix_3x4) \ + \ + M(lab_to_xyz) \ + M(xyz_to_lab) \ + \ + M(gamma_r) \ + M(gamma_g) \ + M(gamma_b) \ + M(gamma_a) \ + M(gamma_rgb) \ + \ + M(tf_r) \ + M(tf_g) \ + M(tf_b) \ + M(tf_a) \ + M(tf_rgb) \ + \ + M(pq_r) \ + M(pq_g) \ + M(pq_b) \ + M(pq_a) \ + M(pq_rgb) \ + \ + M(hlg_r) \ + M(hlg_g) \ + M(hlg_b) \ + M(hlg_a) \ + M(hlg_rgb) \ + \ + M(hlginv_r) \ + M(hlginv_g) \ + M(hlginv_b) \ + M(hlginv_a) \ + M(hlginv_rgb) \ + \ + M(table_r) \ + M(table_g) \ + M(table_b) \ + M(table_a) \ + \ + M(clut_A2B) \ + M(clut_B2A) + +#define SKCMS_STORE_OPS(M) \ + M(store_a8) \ + M(store_g8) \ + M(store_4444) \ + M(store_565) \ + M(store_888) \ + M(store_8888) \ + M(store_1010102) \ + M(store_161616LE) \ + M(store_16161616LE) \ + M(store_161616BE) \ + M(store_16161616BE) \ + M(store_101010x_XR) \ + M(store_hhh) \ + M(store_hhhh) \ + M(store_fff) \ + M(store_ffff) + +enum class Op : int { +#define M(op) op, + SKCMS_WORK_OPS(M) + SKCMS_STORE_OPS(M) +#undef M +}; + +/** Constants */ + +#if defined(__clang__) || defined(__GNUC__) + static constexpr float INFINITY_ = __builtin_inff(); +#else + static const union { + uint32_t bits; + float f; + } inf_ = { 0x7f800000 }; + #define INFINITY_ inf_.f +#endif + +/** Vector type */ + +#if defined(__clang__) + template using Vec = T __attribute__((ext_vector_type(N))); +#elif defined(__GNUC__) + // Unfortunately, GCC does not allow us to omit the struct. This will not compile: + // template using Vec = T __attribute__((vector_size(N*sizeof(T)))); + template struct VecHelper { + typedef T __attribute__((vector_size(N * sizeof(T)))) V; + }; + template using Vec = typename VecHelper::V; +#endif + +/** Interface */ + +namespace baseline { + +void run_program(const Op* program, const void** contexts, ptrdiff_t programSize, + const char* src, char* dst, int n, + const size_t src_bpp, const size_t dst_bpp); + +} +namespace hsw { + +void run_program(const Op* program, const void** contexts, ptrdiff_t programSize, + const char* src, char* dst, int n, + const size_t src_bpp, const size_t dst_bpp); + +} +namespace skx { + +void run_program(const Op* program, const void** contexts, ptrdiff_t programSize, + const char* src, char* dst, int n, + const size_t src_bpp, const size_t dst_bpp); + +} +} // namespace skcms_private diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/src/skcms_TransformBaseline.cc b/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/src/skcms_TransformBaseline.cc new file mode 100644 index 0000000000..bfe1df60a0 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/src/skcms_TransformBaseline.cc @@ -0,0 +1,48 @@ +/* + * Copyright 2018 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "skcms_public.h" // NO_G3_REWRITE +#include "skcms_internals.h" // NO_G3_REWRITE +#include "skcms_Transform.h" // NO_G3_REWRITE +#include +#include +#include +#include +#include + +#if defined(__ARM_NEON) + #include +#elif defined(__SSE__) + #include + + #if defined(__clang__) + // That #include is usually enough, but Clang's headers + // avoid #including the whole kitchen sink when _MSC_VER is defined, + // because lots of programs on Windows would include that and it'd be + // a lot slower. But we want all those headers included, so we can use + // their features (after making runtime checks). + #include + #endif +#endif + +namespace skcms_private { +namespace baseline { + +#if defined(SKCMS_PORTABLE) + // Build skcms in a portable scalar configuration. + #define N 1 + template using V = T; +#else + // Build skcms with basic four-line SIMD support. (SSE on Intel, or Neon on ARM) + #define N 4 + template using V = skcms_private::Vec; +#endif + +#include "Transform_inl.h" + +} // namespace baseline +} // namespace skcms_private diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/src/skcms_TransformHsw.cc b/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/src/skcms_TransformHsw.cc new file mode 100644 index 0000000000..cd3673b1b0 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/src/skcms_TransformHsw.cc @@ -0,0 +1,61 @@ +/* + * Copyright 2018 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "skcms_public.h" // NO_G3_REWRITE +#include "skcms_internals.h" // NO_G3_REWRITE +#include "skcms_Transform.h" // NO_G3_REWRITE +#include +#include +#include +#include +#include + +#if defined(__ARM_NEON) + #include +#elif defined(__SSE__) + #include + + #if defined(__clang__) + // That #include is usually enough, but Clang's headers + // avoid #including the whole kitchen sink when _MSC_VER is defined, + // because lots of programs on Windows would include that and it'd be + // a lot slower. But we want all those headers included, so we can use + // their features (after making runtime checks). + #include + #include + #include + #include + #include + #endif +#endif + +namespace skcms_private { +namespace hsw { + +#if defined(SKCMS_DISABLE_HSW) + +void run_program(const Op* program, const void** contexts, ptrdiff_t programSize, + const char* src, char* dst, int n, + const size_t src_bpp, const size_t dst_bpp) { + skcms_private::baseline::run_program(program, contexts, programSize, + src, dst, n, src_bpp, dst_bpp); +} + +#else + +#define USING_AVX +#define USING_AVX_F16C +#define USING_AVX2 +#define N 8 +template using V = skcms_private::Vec; + +#include "Transform_inl.h" + +#endif + +} // namespace hsw +} // namespace skcms_private diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/src/skcms_TransformSkx.cc b/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/src/skcms_TransformSkx.cc new file mode 100644 index 0000000000..3e849dd4ec --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/src/skcms_TransformSkx.cc @@ -0,0 +1,58 @@ +/* + * Copyright 2018 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "skcms_public.h" // NO_G3_REWRITE +#include "skcms_internals.h" // NO_G3_REWRITE +#include "skcms_Transform.h" // NO_G3_REWRITE +#include +#include +#include +#include +#include + +#if defined(__ARM_NEON) + #include +#elif defined(__SSE__) + #include + + #if defined(__clang__) + // That #include is usually enough, but Clang's headers + // avoid #including the whole kitchen sink when _MSC_VER is defined, + // because lots of programs on Windows would include that and it'd be + // a lot slower. But we want all those headers included, so we can use + // their features (after making runtime checks). + #include + #include + #include + #include + #include + #endif +#endif + +namespace skcms_private { +namespace skx { + +#if defined(SKCMS_DISABLE_SKX) + +void run_program(const Op* program, const void** contexts, ptrdiff_t programSize, + const char* src, char* dst, int n, + const size_t src_bpp, const size_t dst_bpp) { + skcms_private::baseline::run_program(program, contexts, programSize, + src, dst, n, src_bpp, dst_bpp); +} + +#else + +#define USING_AVX512F +#define N 16 +template using V = skcms_private::Vec; +#include "Transform_inl.h" + +#endif + +} // namespace skx +} // namespace skcms_private diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/src/skcms_internals.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/src/skcms_internals.h new file mode 100644 index 0000000000..f3f0a2d6cb --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/src/skcms_internals.h @@ -0,0 +1,138 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#pragma once + +// skcms_internals.h contains APIs shared by skcms' internals and its test tools. +// Please don't use this header from outside the skcms repo. + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// ~~~~ General Helper Macros ~~~~ +// skcms can leverage some C++ extensions when they are present. +#define ARRAY_COUNT(arr) (int)(sizeof((arr)) / sizeof(*(arr))) + +#if defined(__clang__) && defined(__has_cpp_attribute) + #if __has_cpp_attribute(clang::fallthrough) + #define SKCMS_FALLTHROUGH [[clang::fallthrough]] + #endif + + #ifndef SKCMS_HAS_MUSTTAIL + // [[clang::musttail]] is great for performance, but it's not well supported and we run into + // a variety of problems when we use it. Fortunately, it's an optional feature that doesn't + // affect correctness, and usually the compiler will generate a tail-call even for us + // whether or not we force it to do so. + // + // Known limitations: + // - Sanitizers do not work well with [[clang::musttail]], and corrupt src/dst pointers. + // (https://github.com/llvm/llvm-project/issues/70849) + // - Wasm tail-calls were only introduced in 2023 and aren't a mainstream feature yet. + // - Clang 18 runs into an ICE on armv7/androideabi with [[clang::musttail]]. + // (http://crbug.com/1504548) + // - Android RISC-V also runs into an ICE (b/314692534) + // - LoongArch developers indicate they had to turn it off + // - Windows builds generate incorrect code with [[clang::musttail]] and crash mysteriously. + // (http://crbug.com/1505442) + #if __has_cpp_attribute(clang::musttail) && !__has_feature(memory_sanitizer) \ + && !__has_feature(address_sanitizer) \ + && !defined(__EMSCRIPTEN__) \ + && !defined(__arm__) \ + && !defined(__riscv) \ + && !defined(__loongarch__) \ + && !defined(_WIN32) && !defined(__SYMBIAN32__) + #define SKCMS_HAS_MUSTTAIL 1 + #endif + #endif +#endif + +#ifndef SKCMS_FALLTHROUGH + #define SKCMS_FALLTHROUGH +#endif +#ifndef SKCMS_HAS_MUSTTAIL + #define SKCMS_HAS_MUSTTAIL 0 +#endif + +#if defined(__clang__) + #define SKCMS_MAYBE_UNUSED __attribute__((unused)) + #pragma clang diagnostic ignored "-Wused-but-marked-unused" +#elif defined(__GNUC__) + #define SKCMS_MAYBE_UNUSED __attribute__((unused)) +#elif defined(_MSC_VER) + #define SKCMS_MAYBE_UNUSED __pragma(warning(suppress:4100)) +#else + #define SKCMS_MAYBE_UNUSED +#endif + +// sizeof(x) will return size_t, which is 32-bit on some machines and 64-bit on others. +// We have better testing on 64-bit machines, so force 32-bit machines to behave like 64-bit. +// +// Please do not use sizeof() directly, and size_t only when required. +// (We have no way of enforcing these requests...) +#define SAFE_SIZEOF(x) ((uint64_t)sizeof(x)) + +// Same sort of thing for _Layout structs with a variable sized array at the end (named "variable"). +#define SAFE_FIXED_SIZE(type) ((uint64_t)offsetof(type, variable)) + +// If this isn't Clang, GCC, or Emscripten with SIMD support, we are in SKCMS_PORTABLE mode. +#if !defined(SKCMS_PORTABLE) && !(defined(__clang__) || \ + defined(__GNUC__) || \ + (defined(__EMSCRIPTEN__) && defined(__wasm_simd128__))) + #define SKCMS_PORTABLE 1 +#endif + +// If we are in SKCMS_PORTABLE mode or running on a non-x86-64 platform, we can't enable HSW or SKX. +// We also disable HSW/SKX on Android, even if it's Android on x64, since it's unlikely to benefit. +#if defined(SKCMS_PORTABLE) || !defined(__x86_64__) || defined(ANDROID) || defined(__ANDROID__) + #undef SKCMS_FORCE_HSW + #if !defined(SKCMS_DISABLE_HSW) + #define SKCMS_DISABLE_HSW 1 + #endif + + #undef SKCMS_FORCE_SKX + #if !defined(SKCMS_DISABLE_SKX) + #define SKCMS_DISABLE_SKX 1 + #endif +#endif + +// ~~~~ Shared ~~~~ +typedef struct skcms_ICCTag { + uint32_t signature; + uint32_t type; + uint32_t size; + const uint8_t* buf; +} skcms_ICCTag; + +typedef struct skcms_ICCProfile skcms_ICCProfile; +typedef struct skcms_TransferFunction skcms_TransferFunction; +typedef union skcms_Curve skcms_Curve; + +void skcms_GetTagByIndex (const skcms_ICCProfile*, uint32_t idx, skcms_ICCTag*); +bool skcms_GetTagBySignature(const skcms_ICCProfile*, uint32_t sig, skcms_ICCTag*); + +float skcms_MaxRoundtripError(const skcms_Curve* curve, const skcms_TransferFunction* inv_tf); + +// 252 of a random shuffle of all possible bytes. +// 252 is evenly divisible by 3 and 4. Only 192, 10, 241, and 43 are missing. +// Used for ICC profile equivalence testing. +extern const uint8_t skcms_252_random_bytes[252]; + +// ~~~~ Portable Math ~~~~ +static inline float floorf_(float x) { + float roundtrip = (float)((int)x); + return roundtrip > x ? roundtrip - 1 : roundtrip; +} +static inline float fabsf_(float x) { return x < 0 ? -x : x; } +float powf_(float, float); + +#ifdef __cplusplus +} +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/src/skcms_public.h b/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/src/skcms_public.h new file mode 100644 index 0000000000..3510f89ef8 --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/src/skcms_public.h @@ -0,0 +1,406 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#pragma once + +// skcms_public.h contains the entire public API for skcms. + +#ifndef SKCMS_API + #define SKCMS_API +#endif + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// A row-major 3x3 matrix (ie vals[row][col]) +typedef struct skcms_Matrix3x3 { + float vals[3][3]; +} skcms_Matrix3x3; + +// It is _not_ safe to alias the pointers to invert in-place. +SKCMS_API bool skcms_Matrix3x3_invert(const skcms_Matrix3x3*, skcms_Matrix3x3*); +SKCMS_API skcms_Matrix3x3 skcms_Matrix3x3_concat(const skcms_Matrix3x3*, const skcms_Matrix3x3*); + +// A row-major 3x4 matrix (ie vals[row][col]) +typedef struct skcms_Matrix3x4 { + float vals[3][4]; +} skcms_Matrix3x4; + +// A transfer function mapping encoded values to linear values, +// represented by this 7-parameter piecewise function: +// +// linear = sign(encoded) * (c*|encoded| + f) , 0 <= |encoded| < d +// = sign(encoded) * ((a*|encoded| + b)^g + e), d <= |encoded| +// +// (A simple gamma transfer function sets g to gamma and a to 1.) +typedef struct skcms_TransferFunction { + float g, a,b,c,d,e,f; +} skcms_TransferFunction; + +SKCMS_API float skcms_TransferFunction_eval (const skcms_TransferFunction*, float); +SKCMS_API bool skcms_TransferFunction_invert(const skcms_TransferFunction*, + skcms_TransferFunction*); + +typedef enum skcms_TFType { + skcms_TFType_Invalid, + skcms_TFType_sRGBish, + skcms_TFType_PQish, + skcms_TFType_HLGish, + skcms_TFType_HLGinvish, +} skcms_TFType; + +// Identify which kind of transfer function is encoded in an skcms_TransferFunction +SKCMS_API skcms_TFType skcms_TransferFunction_getType(const skcms_TransferFunction*); + +// We can jam a couple alternate transfer function forms into skcms_TransferFunction, +// including those matching the general forms of the SMPTE ST 2084 PQ function or HLG. +// +// PQish: +// max(A + B|encoded|^C, 0) +// linear = sign(encoded) * (------------------------) ^ F +// D + E|encoded|^C +SKCMS_API bool skcms_TransferFunction_makePQish(skcms_TransferFunction*, + float A, float B, float C, + float D, float E, float F); +// HLGish: +// { K * sign(encoded) * ( (R|encoded|)^G ) when 0 <= |encoded| <= 1/R +// linear = { K * sign(encoded) * ( e^(a(|encoded|-c)) + b ) when 1/R < |encoded| +SKCMS_API bool skcms_TransferFunction_makeScaledHLGish(skcms_TransferFunction*, + float K, float R, float G, + float a, float b, float c); + +// Compatibility shim with K=1 for old callers. +static inline bool skcms_TransferFunction_makeHLGish(skcms_TransferFunction* fn, + float R, float G, + float a, float b, float c) { + return skcms_TransferFunction_makeScaledHLGish(fn, 1.0f, R,G, a,b,c); +} + +// PQ mapping encoded [0,1] to linear [0,1]. +static inline bool skcms_TransferFunction_makePQ(skcms_TransferFunction* tf) { + return skcms_TransferFunction_makePQish(tf, -107/128.0f, 1.0f, 32/2523.0f + , 2413/128.0f, -2392/128.0f, 8192/1305.0f); +} +// HLG mapping encoded [0,1] to linear [0,12]. +static inline bool skcms_TransferFunction_makeHLG(skcms_TransferFunction* tf) { + return skcms_TransferFunction_makeHLGish(tf, 2.0f, 2.0f + , 1/0.17883277f, 0.28466892f, 0.55991073f); +} + +// Is this an ordinary sRGB-ish transfer function, or one of the HDR forms we support? +SKCMS_API bool skcms_TransferFunction_isSRGBish(const skcms_TransferFunction*); +SKCMS_API bool skcms_TransferFunction_isPQish (const skcms_TransferFunction*); +SKCMS_API bool skcms_TransferFunction_isHLGish (const skcms_TransferFunction*); + +// Unified representation of 'curv' or 'para' tag data, or a 1D table from 'mft1' or 'mft2' +typedef union skcms_Curve { + struct { + uint32_t alias_of_table_entries; + skcms_TransferFunction parametric; + }; + struct { + uint32_t table_entries; + const uint8_t* table_8; + const uint8_t* table_16; + }; +} skcms_Curve; + +// Complex transforms between device space (A) and profile connection space (B): +// A2B: device -> [ "A" curves -> CLUT ] -> [ "M" curves -> matrix ] -> "B" curves -> PCS +// B2A: device <- [ "A" curves <- CLUT ] <- [ "M" curves <- matrix ] <- "B" curves <- PCS + +typedef struct skcms_A2B { + // Optional: N 1D "A" curves, followed by an N-dimensional CLUT. + // If input_channels == 0, these curves and CLUT are skipped, + // Otherwise, input_channels must be in [1, 4]. + uint32_t input_channels; + skcms_Curve input_curves[4]; + uint8_t grid_points[4]; + const uint8_t* grid_8; + const uint8_t* grid_16; + + // Optional: 3 1D "M" curves, followed by a color matrix. + // If matrix_channels == 0, these curves and matrix are skipped, + // Otherwise, matrix_channels must be 3. + uint32_t matrix_channels; + skcms_Curve matrix_curves[3]; + skcms_Matrix3x4 matrix; + + // Required: 3 1D "B" curves. Always present, and output_channels must be 3. + uint32_t output_channels; + skcms_Curve output_curves[3]; +} skcms_A2B; + +typedef struct skcms_B2A { + // Required: 3 1D "B" curves. Always present, and input_channels must be 3. + uint32_t input_channels; + skcms_Curve input_curves[3]; + + // Optional: a color matrix, followed by 3 1D "M" curves. + // If matrix_channels == 0, this matrix and these curves are skipped, + // Otherwise, matrix_channels must be 3. + uint32_t matrix_channels; + skcms_Matrix3x4 matrix; + skcms_Curve matrix_curves[3]; + + // Optional: an N-dimensional CLUT, followed by N 1D "A" curves. + // If output_channels == 0, this CLUT and these curves are skipped, + // Otherwise, output_channels must be in [1, 4]. + uint32_t output_channels; + uint8_t grid_points[4]; + const uint8_t* grid_8; + const uint8_t* grid_16; + skcms_Curve output_curves[4]; +} skcms_B2A; + +typedef struct skcms_CICP { + uint8_t color_primaries; + uint8_t transfer_characteristics; + uint8_t matrix_coefficients; + uint8_t video_full_range_flag; +} skcms_CICP; + +typedef struct skcms_ICCProfile { + const uint8_t* buffer; + + uint32_t size; + uint32_t data_color_space; + uint32_t pcs; + uint32_t tag_count; + + // skcms_Parse() will set commonly-used fields for you when possible: + + // If we can parse red, green and blue transfer curves from the profile, + // trc will be set to those three curves, and has_trc will be true. + bool has_trc; + skcms_Curve trc[3]; + + // If this profile's gamut can be represented by a 3x3 transform to XYZD50, + // skcms_Parse() sets toXYZD50 to that transform and has_toXYZD50 to true. + bool has_toXYZD50; + skcms_Matrix3x3 toXYZD50; + + // If the profile has a valid A2B0 or A2B1 tag, skcms_Parse() sets A2B to + // that data, and has_A2B to true. skcms_ParseWithA2BPriority() does the + // same following any user-provided prioritization of A2B0, A2B1, or A2B2. + bool has_A2B; + skcms_A2B A2B; + + // If the profile has a valid B2A0 or B2A1 tag, skcms_Parse() sets B2A to + // that data, and has_B2A to true. skcms_ParseWithA2BPriority() does the + // same following any user-provided prioritization of B2A0, B2A1, or B2A2. + bool has_B2A; + skcms_B2A B2A; + + // If the profile has a valid CICP tag, skcms_Parse() sets CICP to that data, + // and has_CICP to true. + bool has_CICP; + skcms_CICP CICP; +} skcms_ICCProfile; + +// The sRGB color profile is so commonly used that we offer a canonical skcms_ICCProfile for it. +SKCMS_API const skcms_ICCProfile* skcms_sRGB_profile(void); +// Ditto for XYZD50, the most common profile connection space. +SKCMS_API const skcms_ICCProfile* skcms_XYZD50_profile(void); + +SKCMS_API const skcms_TransferFunction* skcms_sRGB_TransferFunction(void); +SKCMS_API const skcms_TransferFunction* skcms_sRGB_Inverse_TransferFunction(void); +SKCMS_API const skcms_TransferFunction* skcms_Identity_TransferFunction(void); + +// Practical equality test for two skcms_ICCProfiles. +// The implementation is subject to change, but it will always try to answer +// "can I substitute A for B?" and "can I skip transforming from A to B?". +SKCMS_API bool skcms_ApproximatelyEqualProfiles(const skcms_ICCProfile* A, + const skcms_ICCProfile* B); + +// Practical test that answers: Is curve roughly the inverse of inv_tf? Typically used by passing +// the inverse of a known parametric transfer function (like sRGB), to determine if a particular +// curve is very close to sRGB. +SKCMS_API bool skcms_AreApproximateInverses(const skcms_Curve* curve, + const skcms_TransferFunction* inv_tf); + +// Similar to above, answering the question for all three TRC curves of the given profile. Again, +// passing skcms_sRGB_InverseTransferFunction as inv_tf will answer the question: +// "Does this profile have a transfer function that is very close to sRGB?" +SKCMS_API bool skcms_TRCs_AreApproximateInverse(const skcms_ICCProfile* profile, + const skcms_TransferFunction* inv_tf); + +// Parse an ICC profile and return true if possible, otherwise return false. +// Selects an A2B profile (if present) according to priority list (each entry 0-2). +// The buffer is not copied; it must remain valid as long as the skcms_ICCProfile will be used. +SKCMS_API bool skcms_ParseWithA2BPriority(const void*, size_t, + const int priority[], int priorities, + skcms_ICCProfile*); + +static inline bool skcms_Parse(const void* buf, size_t len, skcms_ICCProfile* profile) { + // For continuity of existing user expectations, + // prefer A2B0 (perceptual) over A2B1 (relative colormetric), and ignore A2B2 (saturation). + const int priority[] = {0,1}; + return skcms_ParseWithA2BPriority(buf, len, + priority, sizeof(priority)/sizeof(*priority), + profile); +} + +SKCMS_API bool skcms_ApproximateCurve(const skcms_Curve* curve, + skcms_TransferFunction* approx, + float* max_error); + +SKCMS_API bool skcms_GetCHAD(const skcms_ICCProfile*, skcms_Matrix3x3*); +SKCMS_API bool skcms_GetWTPT(const skcms_ICCProfile*, float xyz[3]); + +// These are common ICC signature values +enum { + // data_color_space + skcms_Signature_CMYK = 0x434D594B, + skcms_Signature_Gray = 0x47524159, + skcms_Signature_RGB = 0x52474220, + + // pcs + skcms_Signature_Lab = 0x4C616220, + skcms_Signature_XYZ = 0x58595A20, +}; + +typedef enum skcms_PixelFormat { + skcms_PixelFormat_A_8, + skcms_PixelFormat_A_8_, + skcms_PixelFormat_G_8, + skcms_PixelFormat_G_8_, + + skcms_PixelFormat_RGB_565, + skcms_PixelFormat_BGR_565, + + skcms_PixelFormat_ABGR_4444, + skcms_PixelFormat_ARGB_4444, + + skcms_PixelFormat_RGB_888, + skcms_PixelFormat_BGR_888, + skcms_PixelFormat_RGBA_8888, + skcms_PixelFormat_BGRA_8888, + skcms_PixelFormat_RGBA_8888_sRGB, // Automatic sRGB encoding / decoding. + skcms_PixelFormat_BGRA_8888_sRGB, // (Generally used with linear transfer functions.) + + skcms_PixelFormat_RGBA_1010102, + skcms_PixelFormat_BGRA_1010102, + + skcms_PixelFormat_RGB_161616LE, // Little-endian. Pointers must be 16-bit aligned. + skcms_PixelFormat_BGR_161616LE, + skcms_PixelFormat_RGBA_16161616LE, + skcms_PixelFormat_BGRA_16161616LE, + + skcms_PixelFormat_RGB_161616BE, // Big-endian. Pointers must be 16-bit aligned. + skcms_PixelFormat_BGR_161616BE, + skcms_PixelFormat_RGBA_16161616BE, + skcms_PixelFormat_BGRA_16161616BE, + + skcms_PixelFormat_RGB_hhh_Norm, // 1-5-10 half-precision float in [0,1] + skcms_PixelFormat_BGR_hhh_Norm, // Pointers must be 16-bit aligned. + skcms_PixelFormat_RGBA_hhhh_Norm, + skcms_PixelFormat_BGRA_hhhh_Norm, + + skcms_PixelFormat_RGB_hhh, // 1-5-10 half-precision float. + skcms_PixelFormat_BGR_hhh, // Pointers must be 16-bit aligned. + skcms_PixelFormat_RGBA_hhhh, + skcms_PixelFormat_BGRA_hhhh, + + skcms_PixelFormat_RGB_fff, // 1-8-23 single-precision float (the normal kind). + skcms_PixelFormat_BGR_fff, // Pointers must be 32-bit aligned. + skcms_PixelFormat_RGBA_ffff, + skcms_PixelFormat_BGRA_ffff, + + skcms_PixelFormat_RGB_101010x_XR, // Note: This is located here to signal no clamping. + skcms_PixelFormat_BGR_101010x_XR, // Compatible with MTLPixelFormatBGR10_XR. + skcms_PixelFormat_RGBA_10101010_XR, // Note: This is located here to signal no clamping. + skcms_PixelFormat_BGRA_10101010_XR, // Compatible with MTLPixelFormatBGRA10_XR. +} skcms_PixelFormat; + +// We always store any alpha channel linearly. In the chart below, tf-1() is the inverse +// transfer function for the given color profile (applying the transfer function linearizes). + +// We treat opaque as a strong requirement, not just a performance hint: we will ignore +// any source alpha and treat it as 1.0, and will make sure that any destination alpha +// channel is filled with the equivalent of 1.0. + +// We used to offer multiple types of premultiplication, but now just one, PremulAsEncoded. +// This is the premul you're probably used to working with. + +typedef enum skcms_AlphaFormat { + skcms_AlphaFormat_Opaque, // alpha is always opaque + // tf-1(r), tf-1(g), tf-1(b), 1.0 + skcms_AlphaFormat_Unpremul, // alpha and color are unassociated + // tf-1(r), tf-1(g), tf-1(b), a + skcms_AlphaFormat_PremulAsEncoded, // premultiplied while encoded + // tf-1(r)*a, tf-1(g)*a, tf-1(b)*a, a +} skcms_AlphaFormat; + +// Convert npixels pixels from src format and color profile to dst format and color profile +// and return true, otherwise return false. It is safe to alias dst == src if dstFmt == srcFmt. +SKCMS_API bool skcms_Transform(const void* src, + skcms_PixelFormat srcFmt, + skcms_AlphaFormat srcAlpha, + const skcms_ICCProfile* srcProfile, + void* dst, + skcms_PixelFormat dstFmt, + skcms_AlphaFormat dstAlpha, + const skcms_ICCProfile* dstProfile, + size_t npixels); + +// If profile can be used as a destination in skcms_Transform, return true. Otherwise, attempt to +// rewrite it with approximations where reasonable. If successful, return true. If no reasonable +// approximation exists, leave the profile unchanged and return false. +SKCMS_API bool skcms_MakeUsableAsDestination(skcms_ICCProfile* profile); + +// If profile can be used as a destination with a single parametric transfer function (ie for +// rasterization), return true. Otherwise, attempt to rewrite it with approximations where +// reasonable. If successful, return true. If no reasonable approximation exists, leave the +// profile unchanged and return false. +SKCMS_API bool skcms_MakeUsableAsDestinationWithSingleCurve(skcms_ICCProfile* profile); + +// Returns a matrix to adapt XYZ color from given the whitepoint to D50. +SKCMS_API bool skcms_AdaptToXYZD50(float wx, float wy, + skcms_Matrix3x3* toXYZD50); + +// Returns a matrix to convert RGB color into XYZ adapted to D50, given the +// primaries and whitepoint of the RGB model. +SKCMS_API bool skcms_PrimariesToXYZD50(float rx, float ry, + float gx, float gy, + float bx, float by, + float wx, float wy, + skcms_Matrix3x3* toXYZD50); + +// Call before your first call to skcms_Transform() to skip runtime CPU detection. +SKCMS_API void skcms_DisableRuntimeCPUDetection(void); + +// Utilities for programmatically constructing profiles +static inline void skcms_Init(skcms_ICCProfile* p) { + memset(p, 0, sizeof(*p)); + p->data_color_space = skcms_Signature_RGB; + p->pcs = skcms_Signature_XYZ; +} + +static inline void skcms_SetTransferFunction(skcms_ICCProfile* p, + const skcms_TransferFunction* tf) { + p->has_trc = true; + for (int i = 0; i < 3; ++i) { + p->trc[i].table_entries = 0; + p->trc[i].parametric = *tf; + } +} + +static inline void skcms_SetXYZD50(skcms_ICCProfile* p, const skcms_Matrix3x3* m) { + p->has_toXYZD50 = true; + p->toXYZD50 = *m; +} + +#ifdef __cplusplus +} +#endif diff --git a/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/version.sha1 b/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/version.sha1 new file mode 100755 index 0000000000..aac43a8c6e --- /dev/null +++ b/Tests/LottieMetalTest/skia/PublicHeaders/skia/modules/skcms/version.sha1 @@ -0,0 +1 @@ +5d9221d28f9cbbe6db0b745b36d4e5efc09e168e diff --git a/Tests/LottieMetalTest/skia/libskia.framework/Info.plist b/Tests/LottieMetalTest/skia/libskia.framework/Info.plist new file mode 100644 index 0000000000..ac23c3e15d Binary files /dev/null and b/Tests/LottieMetalTest/skia/libskia.framework/Info.plist differ diff --git a/Tests/LottieMetalTest/skia/libskia.framework/libskia b/Tests/LottieMetalTest/skia/libskia.framework/libskia new file mode 100755 index 0000000000..a3688204a9 Binary files /dev/null and b/Tests/LottieMetalTest/skia/libskia.framework/libskia differ diff --git a/submodules/LottieCpp/lottiecpp b/submodules/LottieCpp/lottiecpp index b73dee6ff8..d32a4afe5e 160000 --- a/submodules/LottieCpp/lottiecpp +++ b/submodules/LottieCpp/lottiecpp @@ -1 +1 @@ -Subproject commit b73dee6ff8bfcb9ae5d45baa2fcd386930d19141 +Subproject commit d32a4afe5e196ab22a9e11b9b0318091f10e2707