| // 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 |