diff --git a/lib/stub_ui/lib/painting.dart b/lib/stub_ui/lib/painting.dart index 22312ae0281d5..acfe007f437f5 100644 --- a/lib/stub_ui/lib/painting.dart +++ b/lib/stub_ui/lib/painting.dart @@ -1318,6 +1318,7 @@ class Paint { /// /// * [Gradient], a shader that paints a color gradient. /// * [ImageShader], a shader that tiles an [Image]. + /// * [PictureShader], a shader that tiles a [Picture]. /// * [colorFilter], which overrides [shader]. /// * [color], which is used if [shader] and [colorFilter] are null. Shader get shader { @@ -2669,6 +2670,13 @@ class ImageShader extends Shader { super._(); } +/// A shader (as used by [Paint.shader]) that tiles a picture. +class PictureShader extends Shader { + /// This class is created by the engine, and should not be instantiated + /// or extended directly. + PictureShader._() : super._(); +} + /// Defines how a list of points is interpreted when drawing a set of triangles. /// /// Used by [Canvas.drawVertices]. @@ -3312,6 +3320,15 @@ class Picture { Future toImage(int width, int height) { throw UnimplementedError(); } + + /// Creates a picture shader from this picture. + /// + /// The shader is returned asynchronously to allow time for the gpu to + /// draw the picture and compile a shader. + Future toShader(TileMode tmx, TileMode tmy, Float64List matrix4) { + throw UnimplementedError(); + } + /// Release the resources used by this object. The object is no longer usable /// after this method is called. void dispose() { diff --git a/lib/ui/BUILD.gn b/lib/ui/BUILD.gn index bef50753a4b9e..6b6b642d5a674 100644 --- a/lib/ui/BUILD.gn +++ b/lib/ui/BUILD.gn @@ -48,6 +48,8 @@ source_set("ui") { "painting/picture.h", "painting/picture_recorder.cc", "painting/picture_recorder.h", + "painting/picture_shader.cc", + "painting/picture_shader.h", "painting/rrect.cc", "painting/rrect.h", "painting/shader.cc", diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 605396acdac4a..530c2fe3c4630 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -1319,6 +1319,7 @@ class Paint { /// /// * [Gradient], a shader that paints a color gradient. /// * [ImageShader], a shader that tiles an [Image]. + /// * [PictureShader], a shader that tiles a [Picture]. /// * [colorFilter], which overrides [shader]. /// * [color], which is used if [shader] and [colorFilter] are null. Shader get shader { @@ -2875,6 +2876,14 @@ class ImageShader extends Shader { void _initWithImage(Image image, int tmx, int tmy, Float64List matrix4) native 'ImageShader_initWithImage'; } +/// A shader (as used by [Paint.shader]) that tiles a picture. +class PictureShader extends Shader { + /// This class is created by the engine, and should not be instantiated + /// or extended directly. + @pragma('vm:entry-point') + PictureShader._() : super._(); +} + /// Defines how a list of points is interpreted when drawing a set of triangles. /// /// Used by [Canvas.drawVertices]. @@ -3765,6 +3774,23 @@ class Picture extends NativeFieldWrapperClass2 { String _toImage(int width, int height, _Callback callback) native 'Picture_toImage'; + /// Creates a picture shader from this picture. + /// + /// The shader is returned asynchronously to allow time for the gpu to + /// draw the picture and compile a shader. + Future toShader(TileMode tmx, TileMode tmy, Float64List matrix4) { + assert(tmx != null); + assert(tmy != null); + assert(matrix4 != null); + if (matrix4.length != 16) + throw new ArgumentError('"matrix4" must have 16 entries.'); + return _futurize( + (_Callback callback) => _toShader(tmx, tmy, matrix4, callback) + ); + } + + String _toShader(TileMode tmx, TileMode tmy, Float64List matrix4, _Callback callback) native 'Picture_toShader'; + /// Release the resources used by this object. The object is no longer usable /// after this method is called. void dispose() native 'Picture_dispose'; diff --git a/lib/ui/painting/picture.cc b/lib/ui/painting/picture.cc index 98c37edc115f7..5b20edc5193d0 100644 --- a/lib/ui/painting/picture.cc +++ b/lib/ui/painting/picture.cc @@ -21,6 +21,7 @@ IMPLEMENT_WRAPPERTYPEINFO(ui, Picture); #define FOR_EACH_BINDING(V) \ V(Picture, toImage) \ + V(Picture, toShader) \ V(Picture, dispose) \ V(Picture, GetAllocationSize) @@ -46,6 +47,21 @@ Dart_Handle Picture::toImage(uint32_t width, return RasterizeToImage(picture_.get(), width, height, raw_image_callback); } +Dart_Handle Picture::toShader(SkTileMode tmx, + SkTileMode tmy, + const tonic::Float64List& matrix4, + Dart_Handle raw_shader_callback) { + if (!picture_.get()) { + return tonic::ToDart("Picture is null"); + } + + if (picture_.get()->cullRect().isEmpty()) { + return tonic::ToDart("Picture cull rect is null"); + } + + return TransferToShader(picture_.get(), tmx, tmy, matrix4, raw_shader_callback); +} + void Picture::dispose() { ClearDartWrapper(); } @@ -126,4 +142,81 @@ Dart_Handle Picture::RasterizeToImage(sk_sp picture, return Dart_Null(); } +Dart_Handle Picture::TransferToShader(sk_sp picture, + SkTileMode tmx, + SkTileMode tmy, + const tonic::Float64List& matrix4, + Dart_Handle raw_shader_callback) { + if (Dart_IsNull(raw_shader_callback) || !Dart_IsClosure(raw_shader_callback)) { + return tonic::ToDart("Picture shader callback was invalid"); + } + + auto* dart_state = UIDartState::Current(); + tonic::DartPersistentValue* shader_callback = new tonic::DartPersistentValue(dart_state, raw_shader_callback); + auto unref_queue = dart_state->GetSkiaUnrefQueue(); + auto ui_task_runner = dart_state->GetTaskRunners().GetUITaskRunner(); + auto gpu_task_runner = dart_state->GetTaskRunners().GetGPUTaskRunner(); + + auto matrix = ToSkMatrix(matrix4); + + auto ui_task = fml::MakeCopyable([shader_callback, unref_queue]( + sk_sp shader) mutable { + auto dart_state = shader_callback->dart_state().lock(); + if (!dart_state) { + return; + } + tonic::DartState::Scope scope(dart_state); + + if (!shader) { + tonic::DartInvoke(shader_callback->Get(), {Dart_Null()}); + return; + } + + auto dart_shader = PictureShader::Create(); + dart_shader->set_shader({std::move(shader), std::move(unref_queue)}); + auto* raw_dart_shader = tonic::ToDart(std::move(dart_shader)); + + tonic::DartInvoke(shader_callback->Get(), {raw_dart_shader}); + + delete shader_callback; + }); + + fml::TaskRunner::RunNowOrPostTask( + gpu_task_runner, + [ui_task_runner, picture, tmx, tmy, matrix, ui_task] { + sk_sp shader; + + SkRect tile = picture->cullRect(); + + SkPoint scale; + + scale.set(SkScalarSqrt(matrix.getScaleX() * matrix.getScaleX() + matrix.getSkewX() * matrix.getSkewX()), + SkScalarSqrt(matrix.getScaleY() * matrix.getScaleY() + matrix.getSkewY() * matrix.getSkewY())); + + SkSize scaledSize = SkSize::Make(SkScalarAbs(scale.x() * tile.width()), + SkScalarAbs(scale.y() * tile.height())); + + const SkISize tileSize = scaledSize.toCeil(); + + if (!tileSize.isEmpty()) { + SkMatrix tileMatrix; + tileMatrix.setRectToRect(tile, SkRect::MakeIWH(tileSize.width(), tileSize.height()), SkMatrix::kFill_ScaleToFit); + + SkImage::BitDepth bitDepth = SkImage::BitDepth::kU8; + sk_sp colorSpace = SkColorSpace::MakeSRGB(); + + sk_sp tileImage = SkImage::MakeFromPicture(picture, tileSize, &tileMatrix, nullptr, bitDepth, std::move(colorSpace)); + + if(tileImage) + shader = tileImage->makeShader(tmx, tmy); + } + + fml::TaskRunner::RunNowOrPostTask( + ui_task_runner, + [ui_task, shader]() { ui_task(shader); }); + }); + + return Dart_Null(); +} + } // namespace flutter diff --git a/lib/ui/painting/picture.h b/lib/ui/painting/picture.h index a800f920c48a0..41c9681115535 100644 --- a/lib/ui/painting/picture.h +++ b/lib/ui/painting/picture.h @@ -8,7 +8,11 @@ #include "flutter/flow/skia_gpu_object.h" #include "flutter/lib/ui/dart_wrapper.h" #include "flutter/lib/ui/painting/image.h" +#include "flutter/lib/ui/painting/matrix.h" +#include "flutter/lib/ui/painting/picture_shader.h" +#include "third_party/skia/include/core/SkImage.h" #include "third_party/skia/include/core/SkPicture.h" +#include "third_party/tonic/typed_data/float64_list.h" namespace tonic { class DartLibraryNatives; @@ -31,6 +35,11 @@ class Picture : public RefCountedDartWrappable { uint32_t height, Dart_Handle raw_image_callback); + Dart_Handle toShader(SkTileMode tmx, + SkTileMode tmy, + const tonic::Float64List& matrix4, + Dart_Handle raw_shader_callback); + void dispose(); size_t GetAllocationSize() override; @@ -42,6 +51,12 @@ class Picture : public RefCountedDartWrappable { uint32_t height, Dart_Handle raw_image_callback); + static Dart_Handle TransferToShader(sk_sp picture, + SkTileMode tmx, + SkTileMode tmy, + const tonic::Float64List& matrix4, + Dart_Handle raw_shader_callback); + private: explicit Picture(flutter::SkiaGPUObject picture); diff --git a/lib/ui/painting/picture_shader.cc b/lib/ui/painting/picture_shader.cc new file mode 100644 index 0000000000000..3a0558743258c --- /dev/null +++ b/lib/ui/painting/picture_shader.cc @@ -0,0 +1,19 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/lib/ui/painting/picture_shader.h" + +namespace flutter { + +IMPLEMENT_WRAPPERTYPEINFO(ui, PictureShader); + +fml::RefPtr PictureShader::Create() { + return fml::MakeRefCounted(); +} + +PictureShader::PictureShader() = default; + +PictureShader::~PictureShader() = default; + +} // namespace flutter diff --git a/lib/ui/painting/picture_shader.h b/lib/ui/painting/picture_shader.h new file mode 100644 index 0000000000000..51619ace0abbc --- /dev/null +++ b/lib/ui/painting/picture_shader.h @@ -0,0 +1,27 @@ +// Copyright 2013 The Flutter 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 FLUTTER_LIB_UI_PAINTING_PICTURE_SHADER_H_ +#define FLUTTER_LIB_UI_PAINTING_PICTURE_SHADER_H_ + +#include "flutter/lib/ui/dart_wrapper.h" +#include "flutter/lib/ui/painting/shader.h" + +namespace flutter { + +class PictureShader : public Shader { + DEFINE_WRAPPERTYPEINFO(); + FML_FRIEND_MAKE_REF_COUNTED(PictureShader); + + public: + ~PictureShader() override; + static fml::RefPtr Create(); + + private: + PictureShader(); +}; + +} // namespace flutter + +#endif // FLUTTER_LIB_UI_PAINTING_PICTURE_SHADER_H_