Reland "Track device coordinate space as matrix"
This reverts commit915b779f9c
. Reason for revert: finally coming back to this, figure out what's wrong on Android Original change's description: > Revert "Track device coordinate space as matrix" > > This reverts commitb74d5548a4
. > > Reason for revert: see if this fixes the android roll > > Original change's description: > > Track device coordinate space as matrix > > > > This is a required step to be able to cleanly draw image filtered > > device layers with arbitrary matrices, instead of relying on > > SkMatrixImageFilter to apply the transformation. > > > > Bug: skia:9545 > > Change-Id: I8d84679a281538875cf4a1b73565294fb7f89c86 > > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/249076 > > Commit-Queue: Michael Ludwig <michaelludwig@google.com> > > Reviewed-by: Mike Reed <reed@google.com> > > TBR=robertphillips@google.com,reed@google.com,michaelludwig@google.com > > # Not skipping CQ checks because original CL landed > 1 day ago. > > Bug: skia:9545 > Change-Id: Ie374a7500cfbff35cb0782beb863086e118a005a > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/249986 > Reviewed-by: Michael Ludwig <michaelludwig@google.com> > Commit-Queue: Michael Ludwig <michaelludwig@google.com> TBR=robertphillips@google.com,reed@google.com,michaelludwig@google.com # Not skipping CQ checks because original CL landed > 1 day ago. Bug: skia:9545 Change-Id: If31a9be86cb340a0874533c044c19b6787d5f176 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/272340 Reviewed-by: Mike Reed <reed@google.com> Commit-Queue: Michael Ludwig <michaelludwig@google.com>
This commit is contained in:
parent
93afe641d0
commit
fb3f302bdf
@ -2712,6 +2712,7 @@ private:
|
||||
intptr_t fStorage[32];
|
||||
class SkDrawIter* fImpl; // this points at fStorage
|
||||
SkPaint fDefaultPaint;
|
||||
SkIPoint fDeviceOrigin;
|
||||
bool fDone;
|
||||
};
|
||||
|
||||
@ -2842,7 +2843,7 @@ private:
|
||||
void internalDrawPaint(const SkPaint& paint);
|
||||
void internalSaveLayer(const SaveLayerRec&, SaveLayerStrategy);
|
||||
void internalSaveBehind(const SkRect*);
|
||||
void internalDrawDevice(SkBaseDevice*, int x, int y, const SkPaint*, SkImage* clipImage,
|
||||
void internalDrawDevice(SkBaseDevice*, const SkPaint*, SkImage* clipImage,
|
||||
const SkMatrix& clipMatrix);
|
||||
|
||||
// shared by save() and saveLayer()
|
||||
|
@ -826,3 +826,7 @@ SkBaseDevice::ClipType SkBitmapDevice::onGetClipType() const {
|
||||
return ClipType::kComplex;
|
||||
}
|
||||
}
|
||||
|
||||
SkIRect SkBitmapDevice::onDevClipBounds() const {
|
||||
return fRCStack.rc().getBounds();
|
||||
}
|
||||
|
@ -133,6 +133,7 @@ protected:
|
||||
void onAsRgnClip(SkRegion*) const override;
|
||||
void validateDevBounds(const SkIRect& r) override;
|
||||
ClipType onGetClipType() const override;
|
||||
SkIRect onDevClipBounds() const override;
|
||||
|
||||
virtual void drawBitmap(const SkBitmap&, const SkMatrix&, const SkRect* dstOrNull,
|
||||
const SkPaint&);
|
||||
|
@ -290,8 +290,6 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
int getX() const { return fDevice->getOrigin().x(); }
|
||||
int getY() const { return fDevice->getOrigin().y(); }
|
||||
const SkPaint* getPaint() const { return fPaint; }
|
||||
|
||||
SkBaseDevice* fDevice;
|
||||
@ -634,7 +632,7 @@ SkIRect SkCanvas::getTopLayerBounds() const {
|
||||
if (!d) {
|
||||
return SkIRect::MakeEmpty();
|
||||
}
|
||||
return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
|
||||
return d->getGlobalBounds();
|
||||
}
|
||||
|
||||
SkBaseDevice* SkCanvas::getDevice() const {
|
||||
@ -912,7 +910,8 @@ void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filt
|
||||
// The local bounds of the src device; all the bounds passed to snapSpecial must be intersected
|
||||
// with this rect.
|
||||
const SkIRect srcDevRect = SkIRect::MakeWH(src->width(), src->height());
|
||||
|
||||
// TODO(michaelludwig) - Update this function to use the relative transforms between src and
|
||||
// dst; for now, since devices never have complex transforms, we can keep using getOrigin().
|
||||
if (!filter) {
|
||||
// All non-filtered devices are currently axis aligned, so they only differ by their origin.
|
||||
// This means that we only have to copy a dst-sized block of pixels out of src and translate
|
||||
@ -1224,27 +1223,26 @@ int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
|
||||
}
|
||||
|
||||
void SkCanvas::internalSaveBehind(const SkRect* localBounds) {
|
||||
SkIRect devBounds;
|
||||
if (localBounds) {
|
||||
SkRect tmp;
|
||||
fMCRec->fMatrix.mapRect(&tmp, *localBounds);
|
||||
if (!devBounds.intersect(tmp.round(), this->getDeviceClipBounds())) {
|
||||
devBounds.setEmpty();
|
||||
}
|
||||
} else {
|
||||
devBounds = this->getDeviceClipBounds();
|
||||
}
|
||||
if (devBounds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
SkBaseDevice* device = this->getTopDevice();
|
||||
if (nullptr == device) { // Do we still need this check???
|
||||
return;
|
||||
}
|
||||
|
||||
// need the bounds relative to the device itself
|
||||
devBounds.offset(-device->fOrigin.fX, -device->fOrigin.fY);
|
||||
// Map the local bounds into the top device's coordinate space (this is not
|
||||
// necessarily the full global CTM transform).
|
||||
SkIRect devBounds;
|
||||
if (localBounds) {
|
||||
SkRect tmp;
|
||||
device->localToDevice().mapRect(&tmp, *localBounds);
|
||||
if (!devBounds.intersect(tmp.round(), device->devClipBounds())) {
|
||||
devBounds.setEmpty();
|
||||
}
|
||||
} else {
|
||||
devBounds = device->devClipBounds();
|
||||
}
|
||||
if (devBounds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This is getting the special image from the current device, which is then drawn into (both by
|
||||
// a client, and the drawClippedToSaveBehind below). Since this is not saving a layer, with its
|
||||
@ -1304,14 +1302,13 @@ void SkCanvas::internalRestore() {
|
||||
*/
|
||||
if (layer) {
|
||||
if (fMCRec) {
|
||||
const SkIPoint& origin = layer->fDevice->getOrigin();
|
||||
layer->fDevice->setImmutable();
|
||||
this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
|
||||
layer->fPaint.get(),
|
||||
// At this point, 'layer' has been removed from the device stack, so the devices that
|
||||
// internalDrawDevice sees are the destinations that 'layer' is drawn into.
|
||||
this->internalDrawDevice(layer->fDevice.get(), layer->fPaint.get(),
|
||||
layer->fClipImage.get(), layer->fClipMatrix);
|
||||
// restore what we smashed in internalSaveLayer
|
||||
this->internalSetMatrix(layer->fStashedMatrix);
|
||||
// reset this, since internalDrawDevice will have set it to true
|
||||
delete layer;
|
||||
} else {
|
||||
// we're at the root
|
||||
@ -1389,7 +1386,17 @@ void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoi
|
||||
*rowBytes = pmap.rowBytes();
|
||||
}
|
||||
if (origin) {
|
||||
*origin = this->getTopDevice()->getOrigin();
|
||||
// If the caller requested the origin, they presumably are expecting the returned pixels to
|
||||
// be axis-aligned with the root canvas. If the top level device isn't axis aligned, that's
|
||||
// not the case. Until we update accessTopLayerPixels() to accept a coord space matrix
|
||||
// instead of an origin, just don't expose the pixels in that case. Note that this means
|
||||
// that layers with complex coordinate spaces can still report their pixels if the caller
|
||||
// does not ask for the origin (e.g. just to dump its output to a file, etc).
|
||||
if (this->getTopDevice()->isPixelAlignedToGlobal()) {
|
||||
*origin = this->getTopDevice()->getOrigin();
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return pmap.writable_addr();
|
||||
}
|
||||
@ -1409,7 +1416,7 @@ static void check_drawdevice_colorspaces(SkColorSpace* src, SkColorSpace* dst) {
|
||||
SkASSERT(src == dst);
|
||||
}
|
||||
|
||||
void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
|
||||
void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, const SkPaint* paint,
|
||||
SkImage* clipImage, const SkMatrix& clipMatrix) {
|
||||
SkPaint tmp;
|
||||
if (nullptr == paint) {
|
||||
@ -1424,7 +1431,10 @@ void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPa
|
||||
srcDev->imageInfo().colorSpace());
|
||||
paint = &draw.paint();
|
||||
SkImageFilter* filter = paint->getImageFilter();
|
||||
SkIPoint pos = { x - iter.getX(), y - iter.getY() };
|
||||
// TODO(michaelludwig) - Devices aren't created with complex coordinate systems yet,
|
||||
// so it should always be possible to use the relative origin. Once drawDevice() and
|
||||
// drawSpecial() take an SkMatrix, this can switch to getRelativeTransform() instead.
|
||||
SkIPoint pos = srcDev->getOrigin() - dstDev->getOrigin();
|
||||
if (filter || clipImage) {
|
||||
sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
|
||||
if (specialImage) {
|
||||
@ -2344,7 +2354,7 @@ void SkCanvas::onDrawBehind(const SkPaint& paint) {
|
||||
// We use clipRegion because it is already defined to operate in dev-space
|
||||
// (i.e. ignores the ctm). However, it is going to first translate by -origin,
|
||||
// but we don't want that, so we undo that before calling in.
|
||||
SkRegion rgn(bounds.makeOffset(dev->fOrigin));
|
||||
SkRegion rgn(bounds.makeOffset(dev->getOrigin()));
|
||||
dev->clipRegion(rgn, SkClipOp::kIntersect);
|
||||
dev->drawPaint(draw.paint());
|
||||
dev->restore(fMCRec->fMatrix);
|
||||
@ -3097,6 +3107,11 @@ SkCanvas::LayerIter::~LayerIter() {
|
||||
|
||||
void SkCanvas::LayerIter::next() {
|
||||
fDone = !fImpl->next();
|
||||
if (!fDone) {
|
||||
// Cache the device origin. LayerIter is only used in Android, which doesn't use image
|
||||
// filters, so its devices will always be able to report the origin exactly.
|
||||
fDeviceOrigin = fImpl->fDevice->getOrigin();
|
||||
}
|
||||
}
|
||||
|
||||
SkBaseDevice* SkCanvas::LayerIter::device() const {
|
||||
@ -3119,8 +3134,8 @@ SkIRect SkCanvas::LayerIter::clipBounds() const {
|
||||
return fImpl->fDevice->getGlobalBounds();
|
||||
}
|
||||
|
||||
int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
|
||||
int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
|
||||
int SkCanvas::LayerIter::x() const { return fDeviceOrigin.fX; }
|
||||
int SkCanvas::LayerIter::y() const { return fDeviceOrigin.fY; }
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -3201,17 +3216,12 @@ SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
|
||||
if (fAllocator && fMCRec->fTopLayer->fDevice) {
|
||||
const auto& dev = fMCRec->fTopLayer->fDevice;
|
||||
SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
|
||||
SkIPoint origin = dev->getOrigin();
|
||||
SkMatrix ctm = this->getTotalMatrix();
|
||||
ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
|
||||
|
||||
SkIRect clip = fMCRec->fRasterClip.getBounds();
|
||||
clip.offset(-origin.x(), -origin.y());
|
||||
SkIRect clip = dev->devClipBounds();
|
||||
if (!clip.intersect({0, 0, dev->width(), dev->height()})) {
|
||||
clip.setEmpty();
|
||||
}
|
||||
|
||||
fAllocator->updateHandle(handle, ctm, clip);
|
||||
fAllocator->updateHandle(handle, dev->localToDevice(), clip);
|
||||
return handle;
|
||||
}
|
||||
return nullptr;
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include "src/core/SkDraw.h"
|
||||
#include "src/core/SkRasterClip.h"
|
||||
|
||||
SkIRect SkClipStackDevice::devClipBounds() const {
|
||||
SkIRect SkClipStackDevice::onDevClipBounds() const {
|
||||
SkIRect r = fClipStack.bounds(this->imageInfo().bounds()).roundOut();
|
||||
if (!r.isEmpty()) {
|
||||
SkASSERT(this->imageInfo().bounds().contains(r));
|
||||
|
@ -21,8 +21,6 @@ public:
|
||||
SkClipStack& cs() { return fClipStack; }
|
||||
const SkClipStack& cs() const { return fClipStack; }
|
||||
|
||||
SkIRect devClipBounds() const;
|
||||
|
||||
protected:
|
||||
void onSave() override;
|
||||
void onRestore() override;
|
||||
@ -35,6 +33,7 @@ protected:
|
||||
bool onClipIsWideOpen() const override;
|
||||
void onAsRgnClip(SkRegion*) const override;
|
||||
ClipType onGetClipType() const override;
|
||||
SkIRect onDevClipBounds() const override;
|
||||
|
||||
private:
|
||||
enum {
|
||||
|
@ -33,28 +33,63 @@
|
||||
#include "src/utils/SkPatchUtils.h"
|
||||
|
||||
SkBaseDevice::SkBaseDevice(const SkImageInfo& info, const SkSurfaceProps& surfaceProps)
|
||||
: fInfo(info)
|
||||
, fSurfaceProps(surfaceProps)
|
||||
{
|
||||
fOrigin = {0, 0};
|
||||
: fInfo(info)
|
||||
, fSurfaceProps(surfaceProps) {
|
||||
fDeviceToGlobal.reset();
|
||||
fGlobalToDevice.reset();
|
||||
fLocalToDevice.reset();
|
||||
}
|
||||
|
||||
void SkBaseDevice::setOrigin(const SkMatrix& globalCTM, int x, int y) {
|
||||
fOrigin.set(x, y);
|
||||
fLocalToDevice = globalCTM;
|
||||
void SkBaseDevice::setDeviceCoordinateSystem(const SkMatrix& deviceToGlobal,
|
||||
const SkMatrix& localToDevice,
|
||||
int bufferOriginX,
|
||||
int bufferOriginY) {
|
||||
fDeviceToGlobal = deviceToGlobal;
|
||||
fDeviceToGlobal.normalizePerspective();
|
||||
SkAssertResult(deviceToGlobal.invert(&fGlobalToDevice));
|
||||
|
||||
fLocalToDevice = localToDevice;
|
||||
fLocalToDevice.normalizePerspective();
|
||||
fLocalToDevice.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
|
||||
if (bufferOriginX | bufferOriginY) {
|
||||
fDeviceToGlobal.preTranslate(bufferOriginX, bufferOriginY);
|
||||
fGlobalToDevice.postTranslate(-bufferOriginX, -bufferOriginY);
|
||||
fLocalToDevice.postTranslate(-bufferOriginX, -bufferOriginY);
|
||||
}
|
||||
}
|
||||
|
||||
void SkBaseDevice::setGlobalCTM(const SkCanvasMatrix& ctm) {
|
||||
fLocalToDevice = ctm;
|
||||
fLocalToDevice.normalizePerspective();
|
||||
if (fOrigin.fX | fOrigin.fY) {
|
||||
fLocalToDevice.postTranslate(-SkIntToScalar(fOrigin.fX), -SkIntToScalar(fOrigin.fY));
|
||||
if (!fGlobalToDevice.isIdentity()) {
|
||||
// Map from the global CTM state to this device's coordinate system.
|
||||
fLocalToDevice.postConcat(fGlobalToDevice);
|
||||
}
|
||||
}
|
||||
|
||||
bool SkBaseDevice::isPixelAlignedToGlobal() const {
|
||||
return fDeviceToGlobal.isTranslate() &&
|
||||
SkScalarIsInt(fDeviceToGlobal.getTranslateX()) &&
|
||||
SkScalarIsInt(fDeviceToGlobal.getTranslateY());
|
||||
}
|
||||
|
||||
SkIPoint SkBaseDevice::getOrigin() const {
|
||||
// getOrigin() is deprecated, the old origin has been moved into the fDeviceToGlobal matrix.
|
||||
// This extracts the origin from the matrix, but asserts that a more complicated coordinate
|
||||
// space hasn't been set of the device. This function can be removed once existing use cases
|
||||
// have been updated to use the device-to-global matrix instead or have themselves been removed
|
||||
// (e.g. Android's device-space clip regions are going away, and are not compatible with the
|
||||
// generalized device coordinate system).
|
||||
SkASSERT(this->isPixelAlignedToGlobal());
|
||||
return SkIPoint::Make(SkScalarFloorToInt(fDeviceToGlobal.getTranslateX()),
|
||||
SkScalarFloorToInt(fDeviceToGlobal.getTranslateY()));
|
||||
}
|
||||
|
||||
SkMatrix SkBaseDevice::getRelativeTransform(const SkBaseDevice& inputDevice) const {
|
||||
// To get the transform from the input's space to this space, transform from the input space to
|
||||
// the global space, and then from the global space back to this space.
|
||||
return SkMatrix::Concat(fGlobalToDevice, inputDevice.fDeviceToGlobal);
|
||||
}
|
||||
|
||||
SkPixelGeometry SkBaseDevice::CreateInfo::AdjustGeometry(TileUsage tileUsage, SkPixelGeometry geo) {
|
||||
switch (tileUsage) {
|
||||
case kPossible_TileUsage:
|
||||
|
@ -50,8 +50,9 @@ public:
|
||||
*/
|
||||
void getGlobalBounds(SkIRect* bounds) const {
|
||||
SkASSERT(bounds);
|
||||
const SkIPoint& origin = this->getOrigin();
|
||||
bounds->setXYWH(origin.x(), origin.y(), this->width(), this->height());
|
||||
SkRect localBounds = SkRect::MakeIWH(this->width(), this->height());
|
||||
fDeviceToGlobal.mapRect(&localBounds);
|
||||
*bounds = localBounds.roundOut();
|
||||
}
|
||||
|
||||
SkIRect getGlobalBounds() const {
|
||||
@ -60,6 +61,14 @@ public:
|
||||
return bounds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bounding box of the current clip, in this device's
|
||||
* coordinate space. No pixels outside of these bounds will be touched by
|
||||
* draws unless the clip is further modified (at which point this will
|
||||
* return the updated bounds).
|
||||
*/
|
||||
SkIRect devClipBounds() const { return this->onDevClipBounds(); }
|
||||
|
||||
int width() const {
|
||||
return this->imageInfo().width();
|
||||
}
|
||||
@ -92,10 +101,34 @@ public:
|
||||
bool peekPixels(SkPixmap*);
|
||||
|
||||
/**
|
||||
* Return the device's origin: its offset in device coordinates from
|
||||
* the default origin in its canvas' matrix/clip
|
||||
* Return the device's coordinate space transform: this maps from the device's coordinate space
|
||||
* into the global canvas' space (or root device space). This includes the translation
|
||||
* necessary to account for the device's origin.
|
||||
*/
|
||||
const SkIPoint& getOrigin() const { return fOrigin; }
|
||||
const SkMatrix& deviceToGlobal() const { return fDeviceToGlobal; }
|
||||
/**
|
||||
* Return the inverse of getDeviceToGlobal(), mapping from the global canvas' space (or root
|
||||
* device space) into this device's coordinate space.
|
||||
*/
|
||||
const SkMatrix& globalToDevice() const { return fGlobalToDevice; }
|
||||
/**
|
||||
* DEPRECATED: This asserts that 'getDeviceToGlobal' is a translation matrix with integer
|
||||
* components. In the future some SkDevices will have more complex device-to-global transforms,
|
||||
* so getDeviceToGlobal() or getRelativeTransform() should be used instead.
|
||||
*/
|
||||
SkIPoint getOrigin() const;
|
||||
/**
|
||||
* Returns true when this device's pixel grid is axis aligned with the global coordinate space,
|
||||
* and any relative translation between the two spaces is in integer pixel units.
|
||||
*/
|
||||
bool isPixelAlignedToGlobal() const;
|
||||
/**
|
||||
* Get the transformation from the input device's to this device's coordinate space. This
|
||||
* transform can be used to draw the input device into this device, such that once this device
|
||||
* is drawn to the root device, the net effect will have the input device's content drawn
|
||||
* transformed by the global CTM.
|
||||
*/
|
||||
SkMatrix getRelativeTransform(const SkBaseDevice&) const;
|
||||
|
||||
virtual void* getRasterHandle() const { return nullptr; }
|
||||
|
||||
@ -163,6 +196,10 @@ protected:
|
||||
};
|
||||
virtual ClipType onGetClipType() const = 0;
|
||||
|
||||
// This should strive to be as tight as possible, ideally not just mapping
|
||||
// the global clip bounds by fToGlobal^-1.
|
||||
virtual SkIRect onDevClipBounds() const = 0;
|
||||
|
||||
/** These are called inside the per-device-layer loop for each draw call.
|
||||
When these are called, we have already applied any saveLayer operations,
|
||||
and are handling any looping from the paint.
|
||||
@ -364,8 +401,21 @@ private:
|
||||
*/
|
||||
virtual GrRenderTargetContext* accessRenderTargetContext() { return nullptr; }
|
||||
|
||||
// just called by SkCanvas when built as a layer
|
||||
void setOrigin(const SkMatrix& ctm, int x, int y);
|
||||
// Configure the device's coordinate spaces, specifying both how its device image maps back to
|
||||
// the global space (via 'deviceToGlobal') and the initial CTM of the device (via
|
||||
// 'localToDevice', i.e. what geometry drawn into this device will be transformed with).
|
||||
//
|
||||
// (bufferOriginX, bufferOriginY) defines where the (0,0) pixel the device's backing buffer
|
||||
// is anchored in the device space. The final device-to-global matrix stored by the SkDevice
|
||||
// will include a pre-translation by T(deviceOriginX, deviceOriginY), and the final
|
||||
// local-to-device matrix will have a post-translation of T(-deviceOriginX, -deviceOriginY).
|
||||
void setDeviceCoordinateSystem(const SkMatrix& deviceToGlobal, const SkMatrix& localToDevice,
|
||||
int bufferOriginX, int bufferOriginY);
|
||||
// Convenience to configure the device to be axis-aligned with the root canvas, but with a
|
||||
// unique origin.
|
||||
void setOrigin(const SkMatrix& globalCTM, int x, int y) {
|
||||
this->setDeviceCoordinateSystem(SkMatrix::I(), globalCTM, x, y);
|
||||
}
|
||||
|
||||
/** Causes any deferred drawing to the device to be completed.
|
||||
*/
|
||||
@ -379,9 +429,14 @@ private:
|
||||
*const_cast<SkImageInfo*>(&fInfo) = fInfo.makeWH(w, h);
|
||||
}
|
||||
|
||||
SkIPoint fOrigin;
|
||||
const SkImageInfo fInfo;
|
||||
const SkSurfaceProps fSurfaceProps;
|
||||
// fDeviceToGlobal and fGlobalToDevice are inverses of each other; there are never that many
|
||||
// SkDevices, so pay the memory cost to avoid recalculating the inverse.
|
||||
SkMatrix fDeviceToGlobal;
|
||||
SkMatrix fGlobalToDevice;
|
||||
// This is the device CTM, not the global CTM. This transform maps from local space to the
|
||||
// device's coordinate space; fDeviceToGlobal * fLocalToDevice will match the canvas' CTM.
|
||||
SkMatrix fLocalToDevice;
|
||||
|
||||
typedef SkRefCnt INHERITED;
|
||||
@ -424,6 +479,9 @@ protected:
|
||||
ClipType onGetClipType() const override {
|
||||
return ClipType::kRect;
|
||||
}
|
||||
SkIRect onDevClipBounds() const override {
|
||||
return SkIRect::MakeWH(this->width(), this->height());
|
||||
}
|
||||
|
||||
void drawPaint(const SkPaint& paint) override {}
|
||||
void drawPoints(SkCanvas::PointMode, size_t, const SkPoint[], const SkPaint&) override {}
|
||||
|
@ -302,8 +302,10 @@ void SkPDFDevice::drawAnnotation(const SkRect& rect, const char key[], SkData* v
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
const SkMatrix& pageXform = fDocument->currentPageTransform();
|
||||
SkPoint deviceOffset = {(float)this->getOrigin().x(), (float)this->getOrigin().y()};
|
||||
// Annotations are specified in absolute coordinates, so the page xform maps from device space
|
||||
// to the global space, and applies the document transform.
|
||||
SkMatrix pageXform = this->deviceToGlobal();
|
||||
pageXform.postConcat(fDocument->currentPageTransform());
|
||||
if (rect.isEmpty()) {
|
||||
if (!strcmp(key, SkPDFGetNodeIdKey())) {
|
||||
int nodeID;
|
||||
@ -313,7 +315,7 @@ void SkPDFDevice::drawAnnotation(const SkRect& rect, const char key[], SkData* v
|
||||
return;
|
||||
}
|
||||
if (!strcmp(SkAnnotationKeys::Define_Named_Dest_Key(), key)) {
|
||||
SkPoint p = deviceOffset + this->localToDevice().mapXY(rect.x(), rect.y());
|
||||
SkPoint p = this->localToDevice().mapXY(rect.x(), rect.y());
|
||||
pageXform.mapPoints(&p, 1);
|
||||
auto pg = fDocument->currentPage();
|
||||
fDocument->fNamedDestinations.push_back(SkPDFNamedDestination{sk_ref_sp(value), p, pg});
|
||||
@ -327,8 +329,7 @@ void SkPDFDevice::drawAnnotation(const SkRect& rect, const char key[], SkData* v
|
||||
SkClipStack_AsPath(this->cs(), &clip);
|
||||
Op(clip, path, kIntersect_SkPathOp, &path);
|
||||
// PDF wants a rectangle only.
|
||||
SkRect transformedRect =
|
||||
pageXform.mapRect(path.getBounds().makeOffset(deviceOffset.x(), deviceOffset.y()));
|
||||
SkRect transformedRect = pageXform.mapRect(path.getBounds());
|
||||
if (transformedRect.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user