Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions lib/stub_ui/lib/painting.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -2669,6 +2670,13 @@ class ImageShader extends Shader {
super._();
}

/// A shader (as used by [Paint.shader]) that tiles a picture.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide additional documentation, e.g. sample code (see https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#provide-sample-code).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(notably, how to create a PictureShader should be documented here, as well as how to use it)

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].
Expand Down Expand Up @@ -3312,6 +3320,15 @@ class Picture {
Future<Image> 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<PictureShader> toShader(TileMode tmx, TileMode tmy, Float64List matrix4) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general we prefer to avoid abbreviations, so tileModeX or some such.

In https://master-api.flutter.dev/flutter/painting/paintImage.html we use RepeatImage which doesn't expose mirror. Is your goal to eventually add mirror values to the RepeatImage enum?

throw UnimplementedError();
}

/// Release the resources used by this object. The object is no longer usable
/// after this method is called.
void dispose() {
Expand Down
2 changes: 2 additions & 0 deletions lib/ui/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
26 changes: 26 additions & 0 deletions lib/ui/painting.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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].
Expand Down Expand Up @@ -3765,6 +3774,23 @@ class Picture extends NativeFieldWrapperClass2 {

String _toImage(int width, int height, _Callback<Image> 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<PictureShader> 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<PictureShader> callback) => _toShader(tmx, tmy, matrix4, callback)
);
}

String _toShader(TileMode tmx, TileMode tmy, Float64List matrix4, _Callback<PictureShader> 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';
Expand Down
93 changes: 93 additions & 0 deletions lib/ui/painting/picture.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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();
}
Expand Down Expand Up @@ -126,4 +142,81 @@ Dart_Handle Picture::RasterizeToImage(sk_sp<SkPicture> picture,
return Dart_Null();
}

Dart_Handle Picture::TransferToShader(sk_sp<SkPicture> 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<SkShader> 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<SkShader> 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<SkColorSpace> colorSpace = SkColorSpace::MakeSRGB();

sk_sp<SkImage> 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
15 changes: 15 additions & 0 deletions lib/ui/painting/picture.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -31,6 +35,11 @@ class Picture : public RefCountedDartWrappable<Picture> {
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;
Expand All @@ -42,6 +51,12 @@ class Picture : public RefCountedDartWrappable<Picture> {
uint32_t height,
Dart_Handle raw_image_callback);

static Dart_Handle TransferToShader(sk_sp<SkPicture> picture,
SkTileMode tmx,
SkTileMode tmy,
const tonic::Float64List& matrix4,
Dart_Handle raw_shader_callback);

private:
explicit Picture(flutter::SkiaGPUObject<SkPicture> picture);

Expand Down
19 changes: 19 additions & 0 deletions lib/ui/painting/picture_shader.cc
Original file line number Diff line number Diff line change
@@ -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> PictureShader::Create() {
return fml::MakeRefCounted<PictureShader>();
}

PictureShader::PictureShader() = default;

PictureShader::~PictureShader() = default;

} // namespace flutter
27 changes: 27 additions & 0 deletions lib/ui/painting/picture_shader.h
Original file line number Diff line number Diff line change
@@ -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<PictureShader> Create();

private:
PictureShader();
};

} // namespace flutter

#endif // FLUTTER_LIB_UI_PAINTING_PICTURE_SHADER_H_