diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h index 26458696bc..337ce72767 100644 --- a/include/core/SkCanvas.h +++ b/include/core/SkCanvas.h @@ -444,6 +444,13 @@ public: */ void resetMatrix(); + /** Set the current draw depth of the canvas. + @param z The SkScalar depth; it's tracked in the save/restore stack. + Negative into screen, positive out of screen. + Defaults to 0. + */ + void translateZ(SkScalar z); + /** * Modify the current clip with the specified rectangle. * @param rect The rect to combine with the current clip @@ -1253,6 +1260,10 @@ public: void temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds); protected: + /** Returns the current (cumulative) draw depth of the canvas. + */ + SkScalar getZ() const; + /** After calling saveLayer(), there can be any number of devices that make up the top-most drawing area. LayerIter can be used to iterate through those devices. Note that the iterator is only valid until the next API @@ -1318,6 +1329,7 @@ protected: virtual void didRestore() {} virtual void didConcat(const SkMatrix&) {} virtual void didSetMatrix(const SkMatrix&) {} + virtual void didTranslateZ(SkScalar) {} virtual void onDrawAnnotation(const SkRect&, const char key[], SkData* value); virtual void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&); diff --git a/include/private/SkRecords.h b/include/private/SkRecords.h index 9ec2d2116c..35adca20e7 100644 --- a/include/private/SkRecords.h +++ b/include/private/SkRecords.h @@ -47,6 +47,7 @@ namespace SkRecords { M(Save) \ M(SaveLayer) \ M(SetMatrix) \ + M(TranslateZ) \ M(Concat) \ M(ClipPath) \ M(ClipRRect) \ @@ -218,6 +219,8 @@ RECORD(SetMatrix, 0, RECORD(Concat, 0, TypedMatrix matrix); +RECORD(TranslateZ, 0, SkScalar z); + struct RegionOpAndAA { RegionOpAndAA() {} RegionOpAndAA(SkRegion::Op op, bool aa) : op(op), aa(aa) {} diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index 0ce97fff20..20e745758e 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -294,17 +294,22 @@ public: SkMatrix fMatrix; int fDeferredSaveCount; + // This is the current cumulative depth (aggregate of all done translateZ calls) + SkScalar fCurDrawDepth; + MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) { fFilter = nullptr; fLayer = nullptr; fTopLayer = nullptr; fMatrix.reset(); fDeferredSaveCount = 0; + fCurDrawDepth = 0; // don't bother initializing fNext inc_rec(); } - MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) { + MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix), + fCurDrawDepth(prev.fCurDrawDepth) { fFilter = SkSafeRef(prev.fFilter); fLayer = nullptr; fTopLayer = prev.fTopLayer; @@ -1533,6 +1538,16 @@ void SkCanvas::resetMatrix() { this->setMatrix(SkMatrix::I()); } +void SkCanvas::translateZ(SkScalar z) { + this->checkForDeferredSave(); + this->fMCRec->fCurDrawDepth += z; + this->didTranslateZ(z); +} + +SkScalar SkCanvas::getZ() const { + return this->fMCRec->fCurDrawDepth; +} + ////////////////////////////////////////////////////////////////////////////// void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { diff --git a/src/core/SkPictureFlat.h b/src/core/SkPictureFlat.h index 3546fb2e0a..d8145110b8 100644 --- a/src/core/SkPictureFlat.h +++ b/src/core/SkPictureFlat.h @@ -52,6 +52,7 @@ enum DrawType { SAVE_LAYER_SAVEFLAGS_DEPRECATED, SCALE, SET_MATRIX, + TRANSLATE_Z, SKEW, TRANSLATE, NOOP, diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp index 17ed1aa20b..3b70b56774 100644 --- a/src/core/SkPictureRecord.cpp +++ b/src/core/SkPictureRecord.cpp @@ -218,6 +218,15 @@ void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) { this->INHERITED::didSetMatrix(matrix); } +void SkPictureRecord::didTranslateZ(SkScalar z) { + this->validate(fWriter.bytesWritten(), 0); + // set Z + size_t size = sizeof(SkScalar); + size_t initialOffset = this->addDraw(TRANSLATE_Z, &size); + + this->validate(initialOffset, size); +} + static bool regionOpExpands(SkRegion::Op op) { switch (op) { case SkRegion::kUnion_Op: diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h index bdb6609bd9..276dd3e29b 100644 --- a/src/core/SkPictureRecord.h +++ b/src/core/SkPictureRecord.h @@ -159,6 +159,8 @@ protected: void didConcat(const SkMatrix&) override; void didSetMatrix(const SkMatrix&) override; + void didTranslateZ(SkScalar) override; + void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override; void onDrawText(const void* text, size_t, SkScalar x, SkScalar y, const SkPaint&) override; diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp index ec9aee9562..03f8d53d5e 100644 --- a/src/core/SkRecordDraw.cpp +++ b/src/core/SkRecordDraw.cpp @@ -87,6 +87,8 @@ DRAW(ClipRRect, clipRRect(r.rrect, r.opAA.op, r.opAA.aa)); DRAW(ClipRect, clipRect(r.rect, r.opAA.op, r.opAA.aa)); DRAW(ClipRegion, clipRegion(r.region, r.op)); +DRAW(TranslateZ, SkCanvas::translateZ(r.z)); + DRAW(DrawBitmap, drawBitmap(r.bitmap.shallowCopy(), r.left, r.top, r.paint)); DRAW(DrawBitmapNine, drawBitmapNine(r.bitmap.shallowCopy(), r.center, r.dst, r.paint)); DRAW(DrawBitmapRect, @@ -288,6 +290,8 @@ private: void trackBounds(const ClipPath&) { this->pushControl(); } void trackBounds(const ClipRegion&) { this->pushControl(); } + void trackBounds(const TranslateZ&) { this->pushControl(); } + // For all other ops, we can calculate and store the bounds directly now. template void trackBounds(const T& op) { fBounds[fCurrentOp] = this->bounds(op); diff --git a/src/core/SkRecorder.cpp b/src/core/SkRecorder.cpp index 19cb663eaf..c7869bb6a4 100644 --- a/src/core/SkRecorder.cpp +++ b/src/core/SkRecorder.cpp @@ -369,6 +369,10 @@ void SkRecorder::didSetMatrix(const SkMatrix& matrix) { APPEND(SetMatrix, matrix); } +void SkRecorder::didTranslateZ(SkScalar z) { + APPEND(TranslateZ, z); +} + void SkRecorder::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { INHERITED(onClipRect, rect, op, edgeStyle); SkRecords::RegionOpAndAA opAA(op, kSoft_ClipEdgeStyle == edgeStyle); diff --git a/src/core/SkRecorder.h b/src/core/SkRecorder.h index 3cf0be97c3..66a006712e 100644 --- a/src/core/SkRecorder.h +++ b/src/core/SkRecorder.h @@ -60,6 +60,7 @@ public: void didConcat(const SkMatrix&) override; void didSetMatrix(const SkMatrix&) override; + void didTranslateZ(SkScalar) override; void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override; void onDrawDrawable(SkDrawable*, const SkMatrix*) override; diff --git a/tests/CanvasTest.cpp b/tests/CanvasTest.cpp index 82e065f5ac..0886b53652 100644 --- a/tests/CanvasTest.cpp +++ b/tests/CanvasTest.cpp @@ -779,6 +779,27 @@ DEF_TEST(Canvas_ClipEmptyPath, reporter) { canvas.restore(); } +class SkTestCanvas : public SkCanvas { +public: + void testUpdateDepth(skiatest::Reporter* reporter) { + // set some depths (with picture enabled), then check them as they get set + + REPORTER_ASSERT(reporter, this->getZ() == 0); + this->translateZ(-10); + REPORTER_ASSERT(reporter, this->getZ() == -10); + + this->save(); + this->translateZ(20); + REPORTER_ASSERT(reporter, this->getZ() == 10); + + this->restore(); + REPORTER_ASSERT(reporter, this->getZ() == -10); + + this->translateZ(13.14f); + REPORTER_ASSERT(reporter, SkScalarNearlyEqual(this->getZ(),3.14f)); + } +}; + namespace { class MockFilterCanvas : public SkPaintFilterCanvas { @@ -812,6 +833,11 @@ DEF_TEST(PaintFilterCanvas_ConsistentState, reporter) { REPORTER_ASSERT(reporter, canvas.getTotalMatrix() == filterCanvas.getTotalMatrix()); REPORTER_ASSERT(reporter, canvas.getClipBounds(&clip1) == filterCanvas.getClipBounds(&clip2)); REPORTER_ASSERT(reporter, clip1 == clip2); + + SkTestCanvas* tCanvas; + + tCanvas = (SkTestCanvas*) new SkCanvas(100,100); + tCanvas->testUpdateDepth(reporter); } /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/tools/debugger/SkDebugCanvas.cpp b/tools/debugger/SkDebugCanvas.cpp index b80eeea0b1..ae934a16e7 100644 --- a/tools/debugger/SkDebugCanvas.cpp +++ b/tools/debugger/SkDebugCanvas.cpp @@ -690,6 +690,11 @@ void SkDebugCanvas::didSetMatrix(const SkMatrix& matrix) { this->INHERITED::didSetMatrix(matrix); } +void SkDebugCanvas::didTranslateZ(SkScalar z) { + this->addDrawCommand(new SkTranslateZCommand(z)); + this->INHERITED::didTranslateZ(z); +} + void SkDebugCanvas::toggleCommand(int index, bool toggle) { SkASSERT(index < fCommandVector.count()); fCommandVector[index]->setVisible(toggle); diff --git a/tools/debugger/SkDebugCanvas.h b/tools/debugger/SkDebugCanvas.h index e8d9113438..4264f55200 100644 --- a/tools/debugger/SkDebugCanvas.h +++ b/tools/debugger/SkDebugCanvas.h @@ -194,6 +194,8 @@ protected: void didConcat(const SkMatrix&) override; void didSetMatrix(const SkMatrix&) override; + void didTranslateZ(SkScalar) override; + void onDrawAnnotation(const SkRect&, const char[], SkData*) override; void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override; void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, diff --git a/tools/debugger/SkDrawCommand.cpp b/tools/debugger/SkDrawCommand.cpp index ecd6a7003f..8f42cb70ec 100644 --- a/tools/debugger/SkDrawCommand.cpp +++ b/tools/debugger/SkDrawCommand.cpp @@ -28,6 +28,7 @@ #define SKDEBUGCANVAS_ATTRIBUTE_COMMAND "command" #define SKDEBUGCANVAS_ATTRIBUTE_VISIBLE "visible" #define SKDEBUGCANVAS_ATTRIBUTE_MATRIX "matrix" +#define SKDEBUGCANVAS_ATTRIBUTE_DRAWDEPTHTRANS "drawDepthTranslation" #define SKDEBUGCANVAS_ATTRIBUTE_COORDS "coords" #define SKDEBUGCANVAS_ATTRIBUTE_BOUNDS "bounds" #define SKDEBUGCANVAS_ATTRIBUTE_PAINT "paint" @@ -211,6 +212,7 @@ const char* SkDrawCommand::GetCommandString(OpType type) { case kSave_OpType: return "Save"; case kSaveLayer_OpType: return "SaveLayer"; case kSetMatrix_OpType: return "SetMatrix"; + case kTranslateZ_OpType: return "TranslateZ"; default: SkDebugf("OpType error 0x%08x\n", type); SkASSERT(0); @@ -268,6 +270,8 @@ SkDrawCommand* SkDrawCommand::fromJSON(Json::Value& command, UrlDataManager& url INSTALL_FACTORY(Save); INSTALL_FACTORY(SaveLayer); INSTALL_FACTORY(SetMatrix); + + INSTALL_FACTORY(TranslateZ); } SkString name = SkString(command[SKDEBUGCANVAS_ATTRIBUTE_COMMAND].asCString()); FROM_JSON* factory = factories.find(name); @@ -470,6 +474,11 @@ Json::Value SkDrawCommand::MakeJsonMatrix(const SkMatrix& matrix) { return result; } +Json::Value SkDrawCommand::MakeJsonScalar(SkScalar z) { + Json::Value result(z); + return result; +} + Json::Value SkDrawCommand::MakeJsonPath(const SkPath& path) { Json::Value result(Json::objectValue); switch (path.getFillType()) { @@ -1482,6 +1491,11 @@ static void extract_json_matrix(Json::Value& matrix, SkMatrix* result) { result->set9(values); } +static void extract_json_scalar(Json::Value& scalar, SkScalar* result) { + SkScalar value = scalar.asFloat(); + *result = value; +} + static void extract_json_path(Json::Value& path, SkPath* result) { const char* fillType = path[SKDEBUGCANVAS_ATTRIBUTE_FILLTYPE].asCString(); if (!strcmp(fillType, SKDEBUGCANVAS_FILLTYPE_WINDING)) { @@ -3295,3 +3309,26 @@ SkSetMatrixCommand* SkSetMatrixCommand::fromJSON(Json::Value& command, extract_json_matrix(command[SKDEBUGCANVAS_ATTRIBUTE_MATRIX], &matrix); return new SkSetMatrixCommand(matrix); } + +SkTranslateZCommand::SkTranslateZCommand(SkScalar z) + : INHERITED(kTranslateZ_OpType) { + fZTranslate = z; + fInfo.push(SkObjectParser::ScalarToString(fZTranslate, "drawDepthTranslation")); +} + +void SkTranslateZCommand::execute(SkCanvas* canvas) const { + canvas->translateZ(fZTranslate); +} + +Json::Value SkTranslateZCommand::toJSON(UrlDataManager& urlDataManager) const { + Json::Value result = INHERITED::toJSON(urlDataManager); + result[SKDEBUGCANVAS_ATTRIBUTE_DRAWDEPTHTRANS] = MakeJsonScalar(fZTranslate); + return result; +} + +SkTranslateZCommand* SkTranslateZCommand::fromJSON(Json::Value& command, + UrlDataManager& urlDataManager) { + SkScalar z; + extract_json_scalar(command[SKDEBUGCANVAS_ATTRIBUTE_DRAWDEPTHTRANS], &z); + return new SkTranslateZCommand(z); +} diff --git a/tools/debugger/SkDrawCommand.h b/tools/debugger/SkDrawCommand.h index dc639ec3a3..a7e6c73802 100644 --- a/tools/debugger/SkDrawCommand.h +++ b/tools/debugger/SkDrawCommand.h @@ -56,8 +56,9 @@ public: kSave_OpType, kSaveLayer_OpType, kSetMatrix_OpType, + kTranslateZ_OpType, - kLast_OpType = kSetMatrix_OpType + kLast_OpType = kTranslateZ_OpType }; static const int kOpTypeCount = kLast_OpType + 1; @@ -125,6 +126,7 @@ public: static Json::Value MakeJsonRect(const SkRect& rect); static Json::Value MakeJsonIRect(const SkIRect&); static Json::Value MakeJsonMatrix(const SkMatrix&); + static Json::Value MakeJsonScalar(SkScalar); static Json::Value MakeJsonPath(const SkPath& path); static Json::Value MakeJsonRegion(const SkRegion& region); static Json::Value MakeJsonPaint(const SkPaint& paint, UrlDataManager& urlDataManager); @@ -731,4 +733,16 @@ private: typedef SkDrawCommand INHERITED; }; +class SkTranslateZCommand : public SkDrawCommand { +public: + SkTranslateZCommand(SkScalar); + void execute(SkCanvas* canvas) const override; + Json::Value toJSON(UrlDataManager& urlDataManager) const override; + static SkTranslateZCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager); + +private: + SkScalar fZTranslate; + + typedef SkDrawCommand INHERITED; +}; #endif