aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Mike Reed <reed@google.com>2017-02-14 14:25:14 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-02-14 20:07:08 +0000
commitc42a1cdd1de7a3cf57a9a5fd7363f5fb660e97d0 (patch)
tree9a314b3cb18f42c0c71eba11c7b12d393a1ea2d4
parentdf85c38163245c7fc3c23cad3a4ad104949f3a62 (diff)
work on raster device clipping
With the flag (SkDevice.h) enabled, I get correct drawing w/ the rasterbackend. After this lands, hopefully we can work in parallel on gpu/pdf/svg/xps/etc. BUG=skia:6214 Change-Id: Ie35fee818470aab57aebacca8a2a5b812a552ee2 Reviewed-on: https://skia-review.googlesource.com/8192 Commit-Queue: Mike Reed <reed@google.com> Reviewed-by: Florin Malita <fmalita@chromium.org> Reviewed-by: Robert Phillips <robertphillips@google.com>
-rw-r--r--include/core/SkCanvas.h4
-rw-r--r--src/core/SkBitmapDevice.cpp84
-rw-r--r--src/core/SkBitmapDevice.h5
-rw-r--r--src/core/SkCanvas.cpp75
-rw-r--r--src/core/SkDevice.cpp18
-rw-r--r--src/core/SkDevice.h33
-rw-r--r--src/core/SkRasterClipStack.h170
7 files changed, 337 insertions, 52 deletions
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index 193d1afd69..9d6614fffa 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -1537,8 +1537,8 @@ private:
static SaveLayerFlags LegacySaveFlagsToSaveLayerFlags(uint32_t legacySaveFlags);
static void DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
- SkBaseDevice* dst, const SkMatrix& ctm,
- const SkClipStack* clipStack);
+ SkBaseDevice* dst, const SkIPoint& dstOrigin,
+ const SkMatrix& ctm, const SkClipStack* clipStack);
enum ShaderOverrideOpacity {
kNone_ShaderOverrideOpacity, //!< there is no overriding shader (bitmap or image)
diff --git a/src/core/SkBitmapDevice.cpp b/src/core/SkBitmapDevice.cpp
index 45ec2b70ae..5742e1d0a3 100644
--- a/src/core/SkBitmapDevice.cpp
+++ b/src/core/SkBitmapDevice.cpp
@@ -71,11 +71,10 @@ static bool valid_for_bitmap_device(const SkImageInfo& info,
SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap)
: INHERITED(bitmap.info(), SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType))
, fBitmap(bitmap)
+ , fRCStack(bitmap.width(), bitmap.height())
{
SkASSERT(valid_for_bitmap_device(bitmap.info(), nullptr));
fBitmap.lockPixels();
-
- fRCStack.push_back().setRect(SkIRect::MakeWH(bitmap.width(), bitmap.height()));
}
SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& info) {
@@ -87,11 +86,10 @@ SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkSurfaceProps& sur
: INHERITED(bitmap.info(), surfaceProps)
, fBitmap(bitmap)
, fRasterHandle(hndl)
+ , fRCStack(bitmap.width(), bitmap.height())
{
SkASSERT(valid_for_bitmap_device(bitmap.info(), nullptr));
fBitmap.lockPixels();
-
- fRCStack.push_back().setRect(SkIRect::MakeWH(bitmap.width(), bitmap.height()));
}
SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo,
@@ -137,6 +135,8 @@ void SkBitmapDevice::setNewSize(const SkISize& size) {
SkASSERT(!fBitmap.pixelRef());
fBitmap.setInfo(fBitmap.info().makeWH(size.fWidth, size.fHeight));
this->privateResize(fBitmap.info().width(), fBitmap.info().height());
+
+ fRCStack.setNewSize(size.fWidth, size.fHeight);
}
void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) {
@@ -191,17 +191,35 @@ bool SkBitmapDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, s
///////////////////////////////////////////////////////////////////////////////
+#ifdef SK_USE_DEVICE_CLIPPING
+class ModifiedDraw : public SkDraw {
+public:
+ ModifiedDraw(const SkMatrix& devCTM, const SkRasterClip& rc, SkISize rcs,
+ const SkDraw& draw) : SkDraw(draw) {
+#ifdef SK_DEBUG
+ SkISize dvs = { draw.fDevice->width(), draw.fDevice->height() };
+ SkASSERT(dvs == rcs);
+ SkASSERT(devCTM == *draw.fMatrix);
+#endif
+ fRC = &rc;
+ }
+};
+#define PREPARE_DRAW(draw) ModifiedDraw(this->ctm(), fRCStack.rc(), fRCStack.getRootSize(), draw)
+#else
+#define PREPARE_DRAW(draw) draw
+#endif
+
void SkBitmapDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
- draw.drawPaint(paint);
+ PREPARE_DRAW(draw).drawPaint(paint);
}
void SkBitmapDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
const SkPoint pts[], const SkPaint& paint) {
- draw.drawPoints(mode, count, pts, paint);
+ PREPARE_DRAW(draw).drawPoints(mode, count, pts, paint);
}
void SkBitmapDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) {
- draw.drawRect(r, paint);
+ PREPARE_DRAW(draw).drawRect(r, paint);
}
void SkBitmapDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) {
@@ -221,20 +239,20 @@ void SkBitmapDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const S
// required to override drawRRect.
this->drawPath(draw, path, paint, nullptr, true);
#else
- draw.drawRRect(rrect, paint);
+ PREPARE_DRAW(draw).drawRRect(rrect, paint);
#endif
}
void SkBitmapDevice::drawPath(const SkDraw& draw, const SkPath& path,
const SkPaint& paint, const SkMatrix* prePathMatrix,
bool pathIsMutable) {
- draw.drawPath(path, paint, prePathMatrix, pathIsMutable);
+ PREPARE_DRAW(draw).drawPath(path, paint, prePathMatrix, pathIsMutable);
}
void SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
const SkMatrix& matrix, const SkPaint& paint) {
LogDrawScaleFactor(SkMatrix::Concat(*draw.fMatrix, matrix), paint.getFilterQuality());
- draw.drawBitmap(bitmap, matrix, nullptr, paint);
+ PREPARE_DRAW(draw).drawBitmap(bitmap, matrix, nullptr, paint);
}
static inline bool CanApplyDstMatrixAsCTM(const SkMatrix& m, const SkPaint& paint) {
@@ -323,7 +341,7 @@ void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
// matrix with the CTM, and try to call drawSprite if it can. If not,
// it will make a shader and call drawRect, as we do below.
if (CanApplyDstMatrixAsCTM(matrix, paint)) {
- draw.drawBitmap(*bitmapPtr, matrix, dstPtr, paint);
+ PREPARE_DRAW(draw).drawBitmap(*bitmapPtr, matrix, dstPtr, paint);
return;
}
}
@@ -353,18 +371,18 @@ void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
void SkBitmapDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
int x, int y, const SkPaint& paint) {
- draw.drawSprite(bitmap, x, y, paint);
+ PREPARE_DRAW(draw).drawSprite(bitmap, x, y, paint);
}
void SkBitmapDevice::drawText(const SkDraw& draw, const void* text, size_t len,
SkScalar x, SkScalar y, const SkPaint& paint) {
- draw.drawText((const char*)text, len, x, y, paint);
+ PREPARE_DRAW(draw).drawText((const char*)text, len, x, y, paint);
}
void SkBitmapDevice::drawPosText(const SkDraw& draw, const void* text, size_t len,
const SkScalar xpos[], int scalarsPerPos,
const SkPoint& offset, const SkPaint& paint) {
- draw.drawPosText((const char*)text, len, xpos, scalarsPerPos, offset, paint);
+ PREPARE_DRAW(draw).drawPosText((const char*)text, len, xpos, scalarsPerPos, offset, paint);
}
void SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
@@ -373,14 +391,14 @@ void SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode
const SkColor colors[], SkBlendMode bmode,
const uint16_t indices[], int indexCount,
const SkPaint& paint) {
- draw.drawVertices(vmode, vertexCount, verts, textures, colors, bmode,
+ PREPARE_DRAW(draw).drawVertices(vmode, vertexCount, verts, textures, colors, bmode,
indices, indexCount, paint);
}
void SkBitmapDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device,
int x, int y, const SkPaint& paint) {
SkASSERT(!paint.getImageFilter());
- draw.drawSprite(static_cast<SkBitmapDevice*>(device)->fBitmap, x, y, paint);
+ PREPARE_DRAW(draw).drawSprite(static_cast<SkBitmapDevice*>(device)->fBitmap, x, y, paint);
}
///////////////////////////////////////////////////////////////////////////////
@@ -459,28 +477,44 @@ bool SkBitmapDevice::onShouldDisableLCD(const SkPaint& paint) const {
///////////////////////////////////////////////////////////////////////////////////////////////////
void SkBitmapDevice::onSave() {
- fRCStack.push_back(fRCStack.back());
+ fRCStack.save();
}
void SkBitmapDevice::onRestore() {
- fRCStack.pop_back();
+ fRCStack.restore();
}
void SkBitmapDevice::onClipRect(const SkRect& rect, SkClipOp op, bool aa) {
- fRCStack.back().op(rect, this->ctm(), SkIRect::MakeWH(this->width(), this->height()),
- (SkRegion::Op)op, aa);
+ fRCStack.clipRect(this->ctm(), rect, op, aa);
}
void SkBitmapDevice::onClipRRect(const SkRRect& rrect, SkClipOp op, bool aa) {
- fRCStack.back().op(rrect, this->ctm(), SkIRect::MakeWH(this->width(), this->height()),
- (SkRegion::Op)op, aa);
+ fRCStack.clipRRect(this->ctm(), rrect, op, aa);
}
void SkBitmapDevice::onClipPath(const SkPath& path, SkClipOp op, bool aa) {
- fRCStack.back().op(path, this->ctm(), SkIRect::MakeWH(this->width(), this->height()),
- (SkRegion::Op)op, aa);
+ fRCStack.clipPath(this->ctm(), path, op, aa);
}
void SkBitmapDevice::onClipRegion(const SkRegion& rgn, SkClipOp op) {
- fRCStack.back().op(rgn, (SkRegion::Op)op);
+ SkIPoint origin = this->getOrigin();
+ SkRegion tmp;
+ const SkRegion* ptr = &rgn;
+ if (origin.fX | origin.fY) {
+ // translate from "global/canvas" coordinates to relative to this device
+ rgn.translate(-origin.fX, -origin.fY, &tmp);
+ ptr = &tmp;
+ }
+ fRCStack.clipRegion(*ptr, op);
+}
+
+void SkBitmapDevice::onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) {
+ fRCStack.setDeviceClipRestriction(mutableClipRestriction);
+}
+
+void SkBitmapDevice::validateDevBounds(const SkIRect& drawClipBounds) {
+#ifdef SK_DEBUG
+ const SkIRect& stackBounds = fRCStack.rc().getBounds();
+ SkASSERT(drawClipBounds == stackBounds);
+#endif
}
diff --git a/src/core/SkBitmapDevice.h b/src/core/SkBitmapDevice.h
index 0a6471080b..266b2d9513 100644
--- a/src/core/SkBitmapDevice.h
+++ b/src/core/SkBitmapDevice.h
@@ -15,6 +15,7 @@
#include "SkImageInfo.h"
#include "SkPixelRef.h"
#include "SkRasterClip.h"
+#include "SkRasterClipStack.h"
#include "SkRect.h"
#include "SkScalar.h"
#include "SkSize.h"
@@ -132,6 +133,8 @@ protected:
void onClipRRect(const SkRRect& rrect, SkClipOp, bool aa) override;
void onClipPath(const SkPath& path, SkClipOp, bool aa) override;
void onClipRegion(const SkRegion& deviceRgn, SkClipOp) override;
+ void onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) override;
+ void validateDevBounds(const SkIRect& r) override;
private:
friend class SkCanvas;
@@ -155,7 +158,7 @@ private:
SkBitmap fBitmap;
void* fRasterHandle = nullptr;
- SkTArray<SkRasterClip> fRCStack;
+ SkRasterClipStack fRCStack;
void setNewSize(const SkISize&); // Used by SkCanvas for resetForNextPicture().
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 562e0ae606..0c6f241e97 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -230,12 +230,17 @@ struct DeviceCM {
fMatrixStorage.postTranslate(SkIntToScalar(-x),
SkIntToScalar(-y));
fMatrix = &fMatrixStorage;
-
totalClip.translate(-x, -y, &fClip);
}
fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
+#ifdef SK_USE_DEVICE_CLIPPING
+ SkASSERT(*fMatrix == fDevice->ctm());
+ // TODO: debug tiles-rt-8888 so we can enable this all the time
+// fDevice->validateDevBounds(fClip.getBounds());
+#endif
+
// intersect clip, but don't translate it (yet)
if (updateClip) {
@@ -392,7 +397,9 @@ private:
DeviceCM* layer = fMCRec->fTopLayer; \
while (layer) { \
SkBaseDevice* device = layer->fDevice; \
- code; \
+ if (device) { \
+ code; \
+ } \
layer = layer->fNext; \
} \
} while (0)
@@ -694,6 +701,10 @@ SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
fMCRec->fLayer->fDevice = SkRef(device);
fMCRec->fRasterClip.setRect(device->getGlobalBounds());
fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
+
+#ifdef SK_USE_DEVICE_CLIPPING
+ device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
+#endif
}
return device;
@@ -720,7 +731,7 @@ public:
SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
: INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
{
- this->setOrigin(bounds.x(), bounds.y());
+ this->setOrigin(SkMatrix::I(), bounds.x(), bounds.y());
}
private:
@@ -1006,9 +1017,6 @@ void SkCanvas::doSave() {
SkASSERT(fMCRec->fDeferredSaveCount > 0);
fMCRec->fDeferredSaveCount -= 1;
this->internalSave();
-#ifdef SK_USE_DEVICE_CLIPPING
- FOR_EACH_TOP_DEVICE(device->save());
-#endif
}
void SkCanvas::restore() {
@@ -1024,9 +1032,6 @@ void SkCanvas::restore() {
fSaveCount -= 1;
this->internalRestore();
this->didRestore();
-#ifdef SK_USE_DEVICE_CLIPPING
- FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
-#endif
}
}
}
@@ -1049,6 +1054,9 @@ void SkCanvas::internalSave() {
fMCRec = newTop;
fClipStack->save();
+#ifdef SK_USE_DEVICE_CLIPPING
+ FOR_EACH_TOP_DEVICE(device->save());
+#endif
}
bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
@@ -1123,8 +1131,8 @@ int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
}
void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
- SkBaseDevice* dst, const SkMatrix& ctm,
- const SkClipStack* clipStack) {
+ SkBaseDevice* dst, const SkIPoint& dstOrigin,
+ const SkMatrix& ctm, const SkClipStack* clipStack) {
SkDraw draw;
SkRasterClip rc;
rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
@@ -1139,8 +1147,8 @@ void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filt
SkPaint p;
p.setImageFilter(filter->makeWithLocalMatrix(ctm));
- int x = src->getOrigin().x() - dst->getOrigin().x();
- int y = src->getOrigin().y() - dst->getOrigin().y();
+ int x = src->getOrigin().x() - dstOrigin.x();
+ int y = src->getOrigin().y() - dstOrigin.y();
auto special = src->snapSpecial();
if (special) {
dst->drawSpecial(draw, special.get(), x, y, p);
@@ -1231,7 +1239,7 @@ void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy stra
}
SkBaseDevice* priorDevice = this->getTopDevice();
- if (nullptr == priorDevice) {
+ if (nullptr == priorDevice) { // Do we still need this check???
SkDebugf("Unable to find device for layer.");
return;
}
@@ -1252,7 +1260,9 @@ void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy stra
return;
}
}
- newDevice->setOrigin(ir.fLeft, ir.fTop);
+#ifndef SK_USE_DEVICE_CLIPPING
+ newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
+#endif
DeviceCM* layer =
new DeviceCM(newDevice.get(), paint, this, fConservativeRasterClip, stashedMatrix);
@@ -1263,9 +1273,24 @@ void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy stra
fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
if (rec.fBackdrop) {
- DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(),
+ DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
fMCRec->fMatrix, this->getClipStack());
}
+
+#ifdef SK_USE_DEVICE_CLIPPING
+ newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
+
+ newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
+ if (layer->fNext) {
+ // need to punch a hole in the previous device, so we don't draw there, given that
+ // the new top-layer will allow drawing to happen "below" it.
+ SkRegion hole(ir);
+ do {
+ layer = layer->fNext;
+ layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
+ } while (layer->fNext);
+ }
+#endif
}
int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
@@ -1295,6 +1320,12 @@ void SkCanvas::internalRestore() {
fMCStack.pop_back();
fMCRec = (MCRec*)fMCStack.back();
+#ifdef SK_USE_DEVICE_CLIPPING
+ if (fMCRec) {
+ FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
+ }
+#endif
+
/* Time to draw the layer's offscreen. We can't call the public drawSprite,
since if we're being recorded, we don't want to record this (the
recorder will have already recorded the restore).
@@ -1433,6 +1464,10 @@ void SkCanvas::translate(SkScalar dx, SkScalar dy) {
// Translate shouldn't affect the is-scale-translateness of the matrix.
SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
+#ifdef SK_USE_DEVICE_CLIPPING
+ FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
+#endif
+
this->didTranslate(dx,dy);
}
}
@@ -1482,6 +1517,10 @@ void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
fDeviceCMDirty = true;
fMCRec->fMatrix = matrix;
fIsScaleTranslate = matrix.isScaleTranslate();
+
+#ifdef SK_USE_DEVICE_CLIPPING
+ FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
+#endif
}
void SkCanvas::setMatrix(const SkMatrix& matrix) {
@@ -1542,6 +1581,10 @@ void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
fClipStack->setDeviceClipRestriction(fClipRestrictionRect);
if (!fClipRestrictionRect.isEmpty()) {
this->checkForDeferredSave();
+#ifdef SK_USE_DEVICE_CLIPPING
+ SkRegion restrictRgn(fClipRestrictionRect);
+ FOR_EACH_TOP_DEVICE(device->clipRegion(restrictRgn, SkClipOp::kIntersect));
+#endif
AutoValidateClip avc(this);
fClipStack->clipDevRect(fClipRestrictionRect, kIntersect_SkClipOp);
fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op);
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index 07b9c23373..803cddd543 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -32,10 +32,24 @@ SkBaseDevice::SkBaseDevice(const SkImageInfo& info, const SkSurfaceProps& surfac
, fSurfaceProps(surfaceProps)
{
fOrigin.setZero();
+ fCTM.reset();
}
SkBaseDevice::~SkBaseDevice() {}
+void SkBaseDevice::setOrigin(const SkMatrix& globalCTM, int x, int y) {
+ fOrigin.set(x, y);
+ fCTM = globalCTM;
+ fCTM.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
+}
+
+void SkBaseDevice::setGlobalCTM(const SkMatrix& ctm) {
+ fCTM = ctm;
+ if (fOrigin.fX | fOrigin.fY) {
+ fCTM.postTranslate(-SkIntToScalar(fOrigin.fX), -SkIntToScalar(fOrigin.fY));
+ }
+}
+
SkPixelGeometry SkBaseDevice::CreateInfo::AdjustGeometry(const SkImageInfo& info,
TileUsage tileUsage,
SkPixelGeometry geo,
@@ -519,6 +533,10 @@ void SkBaseDevice::drawTextRSXform(const SkDraw& draw, const void* text, size_t
localM.setRSXform(*xform++);
currM.setConcat(*draw.fMatrix, localM);
localD.fMatrix = &currM;
+#ifdef SK_USE_DEVICE_CLIPPING
+ SkAutoDeviceCTMRestore adc(this, currM);
+#endif
+
int subLen = proc((const char*)text);
this->drawText(localD, text, subLen, 0, 0, paint);
text = (const char*)text + subLen;
diff --git a/src/core/SkDevice.h b/src/core/SkDevice.h
index 3c0b7785d3..3d1b558eab 100644
--- a/src/core/SkDevice.h
+++ b/src/core/SkDevice.h
@@ -121,18 +121,17 @@ public:
void clipRegion(const SkRegion& region, SkClipOp op) {
this->onClipRegion(region, op);
}
+ void androidFramework_setDeviceClipRestriction(SkIRect* mutableClipRestriction) {
+ this->onSetDeviceClipRestriction(mutableClipRestriction);
+ }
const SkMatrix& ctm() const { return fCTM; }
void setCTM(const SkMatrix& ctm) {
fCTM = ctm;
}
- void setGlobalCTM(const SkMatrix& ctm) {
- fCTM = ctm;
- if (fOrigin.fX | fOrigin.fY) {
- fCTM.postTranslate(-SkIntToScalar(fOrigin.fX), -SkIntToScalar(fOrigin.fY));
- }
- }
-
+ void setGlobalCTM(const SkMatrix& ctm);
+ virtual void validateDevBounds(const SkIRect&) {}
+
protected:
enum TileUsage {
kPossible_TileUsage, //!< the created device may be drawn tiled
@@ -157,6 +156,7 @@ protected:
virtual void onClipRRect(const SkRRect& rrect, SkClipOp, bool aa) {}
virtual void onClipPath(const SkPath& path, SkClipOp, bool aa) {}
virtual void onClipRegion(const SkRegion& deviceRgn, SkClipOp) {}
+ virtual void onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) {}
/** These are called inside the per-device-layer loop for each draw call.
When these are called, we have already applied any saveLayer operations,
@@ -367,7 +367,7 @@ private:
virtual GrRenderTargetContext* accessRenderTargetContext() { return nullptr; }
// just called by SkCanvas when built as a layer
- void setOrigin(int x, int y) { fOrigin.set(x, y); }
+ void setOrigin(const SkMatrix& ctm, int x, int y);
/** Causes any deferred drawing to the device to be completed.
*/
@@ -392,4 +392,21 @@ private:
typedef SkRefCnt INHERITED;
};
+class SkAutoDeviceCTMRestore : SkNoncopyable {
+public:
+ SkAutoDeviceCTMRestore(SkBaseDevice* device, const SkMatrix& ctm)
+ : fDevice(device)
+ , fPrevCTM(device->ctm())
+ {
+ fDevice->setCTM(ctm);
+ }
+ ~SkAutoDeviceCTMRestore() {
+ fDevice->setCTM(fPrevCTM);
+ }
+
+private:
+ SkBaseDevice* fDevice;
+ const SkMatrix fPrevCTM;
+};
+
#endif
diff --git a/src/core/SkRasterClipStack.h b/src/core/SkRasterClipStack.h
new file mode 100644
index 0000000000..f606259a31
--- /dev/null
+++ b/src/core/SkRasterClipStack.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkRasterClipStack_DEFINED
+#define SkRasterClipStack_DEFINED
+
+#include "SkDeque.h"
+#include "SkRasterClip.h"
+
+template <typename T> class SkTStack {
+public:
+ SkTStack(void* storage, size_t size) : fDeque(sizeof(T), storage, size), fTop(nullptr) {}
+ ~SkTStack() {
+ while (!fDeque.empty()) {
+ ((T*)fDeque.back())->~T();
+ fDeque.pop_back();
+ }
+ }
+
+ bool empty() const { return fDeque.empty(); }
+
+ int count() const { return fDeque.count(); }
+
+ const T& top() const {
+ SkASSERT(fTop);
+ return *fTop;
+ }
+
+ T& top() {
+ SkASSERT(fTop);
+ return *fTop;
+ }
+
+ T* push_raw() { return (T*)fDeque.push_back(); }
+ T& push() {
+ fTop = this->push_raw();
+ new (fTop) T();
+ return *fTop;
+ }
+ T& push(const T& src) {
+ fTop = this->push_raw();
+ new (fTop) T(src);
+ return *fTop;
+ }
+
+ void pop() {
+ fTop->~T();
+ fDeque.pop_back();
+ fTop = fDeque.empty() ? nullptr : (T*)fDeque.back();
+ }
+
+private:
+ SkDeque fDeque;
+ T* fTop;
+};
+
+class SkRasterClipStack : SkNoncopyable {
+ int fCounter = 0;
+public:
+ SkRasterClipStack(int width, int height)
+ : fStack(fStorage, sizeof(fStorage))
+ , fRootBounds(SkIRect::MakeWH(width, height))
+ {
+ Rec& rec = fStack.push();
+ rec.fRC.setRect(fRootBounds);
+ rec.fDeferredCount = 0;
+ SkASSERT(fStack.count() == 1);
+ }
+
+ void setNewSize(int w, int h) {
+ SkASSERT(fStack.count() == 1);
+ fRootBounds.setXYWH(0, 0, w, h);
+ }
+
+ SkISize getRootSize() const { return fRootBounds.size(); }
+
+ const SkRasterClip& rc() const { return fStack.top().fRC; }
+
+ void save() {
+ fCounter += 1;
+ SkASSERT(fStack.top().fDeferredCount >= 0);
+ fStack.top().fDeferredCount += 1;
+ }
+
+ void restore() {
+ fCounter -= 1; SkASSERT(fCounter >= 0);
+ if (--fStack.top().fDeferredCount < 0) {
+ SkASSERT(fStack.top().fDeferredCount == -1);
+ SkASSERT(fStack.count() > 1);
+ fStack.pop();
+ }
+ }
+
+ void clipRect(const SkMatrix& ctm, const SkRect& rect, SkClipOp op, bool aa) {
+ this->writable_rc().op(rect, ctm, fRootBounds, (SkRegion::Op)op, aa);
+ this->trimIfExpanding(op);
+ this->validate();
+ }
+
+ void clipRRect(const SkMatrix& ctm, const SkRRect& rrect, SkClipOp op, bool aa) {
+ this->writable_rc().op(rrect, ctm, fRootBounds, (SkRegion::Op)op, aa);
+ this->trimIfExpanding(op);
+ this->validate();
+ }
+
+ void clipPath(const SkMatrix& ctm, const SkPath& path, SkClipOp op, bool aa) {
+ this->writable_rc().op(path, ctm, fRootBounds, (SkRegion::Op)op, aa);
+ this->trimIfExpanding(op);
+ this->validate();
+ }
+
+ void clipRegion(const SkRegion& rgn, SkClipOp op) {
+ this->writable_rc().op(rgn, (SkRegion::Op)op);
+ this->trimIfExpanding(op);
+ this->validate();
+ }
+
+ void setDeviceClipRestriction(SkIRect* mutableClipRestriction) {
+ this->writable_rc().setDeviceClipRestriction(mutableClipRestriction);
+ }
+
+ void validate() const {
+#ifdef SK_DEBUG
+ const SkRasterClip& clip = this->rc();
+ if (fRootBounds.isEmpty()) {
+ SkASSERT(clip.isEmpty());
+ } else if (!clip.isEmpty()) {
+ SkASSERT(fRootBounds.contains(clip.getBounds()));
+ }
+#endif
+ }
+
+private:
+ struct Rec {
+ SkRasterClip fRC;
+ int fDeferredCount; // 0 for a "normal" entry
+ };
+
+ enum {
+ ELEM_COUNT = 16,
+ PTR_COUNT = ELEM_COUNT * sizeof(Rec) / sizeof(void*)
+ };
+ void* fStorage[PTR_COUNT];
+ SkTStack<Rec> fStack;
+ SkIRect fRootBounds;
+
+ SkRasterClip& writable_rc() {
+ SkASSERT(fStack.top().fDeferredCount >= 0);
+ if (fStack.top().fDeferredCount > 0) {
+ fStack.top().fDeferredCount -= 1;
+ fStack.push(fStack.top());
+ fStack.top().fDeferredCount = 0;
+ }
+ return fStack.top().fRC;
+ }
+
+ void trimIfExpanding(SkClipOp op) {
+ if ((int)op > (int)SkClipOp::kIntersect) {
+ Rec& rec = fStack.top();
+ SkASSERT(rec.fDeferredCount == 0);
+ rec.fRC.op(fRootBounds, SkRegion::kIntersect_Op);
+ }
+ }
+};
+
+#endif