blob: ca30d2ad6f91ea1e8f1b477b634d786fc1ac0934 [file] [log] [blame]
// 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/display_list/skia/dl_sk_conversions.h"
#include "third_party/skia/include/core/SkColorFilter.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
#include "third_party/skia/include/effects/SkImageFilters.h"
namespace flutter {
// clang-format off
constexpr float kInvertColorMatrix[20] = {
-1.0, 0, 0, 1.0, 0,
0, -1.0, 0, 1.0, 0,
0, 0, -1.0, 1.0, 0,
1.0, 1.0, 1.0, 1.0, 0
};
// clang-format on
SkPaint ToSk(const DlPaint& paint) {
SkPaint sk_paint;
sk_paint.setAntiAlias(paint.isAntiAlias());
sk_paint.setColor(ToSk(paint.getColor()));
sk_paint.setBlendMode(ToSk(paint.getBlendMode()));
sk_paint.setStyle(ToSk(paint.getDrawStyle()));
sk_paint.setStrokeWidth(paint.getStrokeWidth());
sk_paint.setStrokeMiter(paint.getStrokeMiter());
sk_paint.setStrokeCap(ToSk(paint.getStrokeCap()));
sk_paint.setStrokeJoin(ToSk(paint.getStrokeJoin()));
sk_paint.setImageFilter(ToSk(paint.getImageFilterPtr()));
auto color_filter = ToSk(paint.getColorFilterPtr());
if (paint.isInvertColors()) {
auto invert_filter = SkColorFilters::Matrix(kInvertColorMatrix);
if (color_filter) {
invert_filter = invert_filter->makeComposed(color_filter);
}
color_filter = invert_filter;
}
sk_paint.setColorFilter(color_filter);
auto color_source = paint.getColorSourcePtr();
if (color_source) {
// Unconditionally set dither to true for gradient shaders.
sk_paint.setDither(color_source->isGradient());
sk_paint.setShader(ToSk(color_source));
}
sk_paint.setMaskFilter(ToSk(paint.getMaskFilterPtr()));
sk_paint.setPathEffect(ToSk(paint.getPathEffectPtr()));
return sk_paint;
}
SkPaint ToStrokedSk(const DlPaint& paint) {
DlPaint stroked_paint = paint;
stroked_paint.setDrawStyle(DlDrawStyle::kStroke);
return ToSk(stroked_paint);
}
SkPaint ToNonShaderSk(const DlPaint& paint) {
DlPaint non_shader_paint = paint;
non_shader_paint.setColorSource(nullptr);
return ToSk(non_shader_paint);
}
sk_sp<SkShader> ToSk(const DlColorSource* source) {
if (!source) {
return nullptr;
}
static auto ToSkColors = [](const DlGradientColorSourceBase* gradient) {
return reinterpret_cast<const SkColor*>(gradient->colors());
};
switch (source->type()) {
case DlColorSourceType::kColor: {
const DlColorColorSource* color_source = source->asColor();
FML_DCHECK(color_source != nullptr);
return SkShaders::Color(ToSk(color_source->color()));
}
case DlColorSourceType::kImage: {
const DlImageColorSource* image_source = source->asImage();
FML_DCHECK(image_source != nullptr);
auto image = image_source->image();
if (!image || !image->skia_image()) {
return nullptr;
}
return image->skia_image()->makeShader(
ToSk(image_source->horizontal_tile_mode()),
ToSk(image_source->vertical_tile_mode()),
ToSk(image_source->sampling()), image_source->matrix_ptr());
}
case DlColorSourceType::kLinearGradient: {
const DlLinearGradientColorSource* linear_source =
source->asLinearGradient();
FML_DCHECK(linear_source != nullptr);
SkPoint pts[] = {linear_source->start_point(),
linear_source->end_point()};
return SkGradientShader::MakeLinear(
pts, ToSkColors(linear_source), linear_source->stops(),
linear_source->stop_count(), ToSk(linear_source->tile_mode()), 0,
linear_source->matrix_ptr());
}
case DlColorSourceType::kRadialGradient: {
const DlRadialGradientColorSource* radial_source =
source->asRadialGradient();
FML_DCHECK(radial_source != nullptr);
return SkGradientShader::MakeRadial(
radial_source->center(), radial_source->radius(),
ToSkColors(radial_source), radial_source->stops(),
radial_source->stop_count(), ToSk(radial_source->tile_mode()), 0,
radial_source->matrix_ptr());
}
case DlColorSourceType::kConicalGradient: {
const DlConicalGradientColorSource* conical_source =
source->asConicalGradient();
FML_DCHECK(conical_source != nullptr);
return SkGradientShader::MakeTwoPointConical(
conical_source->start_center(), conical_source->start_radius(),
conical_source->end_center(), conical_source->end_radius(),
ToSkColors(conical_source), conical_source->stops(),
conical_source->stop_count(), ToSk(conical_source->tile_mode()), 0,
conical_source->matrix_ptr());
}
case DlColorSourceType::kSweepGradient: {
const DlSweepGradientColorSource* sweep_source =
source->asSweepGradient();
FML_DCHECK(sweep_source != nullptr);
return SkGradientShader::MakeSweep(
sweep_source->center().x(), sweep_source->center().y(),
ToSkColors(sweep_source), sweep_source->stops(),
sweep_source->stop_count(), ToSk(sweep_source->tile_mode()),
sweep_source->start(), sweep_source->end(), 0,
sweep_source->matrix_ptr());
}
case DlColorSourceType::kRuntimeEffect: {
const DlRuntimeEffectColorSource* runtime_source =
source->asRuntimeEffect();
FML_DCHECK(runtime_source != nullptr);
auto runtime_effect = runtime_source->runtime_effect();
if (!runtime_effect || !runtime_effect->skia_runtime_effect()) {
return nullptr;
}
auto samplers = runtime_source->samplers();
std::vector<sk_sp<SkShader>> sk_samplers(samplers.size());
for (size_t i = 0; i < samplers.size(); i++) {
auto sampler = samplers[i];
if (sampler == nullptr) {
return nullptr;
}
sk_samplers[i] = ToSk(sampler);
}
auto uniform_data = runtime_source->uniform_data();
auto ref = new std::shared_ptr<std::vector<uint8_t>>(uniform_data);
auto sk_uniform_data = SkData::MakeWithProc(
uniform_data->data(), uniform_data->size(),
[](const void* ptr, void* context) {
delete reinterpret_cast<std::shared_ptr<std::vector<uint8_t>>*>(
context);
},
ref);
return runtime_effect->skia_runtime_effect()->makeShader(
sk_uniform_data, sk_samplers.data(), sk_samplers.size());
}
#ifdef IMPELLER_ENABLE_3D
case DlColorSourceType::kScene: {
return nullptr;
}
#endif // IMPELLER_ENABLE_3D
}
}
sk_sp<SkImageFilter> ToSk(const DlImageFilter* filter) {
if (!filter) {
return nullptr;
}
switch (filter->type()) {
case DlImageFilterType::kBlur: {
const DlBlurImageFilter* blur_filter = filter->asBlur();
FML_DCHECK(blur_filter != nullptr);
return SkImageFilters::Blur(blur_filter->sigma_x(),
blur_filter->sigma_y(),
ToSk(blur_filter->tile_mode()), nullptr);
}
case DlImageFilterType::kDilate: {
const DlDilateImageFilter* dilate_filter = filter->asDilate();
FML_DCHECK(dilate_filter != nullptr);
return SkImageFilters::Dilate(dilate_filter->radius_x(),
dilate_filter->radius_y(), nullptr);
}
case DlImageFilterType::kErode: {
const DlErodeImageFilter* erode_filter = filter->asErode();
FML_DCHECK(erode_filter != nullptr);
return SkImageFilters::Erode(erode_filter->radius_x(),
erode_filter->radius_y(), nullptr);
}
case DlImageFilterType::kMatrix: {
const DlMatrixImageFilter* matrix_filter = filter->asMatrix();
FML_DCHECK(matrix_filter != nullptr);
return SkImageFilters::MatrixTransform(
matrix_filter->matrix(), ToSk(matrix_filter->sampling()), nullptr);
}
case DlImageFilterType::kCompose: {
const DlComposeImageFilter* compose_filter = filter->asCompose();
FML_DCHECK(compose_filter != nullptr);
return SkImageFilters::Compose(ToSk(compose_filter->outer()),
ToSk(compose_filter->inner()));
}
case DlImageFilterType::kColorFilter: {
const DlColorFilterImageFilter* cf_filter = filter->asColorFilter();
FML_DCHECK(cf_filter != nullptr);
return SkImageFilters::ColorFilter(ToSk(cf_filter->color_filter()),
nullptr);
}
case DlImageFilterType::kLocalMatrix: {
const DlLocalMatrixImageFilter* lm_filter = filter->asLocalMatrix();
FML_DCHECK(lm_filter != nullptr);
sk_sp<SkImageFilter> skia_filter = ToSk(lm_filter->image_filter());
// The image_filter property itself might have been null, or the
// construction of the SkImageFilter might be optimized to null
// for any number of reasons. In any case, if the filter is null
// or optimizaed away, let's then optimize away this local matrix
// case by returning null.
if (!skia_filter) {
return nullptr;
}
return skia_filter->makeWithLocalMatrix(lm_filter->matrix());
}
}
}
sk_sp<SkColorFilter> ToSk(const DlColorFilter* filter) {
if (!filter) {
return nullptr;
}
switch (filter->type()) {
case DlColorFilterType::kBlend: {
const DlBlendColorFilter* blend_filter = filter->asBlend();
FML_DCHECK(blend_filter != nullptr);
return SkColorFilters::Blend(ToSk(blend_filter->color()),
ToSk(blend_filter->mode()));
}
case DlColorFilterType::kMatrix: {
const DlMatrixColorFilter* matrix_filter = filter->asMatrix();
FML_DCHECK(matrix_filter != nullptr);
float matrix[20];
matrix_filter->get_matrix(matrix);
return SkColorFilters::Matrix(matrix);
}
case DlColorFilterType::kSrgbToLinearGamma: {
return SkColorFilters::SRGBToLinearGamma();
}
case DlColorFilterType::kLinearToSrgbGamma: {
return SkColorFilters::LinearToSRGBGamma();
}
}
}
sk_sp<SkMaskFilter> ToSk(const DlMaskFilter* filter) {
if (!filter) {
return nullptr;
}
switch (filter->type()) {
case DlMaskFilterType::kBlur: {
const DlBlurMaskFilter* blur_filter = filter->asBlur();
FML_DCHECK(blur_filter != nullptr);
return SkMaskFilter::MakeBlur(ToSk(blur_filter->style()),
blur_filter->sigma(),
blur_filter->respectCTM());
}
}
}
sk_sp<SkPathEffect> ToSk(const DlPathEffect* effect) {
if (!effect) {
return nullptr;
}
switch (effect->type()) {
case DlPathEffectType::kDash: {
const DlDashPathEffect* dash_effect = effect->asDash();
FML_DCHECK(dash_effect != nullptr);
return SkDashPathEffect::Make(dash_effect->intervals(),
dash_effect->count(), dash_effect->phase());
}
}
}
sk_sp<SkVertices> ToSk(const DlVertices* vertices) {
const SkColor* sk_colors =
reinterpret_cast<const SkColor*>(vertices->colors());
return SkVertices::MakeCopy(ToSk(vertices->mode()), vertices->vertex_count(),
vertices->vertices(),
vertices->texture_coordinates(), sk_colors,
vertices->index_count(), vertices->indices());
}
} // namespace flutter