Hoist/fold GraphicsContext::DrawTiledImage (background-image version)
Folds the "background-image version" of GraphicsContext::DrawTiledImage
into BoxPainter(Base). Mostly a verbatim move of said method and
Image::DrawTiledBackground (the real "meat") an the associated helpers.
This also introduces the intended replacement (for versions of this
method): GraphicsContext::DrawImageTiled.
Calls to StartAnimation are moved into the implementations of
Image::DrawPattern as needed.
Bug: 614125
Change-Id: Ib04daa5abce9c61c12f4a8297920ea25760557cf
Reviewed-on: https://chromium-review.googlesource.com/c/1448458
Commit-Queue: Fredrik Söderquist <fs@opera.com>
Reviewed-by: Florin Malita <fmalita@chromium.org>
Reviewed-by: Stephen Chenney <schenney@chromium.org>
Cr-Commit-Position: refs/heads/master@{#628136}
diff --git a/third_party/blink/renderer/core/paint/box_painter_base.cc b/third_party/blink/renderer/core/paint/box_painter_base.cc
index f84f3cfc..e503a8b 100644
--- a/third_party/blink/renderer/core/paint/box_painter_base.cc
+++ b/third_party/blink/renderer/core/paint/box_painter_base.cc
@@ -309,6 +309,112 @@
namespace {
+// Given the |size| that the whole image should draw at, and the input phase
+// requested by the content, and the space between repeated tiles, return a
+// rectangle with |size| and a location that respects the phase but is no more
+// than one size + space in magnitude. In practice, this means that if there is
+// no repeating the returned rect would contain the destination_offset
+// location. The destination_offset passed here must exactly match the location
+// of the subset in a following call to ComputeSubsetForBackground.
+FloatRect ComputePhaseForBackground(const FloatPoint& destination_offset,
+ const FloatSize& size,
+ const FloatPoint& phase,
+ const FloatSize& spacing) {
+ const FloatSize step_per_tile(size + spacing);
+ return FloatRect(
+ FloatPoint(
+ destination_offset.X() + fmodf(-phase.X(), step_per_tile.Width()),
+ destination_offset.Y() + fmodf(-phase.Y(), step_per_tile.Height())),
+ size);
+}
+
+// Compute the image subset, in intrinsic image coordinates, that gets mapped
+// onto the |subset|, when the whole image would be drawn with phase and size
+// given by |phase_and_size|. Assumes |phase_and_size| contains |subset|. The
+// location of the requested subset should be the painting snapped location, or
+// whatever was used as a destination_offset in ComputePhaseForBackground.
+//
+// It is used to undo the offset added in ComputePhaseForBackground. The size
+// of requested subset should be the unsnapped size so that the computed
+// scale and location in the source image can be correctly determined.
+FloatRect ComputeSubsetForBackground(const FloatRect& phase_and_size,
+ const FloatRect& subset,
+ const FloatSize& intrinsic_size) {
+ // TODO(schenney): Re-enable this after determining why it fails for
+ // CAP, and maybe other cases.
+ // DCHECK(phase_and_size.Contains(subset));
+
+ const FloatSize scale(phase_and_size.Width() / intrinsic_size.Width(),
+ phase_and_size.Height() / intrinsic_size.Height());
+ return FloatRect((subset.X() - phase_and_size.X()) / scale.Width(),
+ (subset.Y() - phase_and_size.Y()) / scale.Height(),
+ subset.Width() / scale.Width(),
+ subset.Height() / scale.Height());
+}
+
+// The unsnapped_subset_size should be the target painting area implied by the
+// content, without any snapping applied. It is necessary to correctly
+// compute the subset of the source image to paint into the destination.
+// The snapped_paint_rect should be the target destination for painting into.
+// The phase is never snapped.
+// The tile_size is the total image size. The mapping from this size
+// to the unsnapped_dest_rect size defines the scaling of the image for
+// sprite computation.
+void DrawTiledBackground(GraphicsContext& context,
+ Image* image,
+ const FloatSize& unsnapped_subset_size,
+ const FloatRect& snapped_paint_rect,
+ const FloatPoint& phase,
+ const FloatSize& tile_size,
+ SkBlendMode op,
+ const FloatSize& repeat_spacing) {
+ DCHECK(!tile_size.IsEmpty());
+
+ // Use the intrinsic size of the image if it has one, otherwise force the
+ // generated image to be the tile size.
+ FloatSize intrinsic_tile_size(image->Size());
+ FloatSize scale(1, 1);
+ if (image->HasRelativeSize()) {
+ intrinsic_tile_size = tile_size;
+ } else {
+ scale = FloatSize(tile_size.Width() / intrinsic_tile_size.Width(),
+ tile_size.Height() / intrinsic_tile_size.Height());
+ }
+
+ const FloatRect one_tile_rect = ComputePhaseForBackground(
+ snapped_paint_rect.Location(), tile_size, phase, repeat_spacing);
+
+ // Check and see if a single draw of the image can cover the entire area we
+ // are supposed to tile. The dest_rect_for_subset must use the same
+ // location that was used in ComputePhaseForBackground and the unsnapped
+ // destination rect in order to correctly evaluate the subset size and
+ // location in the presence of border snapping and zoom.
+ FloatRect dest_rect_for_subset(snapped_paint_rect.Location(),
+ unsnapped_subset_size);
+ if (one_tile_rect.Contains(dest_rect_for_subset)) {
+ FloatRect visible_src_rect = ComputeSubsetForBackground(
+ one_tile_rect, dest_rect_for_subset, intrinsic_tile_size);
+ // Round to avoid filtering pulling in neighboring pixels, for the
+ // common case of sprite maps.
+ // TODO(schenney): Snapping at this level is a problem for cases where we
+ // might be animating background-position to pan over an image. Ideally we
+ // would either snap only if close to integral, or move snapping
+ // calculations up the stack.
+ visible_src_rect = FloatRect(RoundedIntRect(visible_src_rect));
+ context.DrawImage(image, Image::kSyncDecode, snapped_paint_rect,
+ &visible_src_rect, op, kDoNotRespectImageOrientation);
+ return;
+ }
+
+ // Note that this tile rect the image's pre-scaled size.
+ FloatRect tile_rect(FloatPoint(), intrinsic_tile_size);
+ // This call takes the unscaled image, applies the given scale, and paints
+ // it into the snapped_dest_rect using phase from one_tile_rect and the
+ // given repeat spacing. Note the phase is already scaled.
+ context.DrawImageTiled(image, snapped_paint_rect, tile_rect, scale,
+ one_tile_rect.Location(), repeat_spacing, op);
+}
+
inline bool PaintFastBottomLayer(Node* node,
const PaintInfo& paint_info,
const BoxPainterBase::FillLayerInfo& info,
@@ -359,7 +465,7 @@
// Phase calculation uses the actual painted location, given by the
// border-snapped destination rect.
- image_tile = Image::ComputePhaseForBackground(
+ image_tile = ComputePhaseForBackground(
FloatPoint(geometry.SnappedDestRect().Location()),
FloatSize(geometry.TileSize()), geometry.Phase(),
FloatSize(geometry.SpaceSize()));
@@ -417,7 +523,7 @@
// so snap to integers. This is particuarly important for sprite maps.
// Calculation up to this point, in LayoutUnits, can lead to small variations
// from integer size, so it is safe to round without introducing major issues.
- const FloatRect unrounded_subset = Image::ComputeSubsetForBackground(
+ const FloatRect unrounded_subset = ComputeSubsetForBackground(
image_tile, dest_rect_for_subset, intrinsic_tile_size);
FloatRect src_rect = FloatRect(RoundedIntRect(unrounded_subset));
@@ -541,17 +647,17 @@
// NOTE: This method can be called with no image in situations when a bad
// resource locator is given such as "//:0", so still check for image.
if (info.should_paint_image && !geometry.SnappedDestRect().IsEmpty() &&
- image) {
+ !geometry.TileSize().IsEmpty() && image) {
TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "PaintImage",
"data",
inspector_paint_image_event::Data(
node, *info.image, FloatRect(image->Rect()),
FloatRect(scrolled_paint_rect)));
- context.DrawTiledImage(image,
- FloatSize(geometry.UnsnappedDestRect().Size()),
- FloatRect(geometry.SnappedDestRect()),
- geometry.Phase(), FloatSize(geometry.TileSize()),
- composite_op, FloatSize(geometry.SpaceSize()));
+ DrawTiledBackground(context, image,
+ FloatSize(geometry.UnsnappedDestRect().Size()),
+ FloatRect(geometry.SnappedDestRect()), geometry.Phase(),
+ FloatSize(geometry.TileSize()), composite_op,
+ FloatSize(geometry.SpaceSize()));
}
}
diff --git a/third_party/blink/renderer/core/svg/graphics/svg_image.cc b/third_party/blink/renderer/core/svg/graphics/svg_image.cc
index 2eecda79..2293a21 100644
--- a/third_party/blink/renderer/core/svg/graphics/svg_image.cc
+++ b/third_party/blink/renderer/core/svg/graphics/svg_image.cc
@@ -384,6 +384,8 @@
flags.setBlendMode(composite_op);
flags.setColorFilter(sk_ref_sp(context.GetColorFilter()));
context.DrawRect(dst_rect, flags);
+
+ StartAnimation();
}
sk_sp<PaintRecord> SVGImage::PaintRecordForContainer(
diff --git a/third_party/blink/renderer/platform/graphics/graphics_context.cc b/third_party/blink/renderer/platform/graphics/graphics_context.cc
index cc494d2..197174a0 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_context.cc
+++ b/third_party/blink/renderer/platform/graphics/graphics_context.cc
@@ -995,17 +995,17 @@
std::min(resampling, ImageInterpolationQuality()));
}
-void GraphicsContext::DrawTiledImage(Image* image,
- const FloatSize& unsnapped_subset_size,
- const FloatRect& snapped_paint_rect,
- const FloatPoint& unsnapped_phase,
- const FloatSize& tile_size,
- SkBlendMode op,
- const FloatSize& repeat_spacing) {
+void GraphicsContext::DrawImageTiled(Image* image,
+ const FloatRect& dest_rect,
+ const FloatRect& src_rect,
+ const FloatSize& scale_src_to_dest,
+ const FloatPoint& phase,
+ const FloatSize& repeat_spacing,
+ SkBlendMode op) {
if (ContextDisabled() || !image)
return;
- image->DrawTiledBackground(*this, unsnapped_subset_size, snapped_paint_rect,
- unsnapped_phase, tile_size, op, repeat_spacing);
+ image->DrawPattern(*this, src_rect, scale_src_to_dest, phase, op, dest_rect,
+ repeat_spacing);
paint_controller_.SetImagePainted();
}
diff --git a/third_party/blink/renderer/platform/graphics/graphics_context.h b/third_party/blink/renderer/platform/graphics/graphics_context.h
index f46176a4..a8dcb080 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_context.h
+++ b/third_party/blink/renderer/platform/graphics/graphics_context.h
@@ -223,14 +223,13 @@
const FloatRect& src_rect,
SkBlendMode = SkBlendMode::kSrcOver,
RespectImageOrientationEnum = kDoNotRespectImageOrientation);
- // Used for background image
- void DrawTiledImage(Image*,
- const FloatSize& unsnapped_subset_size,
- const FloatRect& snapped_paint_rect,
- const FloatPoint& unsnapped_phase,
- const FloatSize& tile_size,
- SkBlendMode = SkBlendMode::kSrcOver,
- const FloatSize& repeat_spacing = FloatSize());
+ void DrawImageTiled(Image* image,
+ const FloatRect& dest_rect,
+ const FloatRect& src_rect,
+ const FloatSize& scale_src_to_dest,
+ const FloatPoint& phase,
+ const FloatSize& repeat_spacing,
+ SkBlendMode = SkBlendMode::kSrcOver);
// Used for border image
void DrawTiledImage(Image*,
const FloatRect& dest_rect,
diff --git a/third_party/blink/renderer/platform/graphics/image.cc b/third_party/blink/renderer/platform/graphics/image.cc
index efa5fa09..dba1d08 100644
--- a/third_party/blink/renderer/platform/graphics/image.cc
+++ b/third_party/blink/renderer/platform/graphics/image.cc
@@ -141,66 +141,6 @@
}
// TODO(schenney): Lift this code, with the calculations for subsetting the
-// image and the like, up the stack into a BackgroundPainter.
-void Image::DrawTiledBackground(GraphicsContext& ctxt,
- const FloatSize& unsnapped_subset_size,
- const FloatRect& snapped_paint_rect,
- const FloatPoint& phase,
- const FloatSize& tile_size,
- SkBlendMode op,
- const FloatSize& repeat_spacing) {
- if (tile_size.IsEmpty())
- return;
-
- // Use the intrinsic size of the image if it has one, otherwise force the
- // generated image to be the tile size.
- FloatSize intrinsic_tile_size(Size());
- FloatSize scale(1, 1);
- if (HasRelativeSize()) {
- intrinsic_tile_size.SetWidth(tile_size.Width());
- intrinsic_tile_size.SetHeight(tile_size.Height());
- } else {
- scale = FloatSize(tile_size.Width() / intrinsic_tile_size.Width(),
- tile_size.Height() / intrinsic_tile_size.Height());
- }
-
- const FloatRect one_tile_rect = ComputePhaseForBackground(
- snapped_paint_rect.Location(), tile_size, phase, repeat_spacing);
-
- // Check and see if a single draw of the image can cover the entire area we
- // are supposed to tile. The dest_rect_for_subset must use the same
- // location that was used in ComputePhaseForBackground and the unsnapped
- // destination rect in order to correctly evaluate the subset size and
- // location in the presence of border snapping and zoom.
- FloatRect dest_rect_for_subset(snapped_paint_rect.Location(),
- unsnapped_subset_size);
- if (one_tile_rect.Contains(dest_rect_for_subset)) {
- FloatRect visible_src_rect = ComputeSubsetForBackground(
- one_tile_rect, dest_rect_for_subset, intrinsic_tile_size);
- // Round to avoid filtering pulling in neighboring pixels, for the
- // common case of sprite maps.
- // TODO(schenney): Snapping at this level is a problem for cases where we
- // might be animating background-position to pan over an image. Ideally we
- // would either snap only if close to integral, or move snapping
- // calculations up the stack.
- visible_src_rect = FloatRect(RoundedIntRect(visible_src_rect));
- ctxt.DrawImage(this, kSyncDecode, snapped_paint_rect, &visible_src_rect, op,
- kDoNotRespectImageOrientation);
- return;
- }
-
- // Note that this tile rect the image's pre-scaled size.
- FloatRect tile_rect(FloatPoint(), intrinsic_tile_size);
- // This call takes the unscaled image, applies the given scale, and paints
- // it into the snapped_dest_rect using phase from one_tile_rect and the
- // given repeat spacing. Note the phase is already scaled.
- DrawPattern(ctxt, tile_rect, scale, one_tile_rect.Location(), op,
- snapped_paint_rect, repeat_spacing);
-
- StartAnimation();
-}
-
-// TODO(schenney): Lift this code, with the calculations for subsetting the
// image and the like, up the stack into a border painting class.
void Image::DrawTiledBorder(GraphicsContext& ctxt,
const FloatRect& dst_rect,
@@ -295,8 +235,6 @@
DrawPattern(ctxt, src_rect, tile_scale_factor, pattern_phase, op, dst_rect,
spacing);
}
-
- StartAnimation();
}
namespace {
@@ -412,6 +350,8 @@
context.DrawRect(dest_rect, flags);
+ StartAnimation();
+
if (CurrentFrameIsLazyDecoded()) {
TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
"Draw LazyPixelRef", TRACE_EVENT_SCOPE_THREAD,
@@ -454,33 +394,6 @@
return true;
}
-FloatRect Image::ComputePhaseForBackground(const FloatPoint& destination_offset,
- const FloatSize& size,
- const FloatPoint& phase,
- const FloatSize& spacing) {
- const FloatSize step_per_tile(size + spacing);
- return FloatRect(
- FloatPoint(
- destination_offset.X() + fmodf(-phase.X(), step_per_tile.Width()),
- destination_offset.Y() + fmodf(-phase.Y(), step_per_tile.Height())),
- size);
-}
-
-FloatRect Image::ComputeSubsetForBackground(const FloatRect& phase_and_size,
- const FloatRect& subset,
- const FloatSize& intrinsic_size) {
- // TODO(schenney): Re-enable this after determining why it fails for
- // CAP, and maybe other cases.
- // DCHECK(phase_and_size.Contains(subset));
-
- const FloatSize scale(phase_and_size.Width() / intrinsic_size.Width(),
- phase_and_size.Height() / intrinsic_size.Height());
- return FloatRect((subset.X() - phase_and_size.X()) / scale.Width(),
- (subset.Y() - phase_and_size.Y()) / scale.Height(),
- subset.Width() / scale.Width(),
- subset.Height() / scale.Height());
-}
-
SkBitmap Image::AsSkBitmapForCurrentFrame(
RespectImageOrientationEnum should_respect_image_orientation) {
PaintImage paint_image = PaintImageForCurrentFrame();
diff --git a/third_party/blink/renderer/platform/graphics/image.h b/third_party/blink/renderer/platform/graphics/image.h
index 490c63f..a6e42e8 100644
--- a/third_party/blink/renderer/platform/graphics/image.h
+++ b/third_party/blink/renderer/platform/graphics/image.h
@@ -223,33 +223,6 @@
return nullptr;
}
- // Given the |size| that the whole image should draw at, and the
- // input phase requested by the content, and the space between repeated tiles,
- // return a rectangle with |size| and a location that respects
- // the phase but is no more than one size + space in magnitude. In practice,
- // this means that if there is no repeating the returned rect would contain
- // the destination_offset location. The destination_offset passed here must
- // exactly match the location of the subset in a following call to
- // ComputeSubsetForBackground.
- static FloatRect ComputePhaseForBackground(
- const FloatPoint& destination_offset,
- const FloatSize& size,
- const FloatPoint& phase,
- const FloatSize& spacing);
-
- // Compute the image subset, in intrinsic image coordinates, that gets mapped
- // onto the |subset|, when the whole image would be drawn with phase
- // and size given by |phase_and_size|. Assumes
- // |phase_and_size| contains |subset|. The location
- // of the requested subset should be the painting snapped location, or
- // whatever was used as a destination_offset in ComputePhaseForBackground.
- // It is used to undo the offset added in ComputePhaseForBackground. The size
- // of requested subset should be the unsnapped size so that the computed
- // scale and location in the source image can be correctly determined.
- static FloatRect ComputeSubsetForBackground(const FloatRect& phase_and_size,
- const FloatRect& subset,
- const FloatSize& intrinsic_size);
-
virtual sk_sp<PaintRecord> PaintRecordForContainer(
const KURL& url,
const IntSize& container_size,
@@ -278,22 +251,6 @@
protected:
Image(ImageObserver* = nullptr, bool is_multipart = false);
- // The unsnapped_subset_size should be the target painting area implied by the
- // content, without any snapping applied. It is necessary to correctly
- // compute the subset of the source image to paint into the destination.
- // The snapped_paint_rect should be the target destination for painting into.
- // The phase is never snapped.
- // The tile_size is the total image size. The mapping from this size
- // to the unsnapped_dest_rect size defines the scaling of the image for
- // sprite computation.
- void DrawTiledBackground(GraphicsContext&,
- const FloatSize& unsnapped_subset_size,
- const FloatRect& snapped_paint_rect,
- const FloatPoint& phase,
- const FloatSize& tile_size,
- SkBlendMode,
- const FloatSize& repeat_spacing);
-
void DrawTiledBorder(GraphicsContext&,
const FloatRect& dst_rect,
const FloatRect& src_rect,