From e92e4daa763dedd05ca5d51d0282bf21c8e90e4d Mon Sep 17 00:00:00 2001 From: Dan Field Date: Mon, 10 Apr 2023 09:46:04 -0700 Subject: [PATCH] Move Skia conversion utilities to own TU (flutter/engine#40997) Move Skia conversion utilities to own TU --- .../ci/licenses_golden/licenses_flutter | 4 + .../flutter/impeller/display_list/BUILD.gn | 15 ++ .../display_list/display_list_dispatcher.cc | 243 ++++-------------- .../impeller/display_list/skia_conversions.cc | 168 ++++++++++++ .../impeller/display_list/skia_conversions.h | 35 +++ .../flutter/impeller/geometry/path_builder.h | 2 +- engine/src/flutter/lib/ui/BUILD.gn | 5 +- .../lib/ui/painting/image_decoder_impeller.cc | 26 +- 8 files changed, 291 insertions(+), 207 deletions(-) create mode 100644 engine/src/flutter/impeller/display_list/skia_conversions.cc create mode 100644 engine/src/flutter/impeller/display_list/skia_conversions.h diff --git a/engine/src/flutter/ci/licenses_golden/licenses_flutter b/engine/src/flutter/ci/licenses_golden/licenses_flutter index bfa34e3874d..fc0a5896326 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_flutter +++ b/engine/src/flutter/ci/licenses_golden/licenses_flutter @@ -1152,6 +1152,8 @@ ORIGIN: ../../../flutter/impeller/display_list/display_list_vertices_geometry.cc ORIGIN: ../../../flutter/impeller/display_list/display_list_vertices_geometry.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/display_list/nine_patch_converter.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/display_list/nine_patch_converter.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/display_list/skia_conversions.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/display_list/skia_conversions.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/contents/anonymous_contents.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/contents/anonymous_contents.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/contents/atlas_contents.cc + ../../../flutter/LICENSE @@ -3732,6 +3734,8 @@ FILE: ../../../flutter/impeller/display_list/display_list_vertices_geometry.cc FILE: ../../../flutter/impeller/display_list/display_list_vertices_geometry.h FILE: ../../../flutter/impeller/display_list/nine_patch_converter.cc FILE: ../../../flutter/impeller/display_list/nine_patch_converter.h +FILE: ../../../flutter/impeller/display_list/skia_conversions.cc +FILE: ../../../flutter/impeller/display_list/skia_conversions.h FILE: ../../../flutter/impeller/entity/contents/anonymous_contents.cc FILE: ../../../flutter/impeller/entity/contents/anonymous_contents.h FILE: ../../../flutter/impeller/entity/contents/atlas_contents.cc diff --git a/engine/src/flutter/impeller/display_list/BUILD.gn b/engine/src/flutter/impeller/display_list/BUILD.gn index 7b647a80929..7f2370e331d 100644 --- a/engine/src/flutter/impeller/display_list/BUILD.gn +++ b/engine/src/flutter/impeller/display_list/BUILD.gn @@ -4,6 +4,20 @@ import("//flutter/impeller/tools/impeller.gni") +impeller_component("skia_conversions") { + sources = [ + "skia_conversions.cc", + "skia_conversions.h", + ] + + public_deps = [ + "../core", + "../geometry", + "//flutter/fml", + "//third_party/skia", + ] +} + impeller_component("display_list") { sources = [ "display_list_dispatcher.cc", @@ -17,6 +31,7 @@ impeller_component("display_list") { ] public_deps = [ + ":skia_conversions", "../aiks", "//flutter/display_list", "//flutter/fml", diff --git a/engine/src/flutter/impeller/display_list/display_list_dispatcher.cc b/engine/src/flutter/impeller/display_list/display_list_dispatcher.cc index c50d0d00ea0..9603f25cbde 100644 --- a/engine/src/flutter/impeller/display_list/display_list_dispatcher.cc +++ b/engine/src/flutter/impeller/display_list/display_list_dispatcher.cc @@ -18,6 +18,7 @@ #include "impeller/display_list/display_list_image_impeller.h" #include "impeller/display_list/display_list_vertices_geometry.h" #include "impeller/display_list/nine_patch_converter.h" +#include "impeller/display_list/skia_conversions.h" #include "impeller/entity/contents/conical_gradient_contents.h" #include "impeller/entity/contents/filters/filter_contents.h" #include "impeller/entity/contents/filters/inputs/filter_input.h" @@ -35,8 +36,6 @@ #include "impeller/geometry/sigma.h" #include "impeller/typographer/backends/skia/text_frame_skia.h" -#include "third_party/skia/include/core/SkColor.h" - namespace impeller { #define UNIMPLEMENTED \ @@ -252,43 +251,13 @@ void DisplayListDispatcher::setStrokeJoin(flutter::DlStrokeJoin join) { } } -static Point ToPoint(const SkPoint& point) { - return Point::MakeXY(point.fX, point.fY); -} - -static Color ToColor(const SkColor& color) { - return { - static_cast(SkColorGetR(color) / 255.0), // - static_cast(SkColorGetG(color) / 255.0), // - static_cast(SkColorGetB(color) / 255.0), // - static_cast(SkColorGetA(color) / 255.0) // - }; -} - static std::vector ToColors(const flutter::DlColor colors[], int count) { auto result = std::vector(); if (colors == nullptr) { return result; } for (int i = 0; i < count; i++) { - result.push_back(ToColor(colors[i])); - } - return result; -} - -static std::vector ToRSXForms(const SkRSXform xform[], int count) { - auto result = std::vector(); - for (int i = 0; i < count; i++) { - auto form = xform[i]; - // clang-format off - auto matrix = Matrix{ - form.fSCos, form.fSSin, 0, 0, - -form.fSSin, form.fSCos, 0, 0, - 0, 0, 1, 0, - form.fTx, form.fTy, 0, 1 - }; - // clang-format on - result.push_back(matrix); + result.push_back(skia_conversions::ToColor(colors[i])); } return result; } @@ -304,11 +273,11 @@ static void ConvertStops(T* gradient, auto* dl_colors = gradient->colors(); auto* dl_stops = gradient->stops(); if (dl_stops[0] != 0.0) { - colors->emplace_back(ToColor(dl_colors[0])); + colors->emplace_back(skia_conversions::ToColor(dl_colors[0])); stops->emplace_back(0); } for (auto i = 0; i < gradient->stop_count(); i++) { - colors->emplace_back(ToColor(dl_colors[i])); + colors->emplace_back(skia_conversions::ToColor(dl_colors[i])); stops->emplace_back(dl_stops[i]); } if (stops->back() != 1.0) { @@ -374,8 +343,8 @@ void DisplayListDispatcher::setColorSource( const flutter::DlLinearGradientColorSource* linear = source->asLinearGradient(); FML_DCHECK(linear); - auto start_point = ToPoint(linear->start_point()); - auto end_point = ToPoint(linear->end_point()); + auto start_point = skia_conversions::ToPoint(linear->start_point()); + auto end_point = skia_conversions::ToPoint(linear->end_point()); std::vector colors; std::vector stops; ConvertStops(linear, &colors, &stops); @@ -405,9 +374,10 @@ void DisplayListDispatcher::setColorSource( const flutter::DlConicalGradientColorSource* conical_gradient = source->asConicalGradient(); FML_DCHECK(conical_gradient); - Point center = ToPoint(conical_gradient->end_center()); + Point center = skia_conversions::ToPoint(conical_gradient->end_center()); SkScalar radius = conical_gradient->end_radius(); - Point focus_center = ToPoint(conical_gradient->start_center()); + Point focus_center = + skia_conversions::ToPoint(conical_gradient->start_center()); SkScalar focus_radius = conical_gradient->start_radius(); std::vector colors; std::vector stops; @@ -442,7 +412,7 @@ void DisplayListDispatcher::setColorSource( const flutter::DlRadialGradientColorSource* radialGradient = source->asRadialGradient(); FML_DCHECK(radialGradient); - auto center = ToPoint(radialGradient->center()); + auto center = skia_conversions::ToPoint(radialGradient->center()); auto radius = radialGradient->radius(); std::vector colors; std::vector stops; @@ -475,7 +445,7 @@ void DisplayListDispatcher::setColorSource( source->asSweepGradient(); FML_DCHECK(sweepGradient); - auto center = ToPoint(sweepGradient->center()); + auto center = skia_conversions::ToPoint(sweepGradient->center()); auto start_angle = Degrees(sweepGradient->start()); auto end_angle = Degrees(sweepGradient->end()); std::vector colors; @@ -586,7 +556,7 @@ static std::optional ToColorFilterProc( case flutter::DlColorFilterType::kBlend: { auto dl_blend = filter->asBlend(); auto blend_mode = ToBlendMode(dl_blend->mode()); - auto color = ToColor(dl_blend->color()); + auto color = skia_conversions::ToColor(dl_blend->color()); return [blend_mode, color](FilterInput::Ref input) { return ColorFilterContents::MakeBlend(blend_mode, {std::move(input)}, color); @@ -814,27 +784,13 @@ void DisplayListDispatcher::save() { canvas_.Save(); } -static std::optional ToRect(const SkRect* rect) { - if (rect == nullptr) { - return std::nullopt; - } - return Rect::MakeLTRB(rect->fLeft, rect->fTop, rect->fRight, rect->fBottom); -} - -static std::vector ToRects(const SkRect tex[], int count) { - auto result = std::vector(); - for (int i = 0; i < count; i++) { - result.push_back(ToRect(&tex[i]).value()); - } - return result; -} - // |flutter::DlOpReceiver| void DisplayListDispatcher::saveLayer(const SkRect* bounds, const flutter::SaveLayerOptions options, const flutter::DlImageFilter* backdrop) { auto paint = options.renders_with_attributes() ? paint_ : Paint{}; - canvas_.SaveLayer(paint, ToRect(bounds), ToImageFilterProc(backdrop)); + canvas_.SaveLayer(paint, skia_conversions::ToRect(bounds), + ToImageFilterProc(backdrop)); } // |flutter::DlOpReceiver| @@ -915,10 +871,6 @@ void DisplayListDispatcher::transformReset() { canvas_.Transform(initial_matrix_); } -static Rect ToRect(const SkRect& rect) { - return Rect::MakeLTRB(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); -} - static Entity::ClipOperation ToClipOperation( flutter::DlCanvas::ClipOp clip_op) { switch (clip_op) { @@ -933,99 +885,7 @@ static Entity::ClipOperation ToClipOperation( void DisplayListDispatcher::clipRect(const SkRect& rect, ClipOp clip_op, bool is_aa) { - canvas_.ClipRect(ToRect(rect), ToClipOperation(clip_op)); -} - -static PathBuilder::RoundingRadii ToRoundingRadii(const SkRRect& rrect) { - using Corner = SkRRect::Corner; - PathBuilder::RoundingRadii radii; - radii.bottom_left = ToPoint(rrect.radii(Corner::kLowerLeft_Corner)); - radii.bottom_right = ToPoint(rrect.radii(Corner::kLowerRight_Corner)); - radii.top_left = ToPoint(rrect.radii(Corner::kUpperLeft_Corner)); - radii.top_right = ToPoint(rrect.radii(Corner::kUpperRight_Corner)); - return radii; -} - -static Path ToPath(const SkPath& path) { - auto iterator = SkPath::Iter(path, false); - - struct PathData { - union { - SkPoint points[4]; - }; - }; - - PathBuilder builder; - PathData data; - auto verb = SkPath::Verb::kDone_Verb; - do { - verb = iterator.next(data.points); - switch (verb) { - case SkPath::kMove_Verb: - builder.MoveTo(ToPoint(data.points[0])); - break; - case SkPath::kLine_Verb: - builder.LineTo(ToPoint(data.points[1])); - break; - case SkPath::kQuad_Verb: - builder.QuadraticCurveTo(ToPoint(data.points[1]), - ToPoint(data.points[2])); - break; - case SkPath::kConic_Verb: { - constexpr auto kPow2 = 1; // Only works for sweeps up to 90 degrees. - constexpr auto kQuadCount = 1 + (2 * (1 << kPow2)); - SkPoint points[kQuadCount]; - const auto curve_count = - SkPath::ConvertConicToQuads(data.points[0], // - data.points[1], // - data.points[2], // - iterator.conicWeight(), // - points, // - kPow2 // - ); - - for (int curve_index = 0, point_index = 0; // - curve_index < curve_count; // - curve_index++, point_index += 2 // - ) { - builder.QuadraticCurveTo(ToPoint(points[point_index + 1]), - ToPoint(points[point_index + 2])); - } - } break; - case SkPath::kCubic_Verb: - builder.CubicCurveTo(ToPoint(data.points[1]), ToPoint(data.points[2]), - ToPoint(data.points[3])); - break; - case SkPath::kClose_Verb: - builder.Close(); - break; - case SkPath::kDone_Verb: - break; - } - } while (verb != SkPath::Verb::kDone_Verb); - - FillType fill_type; - switch (path.getFillType()) { - case SkPathFillType::kWinding: - fill_type = FillType::kNonZero; - break; - case SkPathFillType::kEvenOdd: - fill_type = FillType::kOdd; - break; - case SkPathFillType::kInverseWinding: - case SkPathFillType::kInverseEvenOdd: - // Flutter doesn't expose these path fill types. These are only visible - // via the receiver interface. We should never get here. - fill_type = FillType::kNonZero; - break; - } - return builder.TakePath(fill_type); -} - -static Path ToPath(const SkRRect& rrect) { - return PathBuilder{} - .AddRoundedRect(ToRect(rrect.getBounds()), ToRoundingRadii(rrect)) - .TakePath(); + canvas_.ClipRect(skia_conversions::ToRect(rect), ToClipOperation(clip_op)); } // |flutter::DlOpReceiver| @@ -1033,10 +893,10 @@ void DisplayListDispatcher::clipRRect(const SkRRect& rrect, ClipOp clip_op, bool is_aa) { if (rrect.isSimple()) { - canvas_.ClipRRect(ToRect(rrect.rect()), rrect.getSimpleRadii().fX, - ToClipOperation(clip_op)); + canvas_.ClipRRect(skia_conversions::ToRect(rrect.rect()), + rrect.getSimpleRadii().fX, ToClipOperation(clip_op)); } else { - canvas_.ClipPath(ToPath(rrect), ToClipOperation(clip_op)); + canvas_.ClipPath(skia_conversions::ToPath(rrect), ToClipOperation(clip_op)); } } @@ -1044,14 +904,14 @@ void DisplayListDispatcher::clipRRect(const SkRRect& rrect, void DisplayListDispatcher::clipPath(const SkPath& path, ClipOp clip_op, bool is_aa) { - canvas_.ClipPath(ToPath(path), ToClipOperation(clip_op)); + canvas_.ClipPath(skia_conversions::ToPath(path), ToClipOperation(clip_op)); } // |flutter::DlOpReceiver| void DisplayListDispatcher::drawColor(flutter::DlColor color, flutter::DlBlendMode dl_mode) { Paint paint; - paint.color = ToColor(color); + paint.color = skia_conversions::ToColor(color); paint.blend_mode = ToBlendMode(dl_mode); canvas_.DrawPaint(paint); } @@ -1063,7 +923,10 @@ void DisplayListDispatcher::drawPaint() { // |flutter::DlOpReceiver| void DisplayListDispatcher::drawLine(const SkPoint& p0, const SkPoint& p1) { - auto path = PathBuilder{}.AddLine(ToPoint(p0), ToPoint(p1)).TakePath(); + auto path = + PathBuilder{} + .AddLine(skia_conversions::ToPoint(p0), skia_conversions::ToPoint(p1)) + .TakePath(); Paint paint = paint_; paint.style = Paint::Style::kStroke; canvas_.DrawPath(path, paint); @@ -1071,30 +934,33 @@ void DisplayListDispatcher::drawLine(const SkPoint& p0, const SkPoint& p1) { // |flutter::DlOpReceiver| void DisplayListDispatcher::drawRect(const SkRect& rect) { - canvas_.DrawRect(ToRect(rect), paint_); + canvas_.DrawRect(skia_conversions::ToRect(rect), paint_); } // |flutter::DlOpReceiver| void DisplayListDispatcher::drawOval(const SkRect& bounds) { if (bounds.width() == bounds.height()) { - canvas_.DrawCircle(ToPoint(bounds.center()), bounds.width() * 0.5, paint_); + canvas_.DrawCircle(skia_conversions::ToPoint(bounds.center()), + bounds.width() * 0.5, paint_); } else { - auto path = PathBuilder{}.AddOval(ToRect(bounds)).TakePath(); + auto path = + PathBuilder{}.AddOval(skia_conversions::ToRect(bounds)).TakePath(); canvas_.DrawPath(path, paint_); } } // |flutter::DlOpReceiver| void DisplayListDispatcher::drawCircle(const SkPoint& center, SkScalar radius) { - canvas_.DrawCircle(ToPoint(center), radius, paint_); + canvas_.DrawCircle(skia_conversions::ToPoint(center), radius, paint_); } // |flutter::DlOpReceiver| void DisplayListDispatcher::drawRRect(const SkRRect& rrect) { if (rrect.isSimple()) { - canvas_.DrawRRect(ToRect(rrect.rect()), rrect.getSimpleRadii().fX, paint_); + canvas_.DrawRRect(skia_conversions::ToRect(rrect.rect()), + rrect.getSimpleRadii().fX, paint_); } else { - canvas_.DrawPath(ToPath(rrect), paint_); + canvas_.DrawPath(skia_conversions::ToPath(rrect), paint_); } } @@ -1102,14 +968,14 @@ void DisplayListDispatcher::drawRRect(const SkRRect& rrect) { void DisplayListDispatcher::drawDRRect(const SkRRect& outer, const SkRRect& inner) { PathBuilder builder; - builder.AddPath(ToPath(outer)); - builder.AddPath(ToPath(inner)); + builder.AddPath(skia_conversions::ToPath(outer)); + builder.AddPath(skia_conversions::ToPath(inner)); canvas_.DrawPath(builder.TakePath(FillType::kOdd), paint_); } // |flutter::DlOpReceiver| void DisplayListDispatcher::drawPath(const SkPath& path) { - canvas_.DrawPath(ToPath(path), paint_); + canvas_.DrawPath(skia_conversions::ToPath(path), paint_); } // |flutter::DlOpReceiver| @@ -1118,7 +984,7 @@ void DisplayListDispatcher::drawArc(const SkRect& oval_bounds, SkScalar sweep_degrees, bool use_center) { PathBuilder builder; - builder.AddArc(ToRect(oval_bounds), Degrees(start_degrees), + builder.AddArc(skia_conversions::ToRect(oval_bounds), Degrees(start_degrees), Degrees(sweep_degrees), use_center); canvas_.DrawPath(builder.TakePath(), paint_); } @@ -1135,24 +1001,24 @@ void DisplayListDispatcher::drawPoints(PointMode mode, paint.stroke_cap = Cap::kSquare; } for (uint32_t i = 0; i < count; i++) { - Point p0 = ToPoint(points[i]); + Point p0 = skia_conversions::ToPoint(points[i]); auto path = PathBuilder{}.AddLine(p0, p0).TakePath(); canvas_.DrawPath(path, paint); } break; case flutter::DlCanvas::PointMode::kLines: for (uint32_t i = 1; i < count; i += 2) { - Point p0 = ToPoint(points[i - 1]); - Point p1 = ToPoint(points[i]); + Point p0 = skia_conversions::ToPoint(points[i - 1]); + Point p1 = skia_conversions::ToPoint(points[i]); auto path = PathBuilder{}.AddLine(p0, p1).TakePath(); canvas_.DrawPath(path, paint); } break; case flutter::DlCanvas::PointMode::kPolygon: if (count > 1) { - Point p0 = ToPoint(points[0]); + Point p0 = skia_conversions::ToPoint(points[0]); for (uint32_t i = 1; i < count; i++) { - Point p1 = ToPoint(points[i]); + Point p1 = skia_conversions::ToPoint(points[i]); auto path = PathBuilder{}.AddLine(p0, p1).TakePath(); canvas_.DrawPath(path, paint); p0 = p1; @@ -1207,8 +1073,8 @@ void DisplayListDispatcher::drawImageRect( SrcRectConstraint constraint = SrcRectConstraint::kFast) { canvas_.DrawImageRect( std::make_shared(image->impeller_texture()), // image - ToRect(src), // source rect - ToRect(dst), // destination rect + skia_conversions::ToRect(src), // source rect + skia_conversions::ToRect(dst), // destination rect render_with_attributes ? paint_ : Paint(), // paint ToSamplerDescriptor(sampling) // sampling ); @@ -1224,7 +1090,8 @@ void DisplayListDispatcher::drawImageNine(const sk_sp image, converter.DrawNinePatch( std::make_shared(image->impeller_texture()), Rect::MakeLTRB(center.fLeft, center.fTop, center.fRight, center.fBottom), - ToRect(dst), ToSamplerDescriptor(filter), &canvas_, &paint_); + skia_conversions::ToRect(dst), ToSamplerDescriptor(filter), &canvas_, + &paint_); } // |flutter::DlOpReceiver| @@ -1238,9 +1105,11 @@ void DisplayListDispatcher::drawAtlas(const sk_sp atlas, const SkRect* cull_rect, bool render_with_attributes) { canvas_.DrawAtlas(std::make_shared(atlas->impeller_texture()), - ToRSXForms(xform, count), ToRects(tex, count), + skia_conversions::ToRSXForms(xform, count), + skia_conversions::ToRects(tex, count), ToColors(colors, count), ToBlendMode(mode), - ToSamplerDescriptor(sampling), ToRect(cull_rect), paint_); + ToSamplerDescriptor(sampling), + skia_conversions::ToRect(cull_rect), paint_); } // |flutter::DlOpReceiver| @@ -1296,7 +1165,7 @@ void DisplayListDispatcher::drawShadow(const SkPath& path, const SkScalar elevation, bool transparent_occluder, SkScalar dpr) { - Color spot_color = ToColor(color); + Color spot_color = skia_conversions::ToColor(color); spot_color.alpha *= 0.25; // Compute the spot color -- ported from SkShadowUtils::ComputeTonalColors. @@ -1348,13 +1217,15 @@ void DisplayListDispatcher::drawShadow(const SkPath& path, SkRRect rrect; SkRect oval; if (path.isRect(&rect)) { - canvas_.DrawRect(ToRect(rect), paint); + canvas_.DrawRect(skia_conversions::ToRect(rect), paint); } else if (path.isRRect(&rrect) && rrect.isSimple()) { - canvas_.DrawRRect(ToRect(rrect.rect()), rrect.getSimpleRadii().fX, paint); + canvas_.DrawRRect(skia_conversions::ToRect(rrect.rect()), + rrect.getSimpleRadii().fX, paint); } else if (path.isOval(&oval) && oval.width() == oval.height()) { - canvas_.DrawCircle(ToPoint(oval.center()), oval.width() * 0.5, paint); + canvas_.DrawCircle(skia_conversions::ToPoint(oval.center()), + oval.width() * 0.5, paint); } else { - canvas_.DrawPath(ToPath(path), paint); + canvas_.DrawPath(skia_conversions::ToPath(path), paint); } canvas_.Restore(); diff --git a/engine/src/flutter/impeller/display_list/skia_conversions.cc b/engine/src/flutter/impeller/display_list/skia_conversions.cc new file mode 100644 index 00000000000..7b54fef8a55 --- /dev/null +++ b/engine/src/flutter/impeller/display_list/skia_conversions.cc @@ -0,0 +1,168 @@ +// 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 "impeller/display_list/skia_conversions.h" + +namespace impeller { +namespace skia_conversions { + +Rect ToRect(const SkRect& rect) { + return Rect::MakeLTRB(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); +} + +std::optional ToRect(const SkRect* rect) { + if (rect == nullptr) { + return std::nullopt; + } + return Rect::MakeLTRB(rect->fLeft, rect->fTop, rect->fRight, rect->fBottom); +} + +std::vector ToRects(const SkRect tex[], int count) { + auto result = std::vector(); + for (int i = 0; i < count; i++) { + result.push_back(ToRect(&tex[i]).value()); + } + return result; +} + +PathBuilder::RoundingRadii ToRoundingRadii(const SkRRect& rrect) { + using Corner = SkRRect::Corner; + PathBuilder::RoundingRadii radii; + radii.bottom_left = ToPoint(rrect.radii(Corner::kLowerLeft_Corner)); + radii.bottom_right = ToPoint(rrect.radii(Corner::kLowerRight_Corner)); + radii.top_left = ToPoint(rrect.radii(Corner::kUpperLeft_Corner)); + radii.top_right = ToPoint(rrect.radii(Corner::kUpperRight_Corner)); + return radii; +} + +Path ToPath(const SkPath& path) { + auto iterator = SkPath::Iter(path, false); + + struct PathData { + union { + SkPoint points[4]; + }; + }; + + PathBuilder builder; + PathData data; + auto verb = SkPath::Verb::kDone_Verb; + do { + verb = iterator.next(data.points); + switch (verb) { + case SkPath::kMove_Verb: + builder.MoveTo(ToPoint(data.points[0])); + break; + case SkPath::kLine_Verb: + builder.LineTo(ToPoint(data.points[1])); + break; + case SkPath::kQuad_Verb: + builder.QuadraticCurveTo(ToPoint(data.points[1]), + ToPoint(data.points[2])); + break; + case SkPath::kConic_Verb: { + constexpr auto kPow2 = 1; // Only works for sweeps up to 90 degrees. + constexpr auto kQuadCount = 1 + (2 * (1 << kPow2)); + SkPoint points[kQuadCount]; + const auto curve_count = + SkPath::ConvertConicToQuads(data.points[0], // + data.points[1], // + data.points[2], // + iterator.conicWeight(), // + points, // + kPow2 // + ); + + for (int curve_index = 0, point_index = 0; // + curve_index < curve_count; // + curve_index++, point_index += 2 // + ) { + builder.QuadraticCurveTo(ToPoint(points[point_index + 1]), + ToPoint(points[point_index + 2])); + } + } break; + case SkPath::kCubic_Verb: + builder.CubicCurveTo(ToPoint(data.points[1]), ToPoint(data.points[2]), + ToPoint(data.points[3])); + break; + case SkPath::kClose_Verb: + builder.Close(); + break; + case SkPath::kDone_Verb: + break; + } + } while (verb != SkPath::Verb::kDone_Verb); + + FillType fill_type; + switch (path.getFillType()) { + case SkPathFillType::kWinding: + fill_type = FillType::kNonZero; + break; + case SkPathFillType::kEvenOdd: + fill_type = FillType::kOdd; + break; + case SkPathFillType::kInverseWinding: + case SkPathFillType::kInverseEvenOdd: + // Flutter doesn't expose these path fill types. These are only visible + // via the receiver interface. We should never get here. + fill_type = FillType::kNonZero; + break; + } + return builder.TakePath(fill_type); +} + +Path ToPath(const SkRRect& rrect) { + return PathBuilder{} + .AddRoundedRect(ToRect(rrect.getBounds()), ToRoundingRadii(rrect)) + .TakePath(); +} + +Point ToPoint(const SkPoint& point) { + return Point::MakeXY(point.fX, point.fY); +} + +Color ToColor(const SkColor& color) { + return { + static_cast(SkColorGetR(color) / 255.0), // + static_cast(SkColorGetG(color) / 255.0), // + static_cast(SkColorGetB(color) / 255.0), // + static_cast(SkColorGetA(color) / 255.0) // + }; +} + +std::vector ToRSXForms(const SkRSXform xform[], int count) { + auto result = std::vector(); + for (int i = 0; i < count; i++) { + auto form = xform[i]; + // clang-format off + auto matrix = Matrix{ + form.fSCos, form.fSSin, 0, 0, + -form.fSSin, form.fSCos, 0, 0, + 0, 0, 1, 0, + form.fTx, form.fTy, 0, 1 + }; + // clang-format on + result.push_back(matrix); + } + return result; +} + +std::optional ToPixelFormat(SkColorType type) { + switch (type) { + case kRGBA_8888_SkColorType: + return impeller::PixelFormat::kR8G8B8A8UNormInt; + case kBGRA_8888_SkColorType: + return impeller::PixelFormat::kB8G8R8A8UNormInt; + case kRGBA_F16_SkColorType: + return impeller::PixelFormat::kR16G16B16A16Float; + case kBGR_101010x_XR_SkColorType: + return impeller::PixelFormat::kB10G10R10XR; + default: + return std::nullopt; + } + return std::nullopt; +} + +} // namespace skia_conversions +} // namespace impeller diff --git a/engine/src/flutter/impeller/display_list/skia_conversions.h b/engine/src/flutter/impeller/display_list/skia_conversions.h new file mode 100644 index 00000000000..64c2d5bcc81 --- /dev/null +++ b/engine/src/flutter/impeller/display_list/skia_conversions.h @@ -0,0 +1,35 @@ +// 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. + +#pragma once + +#include "impeller/core/formats.h" +#include "impeller/geometry/color.h" +#include "impeller/geometry/path.h" +#include "impeller/geometry/path_builder.h" +#include "impeller/geometry/point.h" +#include "impeller/geometry/rect.h" +#include "third_party/skia/include/core/SkColor.h" +#include "third_party/skia/include/core/SkColorType.h" +#include "third_party/skia/include/core/SkPath.h" +#include "third_party/skia/include/core/SkPoint.h" +#include "third_party/skia/include/core/SkRRect.h" +#include "third_party/skia/include/core/SkRSXform.h" + +namespace impeller { +namespace skia_conversions { + +Rect ToRect(const SkRect& rect); +std::optional ToRect(const SkRect* rect); +std::vector ToRects(const SkRect tex[], int count); +Point ToPoint(const SkPoint& point); +Color ToColor(const SkColor& color); +std::vector ToRSXForms(const SkRSXform xform[], int count); +PathBuilder::RoundingRadii ToRoundingRadii(const SkRRect& rrect); +Path ToPath(const SkPath& path); +Path ToPath(const SkRRect& rrect); +std::optional ToPixelFormat(SkColorType type); + +} // namespace skia_conversions +} // namespace impeller diff --git a/engine/src/flutter/impeller/geometry/path_builder.h b/engine/src/flutter/impeller/geometry/path_builder.h index 3c4dede4ae7..de25ca311e7 100644 --- a/engine/src/flutter/impeller/geometry/path_builder.h +++ b/engine/src/flutter/impeller/geometry/path_builder.h @@ -19,7 +19,7 @@ class PathBuilder { /// the angle. However, accuracy rapidly diminishes if magnified for obtuse /// angle arcs, and so multiple cubic curves should be used when approximating /// arcs greater than 90 degrees. - constexpr static const Scalar kArcApproximationMagic = 0.551915024494; + constexpr static const Scalar kArcApproximationMagic = 0.551915024494f; PathBuilder(); diff --git a/engine/src/flutter/lib/ui/BUILD.gn b/engine/src/flutter/lib/ui/BUILD.gn index 0e7960a5590..af2c5997f39 100644 --- a/engine/src/flutter/lib/ui/BUILD.gn +++ b/engine/src/flutter/lib/ui/BUILD.gn @@ -193,7 +193,10 @@ source_set("ui") { "painting/image_encoding_impeller.h", ] - deps += [ "//flutter/impeller" ] + deps += [ + "//flutter/impeller", + "//flutter/impeller/display_list:skia_conversions", + ] } if (!defined(defines)) { diff --git a/engine/src/flutter/lib/ui/painting/image_decoder_impeller.cc b/engine/src/flutter/lib/ui/painting/image_decoder_impeller.cc index 4db68ac2fe9..bbb0ab67715 100644 --- a/engine/src/flutter/lib/ui/painting/image_decoder_impeller.cc +++ b/engine/src/flutter/lib/ui/painting/image_decoder_impeller.cc @@ -16,6 +16,7 @@ #include "flutter/impeller/renderer/context.h" #include "flutter/lib/ui/painting/image_decoder_skia.h" #include "impeller/base/strings.h" +#include "impeller/display_list/skia_conversions.h" #include "impeller/geometry/size.h" #include "third_party/skia/include/core/SkAlphaType.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -106,22 +107,6 @@ static SkAlphaType ChooseCompatibleAlphaType(SkAlphaType type) { return type; } -static std::optional ToPixelFormat(SkColorType type) { - switch (type) { - case kRGBA_8888_SkColorType: - return impeller::PixelFormat::kR8G8B8A8UNormInt; - case kBGRA_8888_SkColorType: - return impeller::PixelFormat::kB8G8R8A8UNormInt; - case kRGBA_F16_SkColorType: - return impeller::PixelFormat::kR16G16B16A16Float; - case kBGR_101010x_XR_SkColorType: - return impeller::PixelFormat::kB10G10R10XR; - default: - return std::nullopt; - } - return std::nullopt; -} - std::optional ImageDecoderImpeller::DecompressTexture( ImageDescriptor* descriptor, SkISize target_size, @@ -174,7 +159,8 @@ std::optional ImageDecoderImpeller::DecompressTexture( .makeAlphaType(alpha_type); } - const auto pixel_format = ToPixelFormat(image_info.colorType()); + const auto pixel_format = + impeller::skia_conversions::ToPixelFormat(image_info.colorType()); if (!pixel_format.has_value()) { FML_DLOG(ERROR) << "Codec pixel format not supported by Impeller."; return std::nullopt; @@ -260,7 +246,8 @@ sk_sp ImageDecoderImpeller::UploadTextureToPrivate( if (!context || !buffer) { return nullptr; } - const auto pixel_format = ToPixelFormat(image_info.colorType()); + const auto pixel_format = + impeller::skia_conversions::ToPixelFormat(image_info.colorType()); if (!pixel_format) { FML_DLOG(ERROR) << "Pixel format unsupported by Impeller."; return nullptr; @@ -319,7 +306,8 @@ sk_sp ImageDecoderImpeller::UploadTextureToShared( return nullptr; } const auto image_info = bitmap->info(); - const auto pixel_format = ToPixelFormat(image_info.colorType()); + const auto pixel_format = + impeller::skia_conversions::ToPixelFormat(image_info.colorType()); if (!pixel_format) { FML_DLOG(ERROR) << "Pixel format unsupported by Impeller."; return nullptr;