SkDevice::drawSpecial accepts arbitrary matrix v2

This opens up the door to render image filter results with an arbitrary
matrix, so we can skip the matrix filter DAG hack. It should also let
me simplify the handling of backdrop image filters and correctly apply
perspective to image filters.

This is essentially the same as
https://skia-review.googlesource.com/c/skia/+/317862
but not parented to the CL that experimented with SkImagePaint.

Some of the function declaration re-org that was done in its prior CL
has been directly integrated into this CL.

Bug: skia:9545
Change-Id: Iad882bd306f3a4064fe60cfc0526226287ea7e29
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/323597
Commit-Queue: Mike Klein <mtklein@google.com>
Reviewed-by: Mike Klein <mtklein@google.com>
This commit is contained in:
Michael Ludwig 2020-10-08 16:47:55 -04:00 committed by Skia Commit-Bot
parent 3d87e9f660
commit 7c4aca04cc
14 changed files with 133 additions and 160 deletions

View File

@ -562,29 +562,6 @@ void SkBitmapDevice::drawVertices(const SkVertices* vertices, SkBlendMode bmode,
BDDraw(this).drawVertices(vertices, bmode, paint);
}
void SkBitmapDevice::drawDevice(SkBaseDevice* device, int x, int y, const SkPaint& origPaint) {
SkASSERT(!origPaint.getImageFilter());
SkASSERT(!origPaint.getMaskFilter());
// todo: can we unify with similar adjustment in SkGpuDevice?
SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
// hack to test coverage
SkBitmapDevice* src = static_cast<SkBitmapDevice*>(device);
if (src->fCoverage) {
SkDraw draw;
SkSimpleMatrixProvider matrixProvider(SkMatrix::I());
draw.fDst = fBitmap.pixmap();
draw.fMatrixProvider = &matrixProvider;
draw.fRC = &fRCStack.rc();
paint.writable()->setShader(src->fBitmap.makeShader());
draw.drawBitmap(*src->fCoverage,
SkMatrix::Translate(SkIntToScalar(x),SkIntToScalar(y)), nullptr, *paint);
} else {
BDDraw(this).drawSprite(src->fBitmap, x, y, *paint);
}
}
void SkBitmapDevice::drawAtlas(const SkImage* atlas, const SkRSXform xform[],
const SkRect tex[], const SkColor colors[], int count,
SkBlendMode mode, const SkPaint& paint) {
@ -598,16 +575,44 @@ void SkBitmapDevice::drawAtlas(const SkImage* atlas, const SkRSXform xform[],
///////////////////////////////////////////////////////////////////////////////
void SkBitmapDevice::drawSpecial(SkSpecialImage* src, int x, int y, const SkPaint& paint) {
SkASSERT(!src->isTextureBacked());
SkASSERT(!paint.getMaskFilter() && !paint.getImageFilter());
void SkBitmapDevice::drawDevice(SkBaseDevice* device, const SkPaint& paint) {
SkASSERT(!paint.getImageFilter());
SkASSERT(!paint.getMaskFilter());
SkBitmap resultBM;
if (src->getROPixels(&resultBM)) {
BDDraw(this).drawSprite(resultBM, x, y, paint);
// hack to test coverage
SkBitmapDevice* src = static_cast<SkBitmapDevice*>(device);
if (src->fCoverage) {
SkDraw draw;
SkSimpleMatrixProvider matrixProvider(device->getRelativeTransform(*this));
draw.fDst = fBitmap.pixmap();
draw.fMatrixProvider = &matrixProvider;
draw.fRC = &fRCStack.rc();
SkPaint deviceAsShader = paint;
deviceAsShader.setShader(src->fBitmap.makeShader());
draw.drawBitmap(*src->fCoverage, SkMatrix::I(), nullptr, deviceAsShader);
} else {
this->INHERITED::drawDevice(device, paint);
}
}
void SkBitmapDevice::drawSpecial(SkSpecialImage* src,
const SkMatrix& localToDevice,
const SkPaint& paint) {
SkASSERT(!paint.getImageFilter());
SkASSERT(!paint.getMaskFilter());
SkASSERT(!src->isTextureBacked());
SkBitmap resultBM;
if (src->getROPixels(&resultBM)) {
SkDraw draw;
SkSimpleMatrixProvider matrixProvider(localToDevice);
draw.fDst = fBitmap.pixmap();
draw.fMatrixProvider = &matrixProvider;
draw.fRC = &fRCStack.rc();
draw.drawBitmap(resultBM, SkMatrix::I(), nullptr, paint);
}
}
sk_sp<SkSpecialImage> SkBitmapDevice::makeSpecial(const SkBitmap& bitmap) {
return SkSpecialImage::MakeFromRaster(bitmap.bounds(), bitmap);
}

View File

@ -97,11 +97,12 @@ protected:
void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override;
void drawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int count,
SkBlendMode, const SkPaint&) override;
void drawDevice(SkBaseDevice*, int x, int y, const SkPaint&) override;
///////////////////////////////////////////////////////////////////////////
void drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&) override;
void drawDevice(SkBaseDevice*, const SkPaint&) override;
void drawSpecial(SkSpecialImage*, const SkMatrix&, const SkPaint&) override;
sk_sp<SkSpecialImage> makeSpecial(const SkBitmap&) override;
sk_sp<SkSpecialImage> makeSpecial(const SkImage*) override;
sk_sp<SkSpecialImage> snapSpecial(const SkIRect&, bool = false) override;

View File

@ -914,7 +914,7 @@ void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filt
if (special) {
// The image is drawn at 1-1 scale with integer translation, so no filtering is needed.
SkPaint p;
dst->drawSpecial(special.get(), 0, 0, p);
dst->drawSpecial(special.get(), SkMatrix::I(), p);
}
return;
}
@ -1038,20 +1038,11 @@ void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filt
// Manually setting the device's CTM requires accounting for the device's origin.
// TODO (michaelludwig) - This could be simpler if the dst device had its origin configured
// before filtering the backdrop device, and if SkAutoDeviceTransformRestore had a way to accept
// a global CTM instead of a device CTM.
// before filtering the backdrop device and we use skif::Mapping instead.
SkMatrix dstCTM = toRoot;
dstCTM.postTranslate(-dstOrigin.x(), -dstOrigin.y());
SkAutoDeviceTransformRestore adr(dst, dstCTM);
// And because devices don't have a special-image draw function that supports arbitrary
// matrices, we are abusing the asImage() functionality here...
SkRect specialSrc = SkRect::Make(special->subset());
auto looseImage = special->asImage();
dst->drawImageRect(
looseImage.get(), &specialSrc,
SkRect::MakeXYWH(offset.x(), offset.y(), special->width(), special->height()),
p, kStrict_SrcRectConstraint);
dstCTM.preTranslate(offset.fX, offset.fY);
dst->drawSpecial(special.get(), dstCTM, p);
}
}
@ -1276,9 +1267,9 @@ void SkCanvas::internalRestore() {
if (backImage) {
SkPaint paint;
paint.setBlendMode(SkBlendMode::kDstOver);
const int x = backImage->fLoc.x();
const int y = backImage->fLoc.y();
this->getTopDevice()->drawSpecial(backImage->fImage.get(), x, y, paint);
this->getTopDevice()->drawSpecial(backImage->fImage.get(),
SkMatrix::Translate(backImage->fLoc.x(),
backImage->fLoc.y()), paint);
}
/* Time to draw the layer's offscreen. We can't call the public drawSprite,
@ -1413,28 +1404,16 @@ void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, const SkPaint* paint) {
check_drawdevice_colorspaces(dstDev->imageInfo().colorSpace(),
srcDev->imageInfo().colorSpace());
SkTCopyOnFirstWrite<SkPaint> noFilterPaint(*paint);
SkImageFilter* filter = paint->getImageFilter();
SkTCopyOnFirstWrite<SkPaint> noFilterPaint(draw.paint());
SkImageFilter* filter = draw.paint().getImageFilter();
if (filter) {
// Check if the image filter was just a color filter (this is the same optimization
// we apply in AutoLayerForImageFilter but handles explicitly saved layers).
sk_sp<SkColorFilter> cf = image_to_color_filter(*paint);
if (cf) {
noFilterPaint.writable()->setColorFilter(std::move(cf));
filter = nullptr;
}
noFilterPaint.writable()->setImageFilter(nullptr);
}
SkASSERT(!noFilterPaint->getImageFilter());
if (!filter) {
// Can draw the src device's buffer w/o any extra image filter evaluation
// (although this draw may include color filter processing extracted from the IF DAG).
// TODO (michaelludwig) - Once drawSpecial can take a matrix, drawDevice should take
// no extra arguments and internally just use the relative transform from src to dst.
SkIPoint pos = srcDev->getOrigin() - dstDev->getOrigin();
dstDev->drawDevice(srcDev, pos.x(), pos.y(), *noFilterPaint);
dstDev->drawDevice(srcDev, *noFilterPaint);
} else {
// Use the whole device buffer, presumably it was sized appropriately to match the
// desired output size of the destination when the layer was first saved.

View File

@ -317,7 +317,7 @@ void SkBaseDevice::drawDrawable(SkDrawable* drawable, const SkMatrix* matrix, Sk
///////////////////////////////////////////////////////////////////////////////////////////////////
void SkBaseDevice::drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&) {}
void SkBaseDevice::drawSpecial(SkSpecialImage*, const SkMatrix&, const SkPaint&) {}
sk_sp<SkSpecialImage> SkBaseDevice::makeSpecial(const SkBitmap&) { return nullptr; }
sk_sp<SkSpecialImage> SkBaseDevice::makeSpecial(const SkImage*) { return nullptr; }
sk_sp<SkSpecialImage> SkBaseDevice::snapSpecial(const SkIRect&, bool) { return nullptr; }
@ -325,6 +325,13 @@ sk_sp<SkSpecialImage> SkBaseDevice::snapSpecial() {
return this->snapSpecial(SkIRect::MakeWH(this->width(), this->height()));
}
void SkBaseDevice::drawDevice(SkBaseDevice* device, const SkPaint& paint) {
sk_sp<SkSpecialImage> deviceImage = device->snapSpecial();
if (deviceImage) {
this->drawSpecial(deviceImage.get(), device->getRelativeTransform(*this), paint);
}
}
void SkBaseDevice::drawFilteredImage(const skif::Mapping& mapping, SkSpecialImage* src,
const SkImageFilter* filter, const SkPaint& paint) {
SkASSERT(!paint.getImageFilter() && !paint.getMaskFilter());
@ -350,13 +357,9 @@ void SkBaseDevice::drawFilteredImage(const skif::Mapping& mapping, SkSpecialImag
SkIPoint offset;
sk_sp<SkSpecialImage> result = as_IFB(filter)->filterImage(ctx).imageAndOffset(&offset);
if (result) {
// TODO(michaelludwig) - Eventually drawSpecial will take a matrix and we can just
// draw using mapping.deviceMatrix() directly. For now, all devices are relative to each
// other by a translation, or its a translation-only sprite draw.
SkASSERT(mapping.deviceMatrix().isTranslate());
offset.fX += SkScalarRoundToInt(mapping.deviceMatrix().getTranslateX());
offset.fY += SkScalarRoundToInt(mapping.deviceMatrix().getTranslateY());
this->drawSpecial(result.get(), offset.fX, offset.fY, paint);
SkMatrix deviceMatrixWithOffset = mapping.deviceMatrix();
deviceMatrixWithOffset.preTranslate(offset.fX, offset.fY);
this->drawSpecial(result.get(), deviceMatrixWithOffset, paint);
}
}

View File

@ -299,12 +299,21 @@ protected:
virtual void drawDrawable(SkDrawable*, const SkMatrix*, SkCanvas*);
/** The SkDevice passed will be an SkDevice which was returned by a call to
onCreateDevice on this device with kNeverTile_TileExpectation.
/**
* The SkDevice passed will be an SkDevice which was returned by a call to
* onCreateDevice on this device with kNeverTile_TileExpectation.
*
* The default implementation calls snapSpecial() and drawSpecial() with the relative transform
* from the input device to this device. The provided SkPaint cannot have a mask filter or
* image filter, and any shader is ignored.
*/
virtual void drawDevice(SkBaseDevice*, int x, int y, const SkPaint&) = 0;
virtual void drawDevice(SkBaseDevice*, const SkPaint&);
virtual void drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&);
/**
* Draw the special image's subset to this device, subject to the given matrix transform instead
* of the device's current local to device matrix.
*/
virtual void drawSpecial(SkSpecialImage*, const SkMatrix& localToDevice, const SkPaint&);
/**
* Evaluate 'filter' and draw the final output into this device using 'paint'. The 'mapping'
@ -516,7 +525,7 @@ protected:
void drawOval(const SkRect&, const SkPaint&) override {}
void drawRRect(const SkRRect&, const SkPaint&) override {}
void drawPath(const SkPath&, const SkPaint&, bool) override {}
void drawDevice(SkBaseDevice*, int, int, const SkPaint&) override {}
void drawDevice(SkBaseDevice*, const SkPaint&) override {}
void drawGlyphRunList(const SkGlyphRunList& glyphRunList) override {}
void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override {}

View File

@ -781,23 +781,11 @@ sk_sp<SkSpecialImage> SkGpuDevice::snapSpecial(const SkIRect& subset, bool force
&this->surfaceProps());
}
void SkGpuDevice::drawDevice(SkBaseDevice* device,
int left, int top, const SkPaint& paint) {
SkASSERT(!paint.getImageFilter());
SkASSERT(!paint.getMaskFilter());
void SkGpuDevice::drawDevice(SkBaseDevice* device, const SkPaint& paint) {
ASSERT_SINGLE_OWNER
// clear of the source device must occur before CHECK_SHOULD_DRAW
GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawDevice", fContext.get());
// drawDevice is defined to be in device coords.
SkGpuDevice* dev = static_cast<SkGpuDevice*>(device);
sk_sp<SkSpecialImage> srcImg(dev->snapSpecial(SkIRect::MakeWH(dev->width(), dev->height())));
if (!srcImg) {
return;
}
this->drawSpecial(srcImg.get(), left, top, paint);
this->INHERITED::drawDevice(device, paint);
}
void SkGpuDevice::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,

View File

@ -118,9 +118,8 @@ public:
void drawDrawable(SkDrawable*, const SkMatrix*, SkCanvas* canvas) override;
void drawDevice(SkBaseDevice*, int x, int y, const SkPaint&) override;
void drawSpecial(SkSpecialImage*, int left, int top, const SkPaint&) override;
void drawDevice(SkBaseDevice*, const SkPaint&) override;
void drawSpecial(SkSpecialImage*, const SkMatrix&, const SkPaint&) override;
void drawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4], SkCanvas::QuadAAFlags aaFlags,
const SkColor4f& color, SkBlendMode mode) override;

View File

@ -651,17 +651,20 @@ void draw_tiled_bitmap(GrRecordingContext* context,
//////////////////////////////////////////////////////////////////////////////
void SkGpuDevice::drawSpecial(SkSpecialImage* special, int left, int top, const SkPaint& paint) {
void SkGpuDevice::drawSpecial(SkSpecialImage* special, const SkMatrix& localToDevice,
const SkPaint& paint) {
SkASSERT(!paint.getMaskFilter() && !paint.getImageFilter());
SkASSERT(special->isTextureBacked());
SkRect src = SkRect::Make(special->subset());
SkRect dst = SkRect::MakeXYWH(left, top, special->width(), special->height());
SkRect dst = SkRect::MakeWH(special->width(), special->height());
SkMatrix srcToDst = SkMatrix::MakeRectToRect(src, dst, SkMatrix::kFill_ScaleToFit);
// TODO (michaelludwig): Once drawSpecial uses arbitrary transforms between two SkGpuDevices,
// always using kNearest may not be the right choice anymore.
GrSamplerState sampler(GrSamplerState::WrapMode::kClamp, GrSamplerState::Filter::kNearest);
GrSamplerState sampler(GrSamplerState::WrapMode::kClamp,
paint.getFilterQuality() >= kLow_SkFilterQuality ?
GrSamplerState::Filter::kLinear : GrSamplerState::Filter::kNearest);
GrAA aa = paint.isAntiAlias() ? GrAA::kYes : GrAA::kNo;
GrQuadAAFlags aaFlags = paint.isAntiAlias() ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone;
GrColorInfo colorInfo(SkColorTypeToGrColorType(special->colorType()),
special->alphaType(), sk_ref_sp(special->getColorSpace()));
@ -670,11 +673,10 @@ void SkGpuDevice::drawSpecial(SkSpecialImage* special, int left, int top, const
GrTextureAdjuster texture(fContext.get(), std::move(view), colorInfo, special->uniqueID());
// In most cases this ought to hit draw_texture since there won't be a color filter,
// alpha-only texture+shader, or a high filter quality.
SkOverrideDeviceMatrixProvider identity(this->asMatrixProvider(), SkMatrix::I());
SkOverrideDeviceMatrixProvider matrixProvider(this->asMatrixProvider(), localToDevice);
draw_texture_producer(fContext.get(), fRenderTargetContext.get(), this->clip(),
identity, paint, &texture, src, dst, nullptr, srcToDst, GrAA::kNo,
GrQuadAAFlags::kNone, SkCanvas::kStrict_SrcRectConstraint,
sampler, false);
matrixProvider, paint, &texture, src, dst, nullptr, srcToDst, aa,
aaFlags, SkCanvas::kStrict_SrcRectConstraint, sampler, false);
}
void SkGpuDevice::drawImageQuad(const SkImage* image, const SkRect* srcRect, const SkRect* dstRect,

View File

@ -969,42 +969,6 @@ void SkPDFDevice::drawFormXObject(SkPDFIndirectReference xObject, SkDynamicMemor
content->writeText(" Do\n");
}
void SkPDFDevice::drawDevice(SkBaseDevice* device, int x, int y, const SkPaint& paint) {
SkASSERT(!paint.getImageFilter());
SkASSERT(!paint.getMaskFilter());
// Check if the source device is really a bitmapdevice (because that's what we returned
// from createDevice (likely due to an imagefilter)
SkPixmap pmap;
if (device->peekPixels(&pmap)) {
SkBitmap bitmap;
bitmap.installPixels(pmap);
this->drawSprite(bitmap, x, y, paint);
return;
}
// our onCreateCompatibleDevice() always creates SkPDFDevice subclasses.
SkPDFDevice* pdfDevice = static_cast<SkPDFDevice*>(device);
if (pdfDevice->isContentEmpty()) {
return;
}
SkMatrix matrix = SkMatrix::Translate(SkIntToScalar(x), SkIntToScalar(y));
ScopedContentEntry content(this, &this->cs(), matrix, paint);
if (!content) {
return;
}
if (content.needShape()) {
SkISize dim = device->imageInfo().dimensions();
content.setShape(SkPath::Rect(SkRect::Make(SkIRect::MakeXYWH(x, y, dim.width(), dim.height()))));
}
if (!content.needSource()) {
return;
}
this->drawFormXObject(pdfDevice->makeFormXObjectFromDevice(), content.stream());
}
sk_sp<SkSurface> SkPDFDevice::makeSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
return SkSurface::MakeRaster(info, &props);
}
@ -1701,10 +1665,45 @@ void SkPDFDevice::internalDrawImageRect(SkKeyedImage imageSubset,
///////////////////////////////////////////////////////////////////////////////////////////////////
#include "include/core/SkImageFilter.h"
#include "src/core/SkSpecialImage.h"
void SkPDFDevice::drawSpecial(SkSpecialImage* srcImg, int x, int y, const SkPaint& paint) {
void SkPDFDevice::drawDevice(SkBaseDevice* device, const SkPaint& paint) {
SkASSERT(!paint.getImageFilter());
SkASSERT(!paint.getMaskFilter());
// Check if the source device is really a bitmapdevice (because that's what we returned
// from createDevice (an image filter would go through drawSpecial, but createDevice uses
// a raster device to apply color filters, too).
SkPixmap pmap;
if (device->peekPixels(&pmap)) {
this->INHERITED::drawDevice(device, paint);
return;
}
// our onCreateCompatibleDevice() always creates SkPDFDevice subclasses.
SkPDFDevice* pdfDevice = static_cast<SkPDFDevice*>(device);
if (pdfDevice->isContentEmpty()) {
return;
}
SkMatrix matrix = device->getRelativeTransform(*this);
ScopedContentEntry content(this, &this->cs(), matrix, paint);
if (!content) {
return;
}
if (content.needShape()) {
SkPath shape = SkPath::Rect(SkRect::Make(device->imageInfo().dimensions()));
shape.transform(matrix);
content.setShape(shape);
}
if (!content.needSource()) {
return;
}
this->drawFormXObject(pdfDevice->makeFormXObjectFromDevice(), content.stream());
}
void SkPDFDevice::drawSpecial(SkSpecialImage* srcImg, const SkMatrix& localToDevice,
const SkPaint& paint) {
if (this->hasEmptyClip()) {
return;
}
@ -1713,7 +1712,8 @@ void SkPDFDevice::drawSpecial(SkSpecialImage* srcImg, int x, int y, const SkPain
SkBitmap resultBM;
if (srcImg->getROPixels(&resultBM)) {
this->drawSprite(resultBM, x, y, paint);
auto r = SkRect::MakeWH(resultBM.width(), resultBM.height());
this->internalDrawImageRect(SkKeyedImage(resultBM), nullptr, r, paint, localToDevice);
}
}

View File

@ -85,8 +85,6 @@ public:
SkCanvas::SrcRectConstraint) override;
void drawGlyphRunList(const SkGlyphRunList& glyphRunList) override;
void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override;
void drawDevice(SkBaseDevice*, int x, int y,
const SkPaint&) override;
// PDF specific methods.
void drawSprite(const SkBitmap& bitmap, int x, int y,
@ -111,7 +109,9 @@ protected:
void drawAnnotation(const SkRect&, const char key[], SkData* value) override;
void drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&) override;
void drawDevice(SkBaseDevice*, const SkPaint&) override;
void drawSpecial(SkSpecialImage*, const SkMatrix&, const SkPaint&) override;
sk_sp<SkSpecialImage> makeSpecial(const SkBitmap&) override;
sk_sp<SkSpecialImage> makeSpecial(const SkImage*) override;
SkImageFilterCache* getImageFilterCache() override;

View File

@ -1092,8 +1092,3 @@ void SkSVGDevice::drawGlyphRunList(const SkGlyphRunList& glyphRunList) {
void SkSVGDevice::drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) {
// todo
}
void SkSVGDevice::drawDevice(SkBaseDevice*, int x, int y,
const SkPaint&) {
// todo
}

View File

@ -36,9 +36,6 @@ protected:
void drawGlyphRunList(const SkGlyphRunList& glyphRunList) override;
void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override;
void drawDevice(SkBaseDevice*, int x, int y,
const SkPaint&) override;
private:
SkSVGDevice(const SkISize& size, std::unique_ptr<SkXMLWriter>, uint32_t);
~SkSVGDevice() override;

View File

@ -1954,16 +1954,12 @@ void SkXPSDevice::drawGlyphRunList(const SkGlyphRunList& glyphRunList) {
}
}
void SkXPSDevice::drawDevice(SkBaseDevice* dev,
int x, int y,
const SkPaint&) {
void SkXPSDevice::drawDevice(SkBaseDevice* dev, const SkPaint&) {
SkXPSDevice* that = static_cast<SkXPSDevice*>(dev);
SkASSERT(that->fTopTypefaces == this->fTopTypefaces);
SkTScopedComPtr<IXpsOMMatrixTransform> xpsTransform;
// TODO(halcanary): assert that current transform is identity rather than calling setter.
XPS_MATRIX rawTransform = {1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f};
HRVM(this->fXpsFactory->CreateMatrixTransform(&rawTransform, &xpsTransform),
HRVM(this->createXpsTransform(dev->getRelativeTransform(*this), &xpsTransform),
"Could not create layer transform.");
HRVM(that->fCurrentXpsCanvas->SetTransformLocal(xpsTransform.get()),
"Could not set layer transform.");

View File

@ -94,8 +94,7 @@ protected:
SkCanvas::SrcRectConstraint) override;
void drawGlyphRunList(const SkGlyphRunList& glyphRunList) override;
void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override;
void drawDevice(SkBaseDevice*, int x, int y,
const SkPaint&) override;
void drawDevice(SkBaseDevice*, const SkPaint&) override;
private:
class TypefaceUse {