diff --git a/impeller/display_list/canvas.cc b/impeller/display_list/canvas.cc index d14db69dc0d69..6617a9f9e30a8 100644 --- a/impeller/display_list/canvas.cc +++ b/impeller/display_list/canvas.cc @@ -734,20 +734,29 @@ void Canvas::DrawImageRect(const std::shared_ptr& image, texture_contents->SetOpacity(paint.color.alpha); texture_contents->SetDeferApplyingOpacity(paint.HasColorFilter()); + // The texture is the source for this draw. The paint's color source is + // irrelevant here, but if left set (dispatchers persist attributes across + // ops and image draws don't re-sync it), Paint::WithColorFilter mistakes + // it for an image color source that already applied the color filter and + // skips the filter entirely. + Paint texture_paint = paint; + texture_paint.color_source = nullptr; + Entity entity; - entity.SetBlendMode(paint.blend_mode); + entity.SetBlendMode(texture_paint.blend_mode); entity.SetTransform(GetCurrentTransform()); - if (!paint.mask_blur_descriptor.has_value()) { - entity.SetContents(paint.WithFilters(std::move(texture_contents))); + if (!texture_paint.mask_blur_descriptor.has_value()) { + entity.SetContents(texture_paint.WithFilters(std::move(texture_contents))); AddRenderEntityToCurrentPass(entity); return; } RectGeometry out_rect(Rect{}); - entity.SetContents(paint.WithFilters( - paint.mask_blur_descriptor->CreateMaskBlur(texture_contents, &out_rect))); + entity.SetContents(texture_paint.WithFilters( + texture_paint.mask_blur_descriptor->CreateMaskBlur(texture_contents, + &out_rect))); AddRenderEntityToCurrentPass(entity); } diff --git a/impeller/display_list/dl_dispatcher.cc b/impeller/display_list/dl_dispatcher.cc index ffdd0c6eca9f8..edf80ed5892c2 100644 --- a/impeller/display_list/dl_dispatcher.cc +++ b/impeller/display_list/dl_dispatcher.cc @@ -735,12 +735,13 @@ void DlDispatcherBase::drawImageRect( AUTO_DEPTH_WATCHER(1u); GetCanvas().DrawImageRect( - image->impeller_texture(), // image - src, // source rect - dst, // destination rect - render_with_attributes ? paint_ : Paint(), // paint - skia_conversions::ToSamplerDescriptor(sampling) // sampling - ); + image->impeller_texture(), // image + src, // source rect + dst, // destination rect + render_with_attributes ? paint_ : Paint(), // paint + skia_conversions::ToSamplerDescriptor(sampling), // sampling + constraint == SrcRectConstraint::kStrict ? SourceRectConstraint::kStrict + : SourceRectConstraint::kFast); } // |flutter::DlOpReceiver| diff --git a/lib/ui/painting/canvas.cc b/lib/ui/painting/canvas.cc index 1da304df6583c..cb05f9fbd2a4c 100644 --- a/lib/ui/painting/canvas.cc +++ b/lib/ui/painting/canvas.cc @@ -445,8 +445,13 @@ Dart_Handle Canvas::drawImageRect(const CanvasImage* image, DlPaint dl_paint; const DlPaint* opt_paint = paint.paint(dl_paint, kDrawImageRectWithPaintFlags); + // Sub-rect sources sample strictly so atlas cells cannot bleed neighbours + // (flutter/flutter#67881). Full-image draws keep kFast semantics. + const bool full_src = + src.contains(SkRect::MakeIWH(dl_image->width(), dl_image->height())); builder()->DrawImageRect(dl_image, src, dst, sampling, opt_paint, - DlCanvas::SrcRectConstraint::kFast); + full_src ? DlCanvas::SrcRectConstraint::kFast + : DlCanvas::SrcRectConstraint::kStrict); } return Dart_Null(); }