Reland "Simplify layer bounds syncing and no-device error handling in SkCanvas::internalSaveLayer"

This reverts commit 6c1191d749a3b9fe144466f473ca222d57898f11.

Reason for revert:
 - the lowest-level issue is fixed in https://skia-review.googlesource.com/c/skia/+/337076
   which prevents bad replaceClips from going beyond the device bounds
 - but this also updates the original CL so that we don't call
   replaceClip in these problematic situations. The old behavior of
   effectively downgrading a saveLayer to a save when the new device
   fails to allocate is better behavior.
 - now the bounds tracking is still consolidated as before, but only
   applied when the kNoLayer_Strategy is used, or the layer should be
   empty (in which case replaceClip() is passed an empty rect and
   everything works out).

 - when the layer fails to allocate, we add a clipRegion to restrict
   nested draw calls to what would have been the layers bounds, while
   still respecting the old clip (that normally would have been applied
   on the layer restore, but won't because there's no layer). This is
   somewhat pedantic, and is probably a rare case in the wild, but it
   makes some of our SkCanvas tests easier to deal with.
 - This is because, if you just make an SkCanvas(width, height) directly
   you get an SkNoPixelsDevice but also use the kFullLayer_Strategy.
   SkNoPixelsDevice always fails to create a layer (since it's meant to
   be used with subclasses of SkCanvas that return kNoLayer_Strategy,
   like SkNoDrawCanvas).
 - applying the failed layer bounds as a clip keeps the canvas' reported
   bounds as accurate as possible in this case.
     - in the future, it may be worth updating how SkCanvas can be
       constructed to avoid this, and overhauling the unit tests but
       I didn't want to further delay these changes.

 - it's important that replaceClip() is still used for the kNoLayer case
   because it allows image-filtered layers to expand the clip bounds
   until the restore. This keeps any virtual canvas or recording canvas
   completely in-sync with the base canvas or eventual real canvas that
   is backed by a device that actually draws.

Original change's description:
> Revert "Simplify layer bounds syncing and no-device error handling in SkCanvas::internalSaveLayer"
>
> This reverts commit b27ba538ecd0bb52981c33a9f5731022cd165bdd.
>
> Reason for revert: causes invalid memory accesses due to replaceClip use, and replaceClip() is probably not the right operation to use
> to emulate a layer when no layer was the strategy or failed to allocate.
>
> Original change's description:
> > Simplify layer bounds syncing and no-device error handling in SkCanvas::internalSaveLayer
> >
> > This corrects some subtle bugs that can occur with recording canvas or
> > if a device fails to be created for a new layer, where the stashed
> > matrix would not be restored properly. Since no new DeviceCM would get
> > added in those cases, the canvas' total matrix wouldn't get fixed in the
> > paired onRestore() and it would remain dirty for the remainder of the
> > canvas's lifetime.
> >
> > After this change, the underlying SkDevice's bounds are also kept in
> > sync with the intent of the saveLayer when kNoLayer_Strategy is used.
> > Previously, the bounds would be applied to the canvas' conservative clip
> > and quick reject bounds, but the device would remain un-updated. As we
> > move towards SkNoPixelsDevice taking over the conservative clip bounds,
> > this ensures bounds remain up to date within a saveLayer/restore pair
> > even if no layer was allocated.
> >
> > Change-Id: I5ca389bdd624ea7278106da863a96e9d8f90e2d1
> > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/335861
> > Reviewed-by: Mike Reed <reed@google.com>
> > Commit-Queue: Michael Ludwig <michaelludwig@google.com>
>
> TBR=mtklein@google.com,bsalomon@google.com,reed@google.com,michaelludwig@google.com
>
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: chromium:1151195, chromium:1151270, chromium:1151294, chromium:1151320, chromium:1151322
> Change-Id: I9db07916ffc450cc6ecc9188d72bb7c35770a974
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/337117
> Reviewed-by: Michael Ludwig <michaelludwig@google.com>
> Commit-Queue: Michael Ludwig <michaelludwig@google.com>

TBR=mtklein@google.com,bsalomon@google.com,reed@google.com,michaelludwig@google.com

# Not skipping CQ checks because this is a reland.

Change-Id: Idcab9084c7f19d8f31b11231fd9b52292fc397a3
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/337157
Reviewed-by: Mike Reed <reed@google.com>
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
2 files changed