diff options
author | Mike Klein <mtklein@google.com> | 2018-09-21 11:19:45 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-09-21 17:20:25 +0000 |
commit | 60900b55f9e1d7e566449c923f2a8104f53f2d04 (patch) | |
tree | 9d32d9b0465743921abe1d4a84a8edc81c605d28 /experimental | |
parent | 1466af42a4f0a280a03c1fc6cc254336e865c301 (diff) | |
download | skqp-60900b55f9e1d7e566449c923f2a8104f53f2d04.tar.gz |
move skpipe to experimental
Nothing's using it except test tools.
I'd like to make that a bit clearer by getting it out of src.
Disabled the fuzzer.
Removed the bench so Android's building nanobench doesn't block this.
Bug: chromium:886713
Change-Id: I761f52c40171c27ff4b699409b32647e84684ec3
Reviewed-on: https://skia-review.googlesource.com/156240
Commit-Queue: Mike Klein <mtklein@google.com>
Reviewed-by: Kevin Lubick <kjlubick@google.com>
Diffstat (limited to 'experimental')
-rw-r--r-- | experimental/pipe/SkPipe.h | 76 | ||||
-rw-r--r-- | experimental/pipe/SkPipeCanvas.cpp | 980 | ||||
-rw-r--r-- | experimental/pipe/SkPipeCanvas.h | 167 | ||||
-rw-r--r-- | experimental/pipe/SkPipeFormat.h | 216 | ||||
-rw-r--r-- | experimental/pipe/SkPipeReader.cpp | 887 | ||||
-rw-r--r-- | experimental/pipe/SkRefSet.h | 38 |
6 files changed, 2364 insertions, 0 deletions
diff --git a/experimental/pipe/SkPipe.h b/experimental/pipe/SkPipe.h new file mode 100644 index 0000000000..65b4e01828 --- /dev/null +++ b/experimental/pipe/SkPipe.h @@ -0,0 +1,76 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkPipe_DEFINED +#define SkPipe_DEFINED + +#include "SkData.h" +#include "SkImage.h" +#include "SkPicture.h" +#include "SkSerialProcs.h" + +class SkCanvas; +class SkTypeface; +class SkWStream; + +struct SkRect; + +class SkPipeSerializer { +public: + SkPipeSerializer(); + ~SkPipeSerializer(); + + void setSerialProcs(const SkSerialProcs&); + + void resetCache(); + + sk_sp<SkData> writeImage(SkImage*); + sk_sp<SkData> writePicture(SkPicture*); + + void writeImage(SkImage*, SkWStream*); + void writePicture(SkPicture*, SkWStream*); + + SkCanvas* beginWrite(const SkRect& cullBounds, SkWStream*); + void endWrite(); + +private: + class Impl; + std::unique_ptr<Impl> fImpl; +}; + +class SkPipeDeserializer { +public: + SkPipeDeserializer(); + ~SkPipeDeserializer(); + + void setDeserialProcs(const SkDeserialProcs&); + + sk_sp<SkImage> readImage(const SkData* data) { + if (!data) { + return nullptr; + } + return this->readImage(data->data(), data->size()); + } + + sk_sp<SkPicture> readPicture(const SkData* data) { + if (!data) { + return nullptr; + } + return this->readPicture(data->data(), data->size()); + } + + sk_sp<SkImage> readImage(const void*, size_t); + sk_sp<SkPicture> readPicture(const void*, size_t); + + bool playback(const void*, size_t, SkCanvas*); + +private: + class Impl; + std::unique_ptr<Impl> fImpl; +}; + +#endif diff --git a/experimental/pipe/SkPipeCanvas.cpp b/experimental/pipe/SkPipeCanvas.cpp new file mode 100644 index 0000000000..1880697231 --- /dev/null +++ b/experimental/pipe/SkPipeCanvas.cpp @@ -0,0 +1,980 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkPipeCanvas.h" + +#include "SkAutoMalloc.h" +#include "SkCanvasPriv.h" +#include "SkColorFilter.h" +#include "SkDrawLooper.h" +#include "SkDrawShadowInfo.h" +#include "SkDrawable.h" +#include "SkImageFilter.h" +#include "SkMaskFilter.h" +#include "SkPathEffect.h" +#include "SkPipeFormat.h" +#include "SkRSXform.h" +#include "SkShader.h" +#include "SkStream.h" +#include "SkTextBlobPriv.h" +#include "SkTo.h" +#include "SkTypeface.h" + +template <typename T> void write_rrect(T* writer, const SkRRect& rrect) { + char tmp[SkRRect::kSizeInMemory]; + rrect.writeToMemory(tmp); + writer->write(tmp, SkRRect::kSizeInMemory); +} + +template <typename T> void write_pad(T* writer, const void* buffer, size_t len) { + writer->write(buffer, len & ~3); + if (len & 3) { + const char* src = (const char*)buffer + (len & ~3); + len &= 3; + uint32_t tmp = 0; + memcpy(&tmp, src, len); + writer->write(&tmp, 4); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +static uint16_t compute_nondef(const SkPaint& paint, PaintUsage usage) { + // kRespectsStroke_PaintUsage is only valid if other bits are also set + SkASSERT(0 != (usage & ~kRespectsStroke_PaintUsage)); + + const SkScalar kTextSize_Default = 12; + const SkScalar kTextScaleX_Default = 1; + const SkScalar kTextSkewX_Default = 0; + const SkScalar kStrokeWidth_Default = 0; + const SkScalar kStrokeMiter_Default = 4; + const SkColor kColor_Default = SK_ColorBLACK; + + unsigned bits = (paint.getColor() != kColor_Default) ? kColor_NonDef : 0; + + if (usage & kText_PaintUsage) { + bits |= (paint.getTextSize() != kTextSize_Default ? kTextSize_NonDef : 0); + bits |= (paint.getTextScaleX() != kTextScaleX_Default ? kTextScaleX_NonDef : 0); + bits |= (paint.getTextSkewX() != kTextSkewX_Default ? kTextSkewX_NonDef : 0); + bits |= (paint.getTypeface() ? kTypeface_NonDef : 0); + } + + // TODO: kImage_PaintUsage only needs the shader/maskfilter IF its colortype is kAlpha_8 + + if (usage & (kVertices_PaintUsage | kDrawPaint_PaintUsage | kImage_PaintUsage | + kText_PaintUsage | kGeometry_PaintUsage | kTextBlob_PaintUsage)) { + bits |= (paint.getShader() ? kShader_NonDef : 0); + } + + if (usage & (kText_PaintUsage | kGeometry_PaintUsage | kTextBlob_PaintUsage)) { + bits |= (paint.getPathEffect() ? kPathEffect_NonDef : 0); + + if (paint.getStyle() != SkPaint::kFill_Style || (usage & kRespectsStroke_PaintUsage)) { + bits |= (paint.getStrokeWidth() != kStrokeWidth_Default ? kStrokeWidth_NonDef : 0); + bits |= (paint.getStrokeMiter() != kStrokeMiter_Default ? kStrokeMiter_NonDef : 0); + } + } + + if (usage & + (kText_PaintUsage | kGeometry_PaintUsage | kImage_PaintUsage | kTextBlob_PaintUsage)) + { + bits |= (paint.getMaskFilter() ? kMaskFilter_NonDef : 0); + } + + bits |= (paint.getColorFilter() ? kColorFilter_NonDef : 0); + bits |= (paint.getImageFilter() ? kImageFilter_NonDef : 0); + bits |= (paint.getDrawLooper() ? kDrawLooper_NonDef : 0); + + return SkToU16(bits); +} + +static uint32_t pack_paint_flags(unsigned flags, unsigned hint, unsigned align, + unsigned filter, unsigned style, unsigned caps, unsigned joins, + unsigned encoding) { + SkASSERT(kFlags_BPF + kHint_BPF + kAlign_BPF + kFilter_BPF <= 32); + + ASSERT_FITS_IN(flags, kFlags_BPF); + ASSERT_FITS_IN(filter, kFilter_BPF); + ASSERT_FITS_IN(style, kStyle_BPF); + ASSERT_FITS_IN(caps, kCaps_BPF); + ASSERT_FITS_IN(joins, kJoins_BPF); + ASSERT_FITS_IN(hint, kHint_BPF); + ASSERT_FITS_IN(align, kAlign_BPF); + ASSERT_FITS_IN(encoding, kEncoding_BPF); + + // left-align the fields of "known" size, and right-align the last (flatFlags) so it can easly + // add more bits in the future. + + uint32_t packed = 0; + int shift = 32; + + shift -= kFlags_BPF; packed |= (flags << shift); + shift -= kFilter_BPF; packed |= (filter << shift); + shift -= kStyle_BPF; packed |= (style << shift); + // these are only needed for stroking (geometry or text) + shift -= kCaps_BPF; packed |= (caps << shift); + shift -= kJoins_BPF; packed |= (joins << shift); + // these are only needed for text + shift -= kHint_BPF; packed |= (hint << shift); + shift -= kAlign_BPF; packed |= (align << shift); + shift -= kEncoding_BPF; packed |= (encoding << shift); + + return packed; +} + +#define CHECK_WRITE_SCALAR(writer, nondef, paint, Field) \ + do { if (nondef & (k##Field##_NonDef)) { \ + writer.writeScalar(paint.get##Field()); \ + }} while (0) + +#define CHECK_WRITE_FLATTENABLE(writer, nondef, paint, Field) \ + do { if (nondef & (k##Field##_NonDef)) { \ + SkFlattenable* f = paint.get##Field(); \ + SkASSERT(f != nullptr); \ + writer.writeFlattenable(f); \ + } } while (0) + +/* + * Header: + * paint flags : 32 + * non_def bits : 16 + * xfermode enum : 8 + * pad zeros : 8 + */ +static void write_paint(SkWriteBuffer& writer, const SkPaint& paint, unsigned usage) { + uint32_t packedFlags = pack_paint_flags(paint.getFlags(), paint.getHinting(), + paint.getTextAlign(), paint.getFilterQuality(), + paint.getStyle(), paint.getStrokeCap(), + paint.getStrokeJoin(), paint.getTextEncoding()); + writer.write32(packedFlags); + + unsigned nondef = compute_nondef(paint, (PaintUsage)usage); + const uint8_t pad = 0; + writer.write32((nondef << 16) | ((unsigned)paint.getBlendMode() << 8) | pad); + + CHECK_WRITE_SCALAR(writer, nondef, paint, TextSize); + CHECK_WRITE_SCALAR(writer, nondef, paint, TextScaleX); + CHECK_WRITE_SCALAR(writer, nondef, paint, TextSkewX); + CHECK_WRITE_SCALAR(writer, nondef, paint, StrokeWidth); + CHECK_WRITE_SCALAR(writer, nondef, paint, StrokeMiter); + + if (nondef & kColor_NonDef) { + writer.write32(paint.getColor()); + } + if (nondef & kTypeface_NonDef) { + // TODO: explore idea of writing bits indicating "use the prev (or prev N) face" + // e.g. 1-N bits is an index into a ring buffer of typefaces + SkTypeface* tf = paint.getTypeface(); + SkASSERT(tf); + writer.writeTypeface(tf); + } + + CHECK_WRITE_FLATTENABLE(writer, nondef, paint, PathEffect); + CHECK_WRITE_FLATTENABLE(writer, nondef, paint, Shader); + CHECK_WRITE_FLATTENABLE(writer, nondef, paint, MaskFilter); + CHECK_WRITE_FLATTENABLE(writer, nondef, paint, ColorFilter); + CHECK_WRITE_FLATTENABLE(writer, nondef, paint, ImageFilter); + CHECK_WRITE_FLATTENABLE(writer, nondef, paint, DrawLooper); +} + +class SkPipeWriter : public SkBinaryWriteBuffer { + enum { + N = 1024/4, + }; + uint32_t fStorage[N]; + SkWStream* fStream; + +public: + SkPipeWriter(SkWStream* stream, SkDeduper* deduper) + : SkBinaryWriteBuffer(fStorage, sizeof(fStorage)) + , fStream(stream) + { + this->setDeduper(deduper); + } + + SkPipeWriter(SkPipeCanvas* pc) : SkPipeWriter(pc->fStream, pc->fDeduper) {} + + ~SkPipeWriter() override { + SkASSERT(SkIsAlign4(fStream->bytesWritten())); + this->writeToStream(fStream); + } + + void writePaint(const SkPaint& paint) override { + write_paint(*this, paint, kUnknown_PaintUsage); + } +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +SkPipeCanvas::SkPipeCanvas(const SkRect& cull, SkPipeDeduper* deduper, SkWStream* stream) + : INHERITED(cull.roundOut()) + , fDeduper(deduper) + , fStream(stream) +{} + +SkPipeCanvas::~SkPipeCanvas() {} + +void SkPipeCanvas::willSave() { + fStream->write32(pack_verb(SkPipeVerb::kSave)); + this->INHERITED::willSave(); +} + +SkCanvas::SaveLayerStrategy SkPipeCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) { + SkPipeWriter writer(this); + uint32_t extra = rec.fSaveLayerFlags; + + // remap this wacky flag + if (extra & SkCanvasPriv::kDontClipToLayer_SaveLayerFlag) { + extra &= ~SkCanvasPriv::kDontClipToLayer_SaveLayerFlag; + extra |= kDontClipToLayer_SaveLayerMask; + } + + if (rec.fBounds) { + extra |= kHasBounds_SaveLayerMask; + } + if (rec.fPaint) { + extra |= kHasPaint_SaveLayerMask; + } + if (rec.fBackdrop) { + extra |= kHasBackdrop_SaveLayerMask; + } + if (rec.fClipMask) { + extra |= kHasClipMask_SaveLayerMask; + } + if (rec.fClipMatrix) { + extra |= kHasClipMatrix_SaveLayerMask; + } + + writer.write32(pack_verb(SkPipeVerb::kSaveLayer, extra)); + if (rec.fBounds) { + writer.writeRect(*rec.fBounds); + } + if (rec.fPaint) { + write_paint(writer, *rec.fPaint, kSaveLayer_PaintUsage); + } + if (rec.fBackdrop) { + writer.writeFlattenable(rec.fBackdrop); + } + if (rec.fClipMask) { + writer.writeImage(rec.fClipMask); + } + if (rec.fClipMatrix) { + writer.writeMatrix(*rec.fClipMatrix); + } + + return kNoLayer_SaveLayerStrategy; +} + +void SkPipeCanvas::willRestore() { + fStream->write32(pack_verb(SkPipeVerb::kRestore)); + this->INHERITED::willRestore(); +} + +template <typename T> void write_sparse_matrix(T* writer, const SkMatrix& matrix) { + SkMatrix::TypeMask tm = matrix.getType(); + SkScalar tmp[9]; + if (tm & SkMatrix::kPerspective_Mask) { + matrix.get9(tmp); + writer->write(tmp, 9 * sizeof(SkScalar)); + } else if (tm & SkMatrix::kAffine_Mask) { + tmp[0] = matrix[SkMatrix::kMScaleX]; + tmp[1] = matrix[SkMatrix::kMSkewX]; + tmp[2] = matrix[SkMatrix::kMTransX]; + tmp[3] = matrix[SkMatrix::kMScaleY]; + tmp[4] = matrix[SkMatrix::kMSkewY]; + tmp[5] = matrix[SkMatrix::kMTransY]; + writer->write(tmp, 6 * sizeof(SkScalar)); + } else if (tm & SkMatrix::kScale_Mask) { + tmp[0] = matrix[SkMatrix::kMScaleX]; + tmp[1] = matrix[SkMatrix::kMTransX]; + tmp[2] = matrix[SkMatrix::kMScaleY]; + tmp[3] = matrix[SkMatrix::kMTransY]; + writer->write(tmp, 4 * sizeof(SkScalar)); + } else if (tm & SkMatrix::kTranslate_Mask) { + tmp[0] = matrix[SkMatrix::kMTransX]; + tmp[1] = matrix[SkMatrix::kMTransY]; + writer->write(tmp, 2 * sizeof(SkScalar)); + } + // else write nothing for Identity +} + +static void do_concat(SkWStream* stream, const SkMatrix& matrix, bool isSetMatrix) { + unsigned mtype = matrix.getType(); + SkASSERT(0 == (mtype & ~kTypeMask_ConcatMask)); + unsigned extra = mtype; + if (isSetMatrix) { + extra |= kSetMatrix_ConcatMask; + } + if (mtype || isSetMatrix) { + stream->write32(pack_verb(SkPipeVerb::kConcat, extra)); + write_sparse_matrix(stream, matrix); + } +} + +void SkPipeCanvas::didConcat(const SkMatrix& matrix) { + do_concat(fStream, matrix, false); + this->INHERITED::didConcat(matrix); +} + +void SkPipeCanvas::didSetMatrix(const SkMatrix& matrix) { + do_concat(fStream, matrix, true); + this->INHERITED::didSetMatrix(matrix); +} + +void SkPipeCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) { + fStream->write32(pack_verb(SkPipeVerb::kClipRect, ((unsigned)op << 1) | edgeStyle)); + fStream->write(&rect, 4 * sizeof(SkScalar)); + + this->INHERITED::onClipRect(rect, op, edgeStyle); +} + +void SkPipeCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) { + fStream->write32(pack_verb(SkPipeVerb::kClipRRect, ((unsigned)op << 1) | edgeStyle)); + write_rrect(fStream, rrect); + + this->INHERITED::onClipRRect(rrect, op, edgeStyle); +} + +void SkPipeCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) { + SkPipeWriter writer(this); + writer.write32(pack_verb(SkPipeVerb::kClipPath, ((unsigned)op << 1) | edgeStyle)); + writer.writePath(path); + + this->INHERITED::onClipPath(path, op, edgeStyle); +} + +void SkPipeCanvas::onClipRegion(const SkRegion& deviceRgn, SkClipOp op) { + SkPipeWriter writer(this); + writer.write32(pack_verb(SkPipeVerb::kClipRegion, (unsigned)op << 1)); + writer.writeRegion(deviceRgn); + + this->INHERITED::onClipRegion(deviceRgn, op); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +void SkPipeCanvas::onDrawArc(const SkRect& bounds, SkScalar startAngle, SkScalar sweepAngle, + bool useCenter, const SkPaint& paint) { + SkPipeWriter writer(this); + writer.write32(pack_verb(SkPipeVerb::kDrawArc, (int)useCenter)); + writer.writeRect(bounds); + writer.writeScalar(startAngle); + writer.writeScalar(sweepAngle); + write_paint(writer, paint, kGeometry_PaintUsage); +} + +void SkPipeCanvas::onDrawAtlas(const SkImage* image, const SkRSXform xform[], const SkRect rect[], + const SkColor colors[], int count, SkBlendMode mode, + const SkRect* cull, const SkPaint* paint) { + unsigned extra = (unsigned)mode; + SkASSERT(0 == (extra & ~kMode_DrawAtlasMask)); + if (colors) { + extra |= kHasColors_DrawAtlasMask; + } + if (cull) { + extra |= kHasCull_DrawAtlasMask; + } + if (paint) { + extra |= kHasPaint_DrawAtlasMask; + } + + SkPipeWriter writer(this); + writer.write32(pack_verb(SkPipeVerb::kDrawAtlas, extra)); + writer.writeImage(image); + writer.write32(count); + writer.write(xform, count * sizeof(SkRSXform)); + writer.write(rect, count * sizeof(SkRect)); + if (colors) { + writer.write(colors, count * sizeof(SkColor)); + } + if (cull) { + writer.writeRect(*cull); + } + if (paint) { + write_paint(writer, *paint, kImage_PaintUsage); + } +} + +void SkPipeCanvas::onDrawPaint(const SkPaint& paint) { + SkPipeWriter writer(this); + writer.write32(pack_verb(SkPipeVerb::kDrawPaint)); + write_paint(writer, paint, kDrawPaint_PaintUsage); +} + +void SkPipeCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[], + const SkPaint& paint) { + SkPipeWriter writer(this); + writer.write32(pack_verb(SkPipeVerb::kDrawPoints, mode)); + writer.write32(SkToU32(count)); + writer.write(pts, count * sizeof(SkPoint)); + write_paint(writer, paint, kGeometry_PaintUsage | kRespectsStroke_PaintUsage); +} + +void SkPipeCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) { + SkPipeWriter writer(this); + writer.write32(pack_verb(SkPipeVerb::kDrawRect)); + writer.write(&rect, sizeof(SkRect)); + write_paint(writer, paint, kGeometry_PaintUsage); +} + +void SkPipeCanvas::onDrawOval(const SkRect& rect, const SkPaint& paint) { + SkPipeWriter writer(this); + writer.write32(pack_verb(SkPipeVerb::kDrawOval)); + writer.write(&rect, sizeof(SkRect)); + write_paint(writer, paint, kGeometry_PaintUsage); +} + +void SkPipeCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) { + SkPipeWriter writer(this); + writer.write32(pack_verb(SkPipeVerb::kDrawRRect)); + write_rrect(&writer, rrect); + write_paint(writer, paint, kGeometry_PaintUsage); +} + +void SkPipeCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) { + SkPipeWriter writer(this); + writer.write32(pack_verb(SkPipeVerb::kDrawDRRect)); + write_rrect(&writer, outer); + write_rrect(&writer, inner); + write_paint(writer, paint, kGeometry_PaintUsage); +} + +void SkPipeCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) { + SkPipeWriter writer(this); + writer.write32(pack_verb(SkPipeVerb::kDrawPath)); + writer.writePath(path); + write_paint(writer, paint, kGeometry_PaintUsage); +} + +void SkPipeCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) { + SkPipeWriter writer(this); + writer.write32(pack_verb(SkPipeVerb::kDrawShadowRec)); + writer.writePath(path); + writer.write(&rec, sizeof(rec)); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +static sk_sp<SkImage> make_from_bitmap(const SkBitmap& bitmap) { + // If we just "make" an image, it will force a CPU copy (if its mutable), only to have + // us then either find it in our cache, or compress and send it. + // + // Better could be to look it up in our cache first, and only create/compress it if we have to. + // + // But for now, just do the dumb thing... + return SkImage::MakeFromBitmap(bitmap); +} + +void SkPipeCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, + const SkPaint* paint) { + sk_sp<SkImage> image = make_from_bitmap(bitmap); + if (image) { + this->onDrawImage(image.get(), x, y, paint); + } +} + +void SkPipeCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, + const SkPaint* paint, SrcRectConstraint constraint) { + sk_sp<SkImage> image = make_from_bitmap(bitmap); + if (image) { + this->onDrawImageRect(image.get(), src, dst, paint, constraint); + } +} + +void SkPipeCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, + const SkRect& dst, const SkPaint* paint) { + sk_sp<SkImage> image = make_from_bitmap(bitmap); + if (image) { + this->onDrawImageNine(image.get(), center, dst, paint); + } +} + +void SkPipeCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, + const SkRect& dst, const SkPaint* paint) { + sk_sp<SkImage> image = make_from_bitmap(bitmap); + if (image) { + this->onDrawImageLattice(image.get(), lattice, dst, paint); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +void SkPipeCanvas::onDrawImage(const SkImage* image, SkScalar left, SkScalar top, + const SkPaint* paint) { + unsigned extra = 0; + if (paint) { + extra |= kHasPaint_DrawImageMask; + } + SkPipeWriter writer(this); + writer.write32(pack_verb(SkPipeVerb::kDrawImage, extra)); + writer.writeImage(image); + writer.writeScalar(left); + writer.writeScalar(top); + if (paint) { + write_paint(writer, *paint, kImage_PaintUsage); + } +} + +void SkPipeCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst, + const SkPaint* paint, SrcRectConstraint constraint) { + SkASSERT(0 == ((unsigned)constraint & ~1)); + unsigned extra = (unsigned)constraint; + if (paint) { + extra |= kHasPaint_DrawImageRectMask; + } + if (src) { + extra |= kHasSrcRect_DrawImageRectMask; + } + + SkPipeWriter writer(this); + writer.write32(pack_verb(SkPipeVerb::kDrawImageRect, extra)); + writer.writeImage(image); + if (src) { + writer.write(src, sizeof(*src)); + } + writer.write(&dst, sizeof(dst)); + if (paint) { + write_paint(writer, *paint, kImage_PaintUsage); + } +} + +void SkPipeCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst, + const SkPaint* paint) { + unsigned extra = 0; + if (paint) { + extra |= kHasPaint_DrawImageNineMask; + } + SkPipeWriter writer(this); + writer.write32(pack_verb(SkPipeVerb::kDrawImageNine, extra)); + writer.writeImage(image); + writer.write(¢er, sizeof(center)); + writer.write(&dst, sizeof(dst)); + if (paint) { + write_paint(writer, *paint, kImage_PaintUsage); + } +} + +void SkPipeCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, + const SkRect& dst, const SkPaint* paint) { + unsigned extra = 0; + if (paint) { + extra |= kHasPaint_DrawImageLatticeMask; + } + SkPipeWriter writer(this); + writer.write32(pack_verb(SkPipeVerb::kDrawImageLattice, extra)); + writer.writeImage(image); + SkCanvasPriv::WriteLattice(writer, lattice); + writer.write(&dst, sizeof(dst)); + if (paint) { + write_paint(writer, *paint, kImage_PaintUsage); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +void SkPipeCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, + const SkPaint& paint) { + SkASSERT(byteLength); + + bool compact = fits_in(byteLength, 24); + + SkPipeWriter writer(this); + writer.write32(pack_verb(SkPipeVerb::kDrawText, compact ? (unsigned)byteLength : 0)); + if (!compact) { + writer.write32(SkToU32(byteLength)); + } + write_pad(&writer, text, byteLength); + writer.writeScalar(x); + writer.writeScalar(y); + write_paint(writer, paint, kText_PaintUsage); +} + +void SkPipeCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], + const SkPaint& paint) { + SkASSERT(byteLength); + + bool compact = fits_in(byteLength, 24); + + SkPipeWriter writer(this); + writer.write32(pack_verb(SkPipeVerb::kDrawPosText, compact ? (unsigned)byteLength : 0)); + if (!compact) { + writer.write32(SkToU32(byteLength)); + } + write_pad(&writer, text, byteLength); + writer.writePointArray(pos, paint.countText(text, byteLength)); + write_paint(writer, paint, kText_PaintUsage); +} + +void SkPipeCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], + SkScalar constY, const SkPaint& paint) { + SkASSERT(byteLength); + + bool compact = fits_in(byteLength, 24); + + SkPipeWriter writer(this); + writer.write32(pack_verb(SkPipeVerb::kDrawPosTextH, compact ? (unsigned)byteLength : 0)); + if (!compact) { + writer.write32(SkToU32(byteLength)); + } + write_pad(&writer, text, byteLength); + writer.writeScalarArray(xpos, paint.countText(text, byteLength)); + writer.writeScalar(constY); + write_paint(writer, paint, kText_PaintUsage); +} + +void SkPipeCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[], + const SkRect* cull, const SkPaint& paint) { + SkASSERT(byteLength); + + bool compact = fits_in(byteLength, 23); + unsigned extra = compact ? (byteLength << 1) : 0; + if (cull) { + extra |= 1; + } + + SkPipeWriter writer(this); + writer.write32(pack_verb(SkPipeVerb::kDrawTextRSXform, extra)); + if (!compact) { + writer.write32(SkToU32(byteLength)); + } + write_pad(&writer, text, byteLength); + + int count = paint.countText(text, byteLength); + writer.write32(count); // maybe we can/should store this in extra as well? + writer.write(xform, count * sizeof(SkRSXform)); + if (cull) { + writer.writeRect(*cull); + } + write_paint(writer, paint, kText_PaintUsage); +} + +void SkPipeCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, + const SkPaint &paint) { + SkPipeWriter writer(this); + writer.write32(pack_verb(SkPipeVerb::kDrawTextBlob, 0)); + SkTextBlobPriv::Flatten(*blob, writer); + writer.writeScalar(x); + writer.writeScalar(y); + write_paint(writer, paint, kTextBlob_PaintUsage); +} + +void SkPipeCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, + const SkPaint* paint) { + unsigned extra = fDeduper->findOrDefinePicture(const_cast<SkPicture*>(picture)); + if (matrix) { + extra |= kHasMatrix_DrawPictureExtra; + } + if (paint) { + extra |= kHasPaint_DrawPictureExtra; + } + SkPipeWriter writer(this); + writer.write32(pack_verb(SkPipeVerb::kDrawPicture, extra)); + if (matrix) { + writer.writeMatrix(*matrix); + } + if (paint) { + write_paint(writer, *paint, kSaveLayer_PaintUsage); + } +} + +void SkPipeCanvas::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) { + // TODO: Is there a better solution than just exploding the drawable? + drawable->draw(this, matrix); +} + +void SkPipeCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) { + size_t size = region.writeToMemory(nullptr); + unsigned extra = 0; + if (fits_in(size, 24)) { + extra = SkToUInt(size); + } + + SkPipeWriter writer(this); + writer.write32(pack_verb(SkPipeVerb::kDrawRegion, extra)); + if (0 == extra) { + writer.write32(size); + } + SkAutoSMalloc<2048> storage(size); + region.writeToMemory(storage.get()); + write_pad(&writer, storage.get(), size); + write_paint(writer, paint, kGeometry_PaintUsage); +} + +void SkPipeCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[], + int boneCount, SkBlendMode bmode, const SkPaint& paint) { + unsigned extra = static_cast<unsigned>(bmode); + + SkPipeWriter writer(this); + writer.write32(pack_verb(SkPipeVerb::kDrawVertices, extra)); + // TODO: dedup vertices? + writer.writeDataAsByteArray(vertices->encode().get()); + writer.write32(boneCount); + writer.write(bones, sizeof(SkVertices::Bone) * boneCount); + write_paint(writer, paint, kVertices_PaintUsage); +} + +void SkPipeCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], + const SkPoint texCoords[4], SkBlendMode bmode, + const SkPaint& paint) { + SkPipeWriter writer(this); + unsigned extra = 0; + SkASSERT(0 == ((int)bmode & ~kModeEnum_DrawPatchExtraMask)); + extra = (unsigned)bmode; + if (colors) { + extra |= kHasColors_DrawPatchExtraMask; + } + if (texCoords) { + extra |= kHasTexture_DrawPatchExtraMask; + } + writer.write32(pack_verb(SkPipeVerb::kDrawPatch, extra)); + writer.write(cubics, sizeof(SkPoint) * 12); + if (colors) { + writer.write(colors, sizeof(SkColor) * 4); + } + if (texCoords) { + writer.write(texCoords, sizeof(SkPoint) * 4); + } + write_paint(writer, paint, kGeometry_PaintUsage); +} + +void SkPipeCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* data) { + const size_t len = strlen(key) + 1; // must write the trailing 0 + bool compact = fits_in(len, 23); + uint32_t extra = compact ? (unsigned)len : 0; + extra <<= 1; // make room for has_data_sentinel + if (data) { + extra |= 1; + } + + fStream->write32(pack_verb(SkPipeVerb::kDrawAnnotation, extra)); + fStream->write(&rect, sizeof(SkRect)); + if (!compact) { + fStream->write32(SkToU32(len)); + } + write_pad(fStream, key, len); + if (data) { + fStream->write32(SkToU32(data->size())); + write_pad(fStream, data->data(), data->size()); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +static sk_sp<SkData> encode(SkImage* img, SkSerialImageProc proc, void* ctx) { + if (proc) { + if (auto data = proc(img, ctx)) { + return data; + } + } + return img->encodeToData(); +} + +static bool show_deduper_traffic = false; + +int SkPipeDeduper::findOrDefineImage(SkImage* image) { + int index = fImages.find(image->uniqueID()); + SkASSERT(index >= 0); + if (index) { + if (show_deduper_traffic) { + SkDebugf(" reuseImage(%d)\n", index - 1); + } + return index; + } + + sk_sp<SkData> data = encode(image, fProcs.fImageProc, fProcs.fImageCtx); + if (data) { + index = fImages.add(image->uniqueID()); + SkASSERT(index > 0); + SkASSERT(fits_in(index, 24)); + fStream->write32(pack_verb(SkPipeVerb::kDefineImage, index)); + + uint32_t len = SkToU32(data->size()); + fStream->write32(SkAlign4(len)); + write_pad(fStream, data->data(), len); + + if (show_deduper_traffic) { + int size = image->width() * image->height() << 2; + SkDebugf(" defineImage(%d) %d -> %d\n", index - 1, size, len); + } + return index; + } + SkDebugf("+++ failed to encode image [%d %d]\n", image->width(), image->height()); + return 0; // failed to encode +} + +int SkPipeDeduper::findOrDefinePicture(SkPicture* picture) { + int index = fPictures.find(picture->uniqueID()); + SkASSERT(index >= 0); + if (index) { + if (show_deduper_traffic) { + SkDebugf(" reusePicture(%d)\n", index - 1); + } + return index; + } + + size_t prevWritten = fStream->bytesWritten(); + unsigned extra = 0; // 0 means we're defining a new picture, non-zero means undef_index + 1 + fStream->write32(pack_verb(SkPipeVerb::kDefinePicture, extra)); + const SkRect cull = picture->cullRect(); + fStream->write(&cull, sizeof(cull)); + picture->playback(fPipeCanvas); + // call fPictures.add *after* we're written the picture, so that any nested pictures will have + // already been defined, and we get the "last" index value. + index = fPictures.add(picture->uniqueID()); + ASSERT_FITS_IN(index, kObjectDefinitionBits); + fStream->write32(pack_verb(SkPipeVerb::kEndPicture, index)); + + if (show_deduper_traffic) { + SkDebugf(" definePicture(%d) %d\n", + index - 1, SkToU32(fStream->bytesWritten() - prevWritten)); + } + return index; +} + +static sk_sp<SkData> encode(const SkSerialProcs& procs, SkTypeface* tf) { + if (procs.fTypefaceProc) { + auto data = procs.fTypefaceProc(tf, procs.fTypefaceCtx); + if (data) { + return data; + } + } + SkDynamicMemoryWStream stream; + tf->serialize(&stream); + return sk_sp<SkData>(stream.detachAsData()); +} + +int SkPipeDeduper::findOrDefineTypeface(SkTypeface* typeface) { + if (!typeface) { + return 0; // default + } + + int index = fTypefaces.find(typeface->uniqueID()); + SkASSERT(index >= 0); + if (index) { + if (show_deduper_traffic) { + SkDebugf(" reuseTypeface(%d)\n", index - 1); + } + return index; + } + + sk_sp<SkData> data = encode(fProcs, typeface); + if (data) { + index = fTypefaces.add(typeface->uniqueID()); + SkASSERT(index > 0); + SkASSERT(fits_in(index, 24)); + fStream->write32(pack_verb(SkPipeVerb::kDefineTypeface, index)); + + uint32_t len = SkToU32(data->size()); + fStream->write32(SkAlign4(len)); + write_pad(fStream, data->data(), len); + + if (show_deduper_traffic) { + SkDebugf(" defineTypeface(%d) %d\n", index - 1, len); + } + return index; + } + SkDebugf("+++ failed to encode typeface %d\n", typeface->uniqueID()); + return 0; // failed to encode +} + +int SkPipeDeduper::findOrDefineFactory(SkFlattenable* flattenable) { + if (!flattenable) { + return 0; + } + + int index = fFactories.find(flattenable->getFactory()); + SkASSERT(index >= 0); + if (index) { + if (show_deduper_traffic) { + SkDebugf(" reuseFactory(%d)\n", index - 1); + } + return index; + } + + index = fFactories.add(flattenable->getFactory()); + ASSERT_FITS_IN(index, kIndex_DefineFactoryExtraBits); + const char* name = flattenable->getTypeName(); + size_t len = strlen(name); + ASSERT_FITS_IN(len, kNameLength_DefineFactoryExtraBits); + unsigned extra = (index << kNameLength_DefineFactoryExtraBits) | len; + size_t prevWritten = fStream->bytesWritten(); + fStream->write32(pack_verb(SkPipeVerb::kDefineFactory, extra)); + write_pad(fStream, name, len + 1); + if (false) { + SkDebugf(" defineFactory(%d) %d %s\n", + index - 1, SkToU32(fStream->bytesWritten() - prevWritten), name); + } + return index; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +#include "SkPipe.h" + +class SkPipeSerializer::Impl { +public: + SkPipeDeduper fDeduper; + std::unique_ptr<SkPipeCanvas> fCanvas; +}; + +SkPipeSerializer::SkPipeSerializer() : fImpl(new Impl) {} + +SkPipeSerializer::~SkPipeSerializer() { + if (fImpl->fCanvas) { + this->endWrite(); + } +} + +void SkPipeSerializer::resetCache() { + fImpl->fDeduper.resetCaches(); +} + +sk_sp<SkData> SkPipeSerializer::writeImage(SkImage* image) { + SkDynamicMemoryWStream stream; + this->writeImage(image, &stream); + return stream.detachAsData(); +} + +sk_sp<SkData> SkPipeSerializer::writePicture(SkPicture* picture) { + SkDynamicMemoryWStream stream; + this->writePicture(picture, &stream); + return stream.detachAsData(); +} + +void SkPipeSerializer::writePicture(SkPicture* picture, SkWStream* stream) { + int index = fImpl->fDeduper.findPicture(picture); + if (0 == index) { + // Try to define the picture + this->beginWrite(picture->cullRect(), stream); + index = fImpl->fDeduper.findOrDefinePicture(picture); + this->endWrite(); + } + stream->write32(pack_verb(SkPipeVerb::kWritePicture, index)); +} + +void SkPipeSerializer::writeImage(SkImage* image, SkWStream* stream) { + int index = fImpl->fDeduper.findImage(image); + if (0 == index) { + // Try to define the image + fImpl->fDeduper.setStream(stream); + index = fImpl->fDeduper.findOrDefineImage(image); + } + stream->write32(pack_verb(SkPipeVerb::kWriteImage, index)); +} + +SkCanvas* SkPipeSerializer::beginWrite(const SkRect& cull, SkWStream* stream) { + SkASSERT(nullptr == fImpl->fCanvas); + fImpl->fCanvas.reset(new SkPipeCanvas(cull, &fImpl->fDeduper, stream)); + fImpl->fDeduper.setStream(stream); + fImpl->fDeduper.setCanvas(fImpl->fCanvas.get()); + return fImpl->fCanvas.get(); +} + +void SkPipeSerializer::endWrite() { + fImpl->fCanvas->restoreToCount(1); + fImpl->fCanvas.reset(nullptr); + fImpl->fDeduper.setCanvas(nullptr); +} diff --git a/experimental/pipe/SkPipeCanvas.h b/experimental/pipe/SkPipeCanvas.h new file mode 100644 index 0000000000..e90a0447b5 --- /dev/null +++ b/experimental/pipe/SkPipeCanvas.h @@ -0,0 +1,167 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkPipeCanvas_DEFINED +#define SkPipeCanvas_DEFINED + +#include "SkCanvasVirtualEnforcer.h" +#include "SkDeduper.h" +#include "SkImage.h" +#include "SkNoDrawCanvas.h" +#include "SkPipe.h" +#include "SkTypeface.h" +#include "SkWriteBuffer.h" + +class SkPipeCanvas; +class SkPipeWriter; + +template <typename T> class SkTIndexSet { +public: + void reset() { fArray.reset(); } + + // returns the found index or 0 + int find(const T& key) const { + const Rec* stop = fArray.end(); + for (const Rec* curr = fArray.begin(); curr < stop; ++curr) { + if (key == curr->fKey) { + return curr->fIndex; + } + } + return 0; + } + + // returns the new index + int add(const T& key) { + Rec* rec = fArray.append(); + rec->fKey = key; + rec->fIndex = fNextIndex++; + return rec->fIndex; + } + +private: + struct Rec { + T fKey; + int fIndex; + }; + + SkTDArray<Rec> fArray; + int fNextIndex = 1; +}; + +class SkPipeDeduper : public SkDeduper { +public: + void resetCaches() { + fImages.reset(); + fPictures.reset(); + fTypefaces.reset(); + fFactories.reset(); + } + + void setCanvas(SkPipeCanvas* canvas) { fPipeCanvas = canvas; } + void setStream(SkWStream* stream) { fStream = stream; } + void setSerialProcs(const SkSerialProcs& procs) { fProcs = procs; } + + // returns 0 if not found + int findImage(SkImage* image) const { return fImages.find(image->uniqueID()); } + int findPicture(SkPicture* picture) const { return fPictures.find(picture->uniqueID()); } + + int findOrDefineImage(SkImage*) override; + int findOrDefinePicture(SkPicture*) override; + int findOrDefineTypeface(SkTypeface*) override; + int findOrDefineFactory(SkFlattenable*) override; + +private: + SkPipeCanvas* fPipeCanvas = nullptr; + SkWStream* fStream = nullptr; + SkSerialProcs fProcs; + + // All our keys (at the moment) are 32bit uniqueIDs + SkTIndexSet<uint32_t> fImages; + SkTIndexSet<uint32_t> fPictures; + SkTIndexSet<uint32_t> fTypefaces; + SkTIndexSet<SkFlattenable::Factory> fFactories; +}; + + +class SkPipeCanvas : public SkCanvasVirtualEnforcer<SkNoDrawCanvas> { +public: + SkPipeCanvas(const SkRect& cull, SkPipeDeduper*, SkWStream*); + ~SkPipeCanvas() override; + +protected: + void willSave() override; + SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override; + void willRestore() override; + + void didConcat(const SkMatrix&) override; + void didSetMatrix(const SkMatrix&) override; + + void onDrawArc(const SkRect&, SkScalar startAngle, SkScalar sweepAngle, bool useCenter, + const SkPaint&) override; + void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], + int count, SkBlendMode, const SkRect* cull, const SkPaint*) override; + void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override; + void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, + const SkPaint&) override; + void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], + const SkPaint&) override; + void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], + SkScalar constY, const SkPaint&) override; + void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint&) override; + void onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[], + const SkRect* cull, const SkPaint& paint) override; + void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], const SkPoint texCoords[4], + SkBlendMode, const SkPaint&) override; + + void onDrawPaint(const SkPaint&) override; + void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override; + void onDrawRect(const SkRect&, const SkPaint&) override; + void onDrawOval(const SkRect&, const SkPaint&) override; + void onDrawRegion(const SkRegion&, const SkPaint&) override; + void onDrawRRect(const SkRRect&, const SkPaint&) override; + void onDrawPath(const SkPath&, const SkPaint&) override; + void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override; + + void onDrawImage(const SkImage*, SkScalar left, SkScalar top, const SkPaint*) override; + void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst, + const SkPaint*, SrcRectConstraint) override; + void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst, + const SkPaint*) override; + void onDrawImageLattice(const SkImage*, const Lattice& lattice, const SkRect& dst, + const SkPaint*) override; + void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount, + SkBlendMode, const SkPaint&) override; + + void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override; + void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override; + void onClipPath(const SkPath&, SkClipOp, ClipEdgeStyle) override; + void onClipRegion(const SkRegion&, SkClipOp) override; + + void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override; + void onDrawAnnotation(const SkRect&, const char[], SkData*) override; + void onDrawDrawable(SkDrawable*, const SkMatrix*) override; + + // These we turn into images + void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint*) override; + void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*, + SrcRectConstraint) override; + void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, + const SkPaint*) override; + void onDrawBitmapLattice(const SkBitmap&, const Lattice& lattice, const SkRect& dst, + const SkPaint*) override; + +private: + SkPipeDeduper* fDeduper; + SkWStream* fStream; + + friend class SkPipeWriter; + + typedef SkCanvasVirtualEnforcer<SkNoDrawCanvas> INHERITED; +}; + + +#endif diff --git a/experimental/pipe/SkPipeFormat.h b/experimental/pipe/SkPipeFormat.h new file mode 100644 index 0000000000..2b494644ca --- /dev/null +++ b/experimental/pipe/SkPipeFormat.h @@ -0,0 +1,216 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkPipeFormat_DEFINED +#define SkPipeFormat_DEFINED + +#include "SkTypes.h" + +#define kDefinePicture_ExtPipeVerb SkSetFourByteTag('s', 'k', 'p', 'i') + +enum class SkPipeVerb : uint8_t { + kSave, // extra == 0 + kSaveLayer, + kRestore, // extra == 0 + kConcat, // extra == SkMatrix::MaskType + + kClipRect, // extra == (SkRegion::Op << 1) | isAntiAlias:1 + kClipRRect, // extra == (SkRegion::Op << 1) | isAntiAlias:1 + kClipPath, // extra == (SkRegion::Op << 1) | isAntiAlias:1 + kClipRegion, // extra == (SkRegion::Op << 1) + + kDrawArc, // extra == useCenter + kDrawAtlas, // extra == has_colors | has_cull | has_paint | mode + kDrawDRRect, + kDrawText, // extra == byteLength:24 else next 32 + kDrawPosText, // extra == byteLength:24 else next 32 + kDrawPosTextH, // extra == byteLength:24 else next 32 + kDrawRegion, // extra == size:24 of region, or 0 means next 32 + kDrawTextBlob, + kDrawTextRSXform, // extra == (byteLength:23 << 1) else next 32 | has_cull_rect:1 + kDrawPatch, + kDrawPaint, // extra == 0 + kDrawPoints, // extra == PointMode + kDrawRect, // extra == 0 + kDrawPath, // extra == 0 + kDrawShadowRec, // extra == 0 + kDrawOval, // extra == 0 + kDrawRRect, // extra == 0 + + kDrawImage, // extra == has_paint:1 + kDrawImageRect, // extra == constraint | has_src_rect | has_paint + kDrawImageNine, // extra == has_paint:1 + kDrawImageLattice, // extra == has_paint:1 + + kDrawVertices, + + kDrawPicture, // extra == picture_index + kDrawAnnotation, // extra == (key_len_plus_1:23 << 1) else next 32 | has_data:1 + + kDefineImage, // extra == image_index + kDefineTypeface, + kDefineFactory, // extra == factory_index (followed by padded getTypeName string) + kDefinePicture, // extra == 0 or forget_index + 1 (0 means we're defining a new picture) + kEndPicture, // extra == picture_index + kWriteImage, // extra == image_index + kWritePicture, // extra == picture_index +}; + +enum PaintUsage { + kText_PaintUsage = 1 << 0, + kTextBlob_PaintUsage = 1 << 1, + kGeometry_PaintUsage = 1 << 2, + kImage_PaintUsage = 1 << 3, + kSaveLayer_PaintUsage = 1 << 4, + kDrawPaint_PaintUsage = 1 << 5, + kVertices_PaintUsage = 1 << 6, + kRespectsStroke_PaintUsage = 1 << 7, + kUnknown_PaintUsage = 0xFF, +}; + +// must sum to <= 32 +enum BitsPerField { + kFlags_BPF = 16, + kFilter_BPF = 2, + kStyle_BPF = 2, + kCaps_BPF = 2, + kJoins_BPF = 2, + kHint_BPF = 2, + kAlign_BPF = 2, + kEncoding_BPF = 2, +}; + +enum { + kTextSize_NonDef = 1 << 0, + kTextScaleX_NonDef = 1 << 1, + kTextSkewX_NonDef = 1 << 2, + kStrokeWidth_NonDef = 1 << 3, + kStrokeMiter_NonDef = 1 << 4, + kColor_NonDef = 1 << 5, + kTypeface_NonDef = 1 << 6, + kPathEffect_NonDef = 1 << 7, + kShader_NonDef = 1 << 8, + kMaskFilter_NonDef = 1 << 9, + kColorFilter_NonDef = 1 << 10, + kRasterizer_NonDef = 1 << 11, + kImageFilter_NonDef = 1 << 12, + kDrawLooper_NonDef = 1 << 13, +}; + +enum { + kFlags_SaveLayerMask = 0xFF, + kHasBounds_SaveLayerMask = 1 << 8, + kHasPaint_SaveLayerMask = 1 << 9, + kHasBackdrop_SaveLayerMask = 1 << 10, + kDontClipToLayer_SaveLayerMask = 1 << 11, + kHasClipMask_SaveLayerMask = 1 << 12, + kHasClipMatrix_SaveLayerMask = 1 << 13, +}; + +enum { + kObjectDefinitionBits = 20, + kIndex_ObjectDefinitionMask = ((1 << kObjectDefinitionBits) - 1), + kUser_ObjectDefinitionMask = 0x7 << kObjectDefinitionBits, + kUndef_ObjectDefinitionMask = 1 << 23, + // (Undef:1 | User:3 | Index:20) must fit in extra:24 +}; + +enum { + kTypeMask_ConcatMask = 0xF, + kSetMatrix_ConcatMask = 1 << 4, +}; + +enum { + kMode_DrawAtlasMask = 0xFF, + kHasColors_DrawAtlasMask = 1 << 8, + kHasCull_DrawAtlasMask = 1 << 9, + kHasPaint_DrawAtlasMask = 1 << 10, +}; + +enum { + kHasPaint_DrawImageMask = 1 << 0, +}; + +enum { + kConstraint_DrawImageRectMask = 1 << 0, + kHasPaint_DrawImageRectMask = 1 << 1, + kHasSrcRect_DrawImageRectMask = 1 << 2, +}; + +enum { + kHasPaint_DrawImageNineMask = 1 << 0, +}; + +enum { + // picture_index takes the first kObjectDefinitionBits bits + kHasMatrix_DrawPictureExtra = 1 << 21, + kHasPaint_DrawPictureExtra = 1 << 22, +}; + +enum { + kIndex_DefineFactoryExtraBits = 10, + kNameLength_DefineFactoryExtraBits = 14, // includes trailing 0 + kNameLength_DefineFactoryExtraMask = (1 << kNameLength_DefineFactoryExtraBits) - 1, +}; + +enum { + kModeEnum_DrawPatchExtraMask = 0xFF, + kExplicitXfer_DrawPatchExtraValue = 0xFF, + kHasColors_DrawPatchExtraMask = 0x100, + kHasTexture_DrawPatchExtraMask = 0x200, +}; + +enum { + // if we store a zero for VCount, then read an int after the packedverb for the vcount + kVCount_DrawVerticesMask = (1 << 11) - 1, + + kVMode_DrawVerticesShift = 11, + kVMode_DrawVerticesMask = 3 << kVMode_DrawVerticesShift, + + kXMode_DrawVerticesShift = 13, + kXMode_DrawVerticesMask = 0xFF << kXMode_DrawVerticesShift, + + kHasTex_DrawVerticesMask = 1 << 21, + kHasColors_DrawVerticesMask = 1 << 22, + kHasIndices_DrawVerticesMask = 1 << 23, +}; + +enum { + kHasPaint_DrawImageLatticeMask = 1 << 0, + kHasFlags_DrawImageLatticeMask = 1 << 1, + kXCount_DrawImageLatticeShift = 2, // bits 2:9 are xcount or FF means 32bits follow + kYCount_DrawImageLatticeShift = 10, // bits 10:17 are ycount or FF means 32bits follow + kCount_DrawImageLatticeMask = 0xFF, // sentinel for 32bits follow, + // thus max inline count is 254 +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +static inline bool fits_in(int value, int bits) { + return value >= 0 && value < (1 << bits); +} + +static inline void ASSERT_FITS_IN(int value, int bits) { + SkASSERT(fits_in(value, bits)); +} + +static inline uint32_t pack_verb(SkPipeVerb verb, unsigned extra = 0) { + //SkDebugf("pack [%d] %d\n", verb, extra); + ASSERT_FITS_IN((unsigned)verb, 8); + ASSERT_FITS_IN(extra, 24); + return ((uint32_t)verb << 24) | extra; +} + +static inline SkPipeVerb unpack_verb(uint32_t data) { + return (SkPipeVerb)(data >> 24); +} + +static inline unsigned unpack_verb_extra(uint32_t data) { + return data & 0xFFFFFF; +} + +#endif diff --git a/experimental/pipe/SkPipeReader.cpp b/experimental/pipe/SkPipeReader.cpp new file mode 100644 index 0000000000..78db5811b0 --- /dev/null +++ b/experimental/pipe/SkPipeReader.cpp @@ -0,0 +1,887 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkCanvas.h" +#include "SkCanvasPriv.h" +#include "SkDeduper.h" +#include "SkDrawShadowInfo.h" +#include "SkPicture.h" +#include "SkPictureRecorder.h" +#include "SkPipe.h" +#include "SkPipeFormat.h" +#include "SkReadBuffer.h" +#include "SkRefSet.h" +#include "SkRSXform.h" +#include "SkTextBlobPriv.h" +#include "SkTypeface.h" +#include "SkVertices.h" + +class SkPipeReader; + +static bool do_playback(SkPipeReader& reader, SkCanvas* canvas, int* endPictureIndex = nullptr); + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class SkPipeInflator : public SkInflator { +public: + SkPipeInflator(SkRefSet<SkImage>* images, SkRefSet<SkPicture>* pictures, + SkRefSet<SkTypeface>* typefaces, SkTDArray<SkFlattenable::Factory>* factories, + const SkDeserialProcs& procs) + : fImages(images) + , fPictures(pictures) + , fTypefaces(typefaces) + , fFactories(factories) + , fProcs(procs) + {} + + SkImage* getImage(int index) override { + return index ? fImages->get(index - 1) : nullptr; + } + SkPicture* getPicture(int index) override { + return index ? fPictures->get(index - 1) : nullptr; + } + SkTypeface* getTypeface(int index) override { + return fTypefaces->get(index - 1); + } + SkFlattenable::Factory getFactory(int index) override { + return index ? fFactories->getAt(index - 1) : nullptr; + } + + bool setImage(int index, sk_sp<SkImage> img) { + return fImages->set(index - 1, std::move(img)); + } + bool setPicture(int index, sk_sp<SkPicture> pic) { + return fPictures->set(index - 1, std::move(pic)); + } + bool setTypeface(int index, sk_sp<SkTypeface> face) { + return fTypefaces->set(index - 1, std::move(face)); + } + bool setFactory(int index, SkFlattenable::Factory factory) { + SkASSERT(index > 0); + SkASSERT(factory); + index -= 1; + if ((unsigned)index < (unsigned)fFactories->count()) { + (*fFactories)[index] = factory; + return true; + } + if (fFactories->count() == index) { + *fFactories->append() = factory; + return true; + } + SkDebugf("setFactory: index [%d] out of range %d\n", index, fFactories->count()); + return false; + } + + void setDeserialProcs(const SkDeserialProcs& procs) { + fProcs = procs; + } + + sk_sp<SkTypeface> makeTypeface(const void* data, size_t size); + sk_sp<SkImage> makeImage(const sk_sp<SkData>&); + +private: + SkRefSet<SkImage>* fImages; + SkRefSet<SkPicture>* fPictures; + SkRefSet<SkTypeface>* fTypefaces; + SkTDArray<SkFlattenable::Factory>* fFactories; + SkDeserialProcs fProcs; +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +static SkRRect read_rrect(SkReadBuffer& reader) { + SkRRect rrect; + rrect.readFromMemory(reader.skip(SkRRect::kSizeInMemory), SkRRect::kSizeInMemory); + return rrect; +} + +static SkMatrix read_sparse_matrix(SkReadBuffer& reader, SkMatrix::TypeMask tm) { + SkMatrix matrix; + matrix.reset(); + + if (tm & SkMatrix::kPerspective_Mask) { + matrix.set9(reader.skipT<SkScalar>(9)); + } else if (tm & SkMatrix::kAffine_Mask) { + const SkScalar* tmp = reader.skipT<SkScalar>(6); + matrix[SkMatrix::kMScaleX] = tmp[0]; + matrix[SkMatrix::kMSkewX] = tmp[1]; + matrix[SkMatrix::kMTransX] = tmp[2]; + matrix[SkMatrix::kMScaleY] = tmp[3]; + matrix[SkMatrix::kMSkewY] = tmp[4]; + matrix[SkMatrix::kMTransY] = tmp[5]; + } else if (tm & SkMatrix::kScale_Mask) { + const SkScalar* tmp = reader.skipT<SkScalar>(4); + matrix[SkMatrix::kMScaleX] = tmp[0]; + matrix[SkMatrix::kMTransX] = tmp[1]; + matrix[SkMatrix::kMScaleY] = tmp[2]; + matrix[SkMatrix::kMTransY] = tmp[3]; + } else if (tm & SkMatrix::kTranslate_Mask) { + const SkScalar* tmp = reader.skipT<SkScalar>(2); + matrix[SkMatrix::kMTransX] = tmp[0]; + matrix[SkMatrix::kMTransY] = tmp[1]; + } + // else read nothing for Identity + return matrix; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#define CHECK_SET_SCALAR(Field) \ + do { if (nondef & k##Field##_NonDef) { \ + paint.set##Field(reader.readScalar()); \ + }} while (0) + +#define CHECK_SET_FLATTENABLE(Field) \ + do { if (nondef & k##Field##_NonDef) { \ + paint.set##Field(reader.read##Field()); \ + }} while (0) + +/* + * Header: + * paint flags : 32 + * non_def bits : 16 + * xfermode enum : 8 + * pad zeros : 8 + */ +static SkPaint read_paint(SkReadBuffer& reader) { + SkPaint paint; + + uint32_t packedFlags = reader.read32(); + uint32_t extra = reader.read32(); + unsigned nondef = extra >> 16; + paint.setBlendMode(SkBlendMode((extra >> 8) & 0xFF)); + SkASSERT((extra & 0xFF) == 0); // zero pad byte + + packedFlags >>= 2; // currently unused + paint.setTextEncoding((SkPaint::TextEncoding)(packedFlags & 3)); packedFlags >>= 2; + paint.setTextAlign((SkPaint::Align)(packedFlags & 3)); packedFlags >>= 2; + paint.setHinting((SkPaint::Hinting)(packedFlags & 3)); packedFlags >>= 2; + paint.setStrokeJoin((SkPaint::Join)(packedFlags & 3)); packedFlags >>= 2; + paint.setStrokeCap((SkPaint::Cap)(packedFlags & 3)); packedFlags >>= 2; + paint.setStyle((SkPaint::Style)(packedFlags & 3)); packedFlags >>= 2; + paint.setFilterQuality((SkFilterQuality)(packedFlags & 3)); packedFlags >>= 2; + paint.setFlags(packedFlags); + + CHECK_SET_SCALAR(TextSize); + CHECK_SET_SCALAR(TextScaleX); + CHECK_SET_SCALAR(TextSkewX); + CHECK_SET_SCALAR(StrokeWidth); + CHECK_SET_SCALAR(StrokeMiter); + + if (nondef & kColor_NonDef) { + paint.setColor(reader.read32()); + } + + CHECK_SET_FLATTENABLE(Typeface); + CHECK_SET_FLATTENABLE(PathEffect); + CHECK_SET_FLATTENABLE(Shader); + CHECK_SET_FLATTENABLE(MaskFilter); + CHECK_SET_FLATTENABLE(ColorFilter); + CHECK_SET_FLATTENABLE(ImageFilter); + CHECK_SET_FLATTENABLE(DrawLooper); + + return paint; +} + +class SkPipeReader : public SkReadBuffer { +public: + SkPipeReader(SkPipeDeserializer* sink, const void* data, size_t size) + : SkReadBuffer(data, size) + , fSink(sink) + {} + + SkPipeDeserializer* fSink; + + SkFlattenable::Factory findFactory(const char name[]) { + SkFlattenable::Factory factory; + // Check if a custom Factory has been specified for this flattenable. + if (!(factory = this->getCustomFactory(SkString(name)))) { + // If there is no custom Factory, check for a default. + factory = SkFlattenable::NameToFactory(name); + } + return factory; + } + + bool readPaint(SkPaint* paint) override { + *paint = read_paint(*this); + return this->isValid(); + } +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +typedef void (*SkPipeHandler)(SkPipeReader&, uint32_t packedVerb, SkCanvas*); + +static void save_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kSave == unpack_verb(packedVerb)); + canvas->save(); +} + +static void saveLayer_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kSaveLayer == unpack_verb(packedVerb)); + unsigned extra = unpack_verb_extra(packedVerb); + const SkRect* bounds = (extra & kHasBounds_SaveLayerMask) ? reader.skipT<SkRect>() : nullptr; + SkPaint paintStorage, *paint = nullptr; + if (extra & kHasPaint_SaveLayerMask) { + paintStorage = read_paint(reader); + paint = &paintStorage; + } + sk_sp<SkImageFilter> backdrop; + if (extra & kHasBackdrop_SaveLayerMask) { + backdrop = reader.readImageFilter(); + } + sk_sp<SkImage> clipMask; + if (extra & kHasClipMask_SaveLayerMask) { + clipMask = reader.readImage(); + } + SkMatrix clipMatrix; + if (extra & kHasClipMatrix_SaveLayerMask) { + reader.readMatrix(&clipMatrix); + } + SkCanvas::SaveLayerFlags flags = (SkCanvas::SaveLayerFlags)(extra & kFlags_SaveLayerMask); + + // unremap this wacky flag + if (extra & kDontClipToLayer_SaveLayerMask) { + flags |= SkCanvasPriv::kDontClipToLayer_SaveLayerFlag; + } + + canvas->saveLayer(SkCanvas::SaveLayerRec(bounds, paint, backdrop.get(), clipMask.get(), + (extra & kHasClipMatrix_SaveLayerMask) ? &clipMatrix : nullptr, flags)); +} + +static void restore_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kRestore == unpack_verb(packedVerb)); + canvas->restore(); +} + +static void concat_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kConcat == unpack_verb(packedVerb)); + SkMatrix::TypeMask tm = (SkMatrix::TypeMask)(packedVerb & kTypeMask_ConcatMask); + const SkMatrix matrix = read_sparse_matrix(reader, tm); + if (packedVerb & kSetMatrix_ConcatMask) { + canvas->setMatrix(matrix); + } else { + canvas->concat(matrix); + } +} + +static void clipRect_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kClipRect == unpack_verb(packedVerb)); + SkClipOp op = (SkClipOp)(unpack_verb_extra(packedVerb) >> 1); + bool isAA = unpack_verb_extra(packedVerb) & 1; + canvas->clipRect(*reader.skipT<SkRect>(), op, isAA); +} + +static void clipRRect_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kClipRRect == unpack_verb(packedVerb)); + SkClipOp op = (SkClipOp)(unpack_verb_extra(packedVerb) >> 1); + bool isAA = unpack_verb_extra(packedVerb) & 1; + canvas->clipRRect(read_rrect(reader), op, isAA); +} + +static void clipPath_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kClipPath == unpack_verb(packedVerb)); + SkClipOp op = (SkClipOp)(unpack_verb_extra(packedVerb) >> 1); + bool isAA = unpack_verb_extra(packedVerb) & 1; + SkPath path; + reader.readPath(&path); + canvas->clipPath(path, op, isAA); +} + +static void clipRegion_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kClipRegion == unpack_verb(packedVerb)); + SkClipOp op = (SkClipOp)(unpack_verb_extra(packedVerb) >> 1); + SkRegion region; + reader.readRegion(®ion); + canvas->clipRegion(region, op); +} + +static void drawArc_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kDrawArc == unpack_verb(packedVerb)); + const bool useCenter = (bool)(unpack_verb_extra(packedVerb) & 1); + const SkScalar* scalars = reader.skipT<SkScalar>(6); // bounds[0..3], start[4], sweep[5] + const SkRect* bounds = (const SkRect*)scalars; + canvas->drawArc(*bounds, scalars[4], scalars[5], useCenter, read_paint(reader)); +} + +static void drawAtlas_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kDrawAtlas == unpack_verb(packedVerb)); + SkBlendMode mode = (SkBlendMode)(packedVerb & kMode_DrawAtlasMask); + sk_sp<SkImage> image(reader.readImage()); + int count = reader.read32(); + const SkRSXform* xform = reader.skipT<SkRSXform>(count); + const SkRect* rect = reader.skipT<SkRect>(count); + const SkColor* color = nullptr; + if (packedVerb & kHasColors_DrawAtlasMask) { + color = reader.skipT<SkColor>(count); + } + const SkRect* cull = nullptr; + if (packedVerb & kHasCull_DrawAtlasMask) { + cull = reader.skipT<SkRect>(); + } + SkPaint paintStorage, *paint = nullptr; + if (packedVerb & kHasPaint_DrawAtlasMask) { + paintStorage = read_paint(reader); + paint = &paintStorage; + } + canvas->drawAtlas(image, xform, rect, color, count, mode, cull, paint); +} + +static void drawDRRect_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kDrawDRRect == unpack_verb(packedVerb)); + const SkRRect outer = read_rrect(reader); + const SkRRect inner = read_rrect(reader); + canvas->drawDRRect(outer, inner, read_paint(reader)); +} + +static void drawText_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kDrawText == unpack_verb(packedVerb)); + uint32_t len = unpack_verb_extra(packedVerb); + if (0 == len) { + len = reader.read32(); + } + const void* text = reader.skip(SkAlign4(len)); + SkScalar x = reader.readScalar(); + SkScalar y = reader.readScalar(); + canvas->drawText(text, len, x, y, read_paint(reader)); +} + +static void drawPosText_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kDrawPosText == unpack_verb(packedVerb)); + uint32_t len = unpack_verb_extra(packedVerb); + if (0 == len) { + len = reader.read32(); + } + const void* text = reader.skip(SkAlign4(len)); + int count = reader.read32(); + const SkPoint* pos = reader.skipT<SkPoint>(count); + SkPaint paint = read_paint(reader); + SkASSERT(paint.countText(text, len) == count); + canvas->drawPosText(text, len, pos, paint); +} + +static void drawPosTextH_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kDrawPosTextH == unpack_verb(packedVerb)); + uint32_t len = unpack_verb_extra(packedVerb); + if (0 == len) { + len = reader.read32(); + } + const void* text = reader.skip(SkAlign4(len)); + int count = reader.read32(); + const SkScalar* xpos = reader.skipT<SkScalar>(count); + SkScalar constY = reader.readScalar(); + SkPaint paint = read_paint(reader); + SkASSERT(paint.countText(text, len) == count); + canvas->drawPosTextH(text, len, xpos, constY, paint); +} + +static void drawTextBlob_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + sk_sp<SkTextBlob> tb = SkTextBlobPriv::MakeFromBuffer(reader); + SkScalar x = reader.readScalar(); + SkScalar y = reader.readScalar(); + canvas->drawTextBlob(tb, x, y, read_paint(reader)); +} + +static void drawTextRSXform_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kDrawTextRSXform == unpack_verb(packedVerb)); + uint32_t len = unpack_verb_extra(packedVerb) >> 1; + if (0 == len) { + len = reader.read32(); + } + const void* text = reader.skip(SkAlign4(len)); + int count = reader.read32(); + const SkRSXform* xform = reader.skipT<SkRSXform>(count); + const SkRect* cull = (packedVerb & 1) ? reader.skipT<SkRect>() : nullptr; + SkPaint paint = read_paint(reader); + SkASSERT(paint.countText(text, len) == count); + canvas->drawTextRSXform(text, len, xform, cull, paint); +} + +static void drawPatch_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kDrawPatch == unpack_verb(packedVerb)); + const SkColor* colors = nullptr; + const SkPoint* tex = nullptr; + const SkPoint* cubics = reader.skipT<SkPoint>(12); + if (packedVerb & kHasColors_DrawPatchExtraMask) { + colors = reader.skipT<SkColor>(4); + } + if (packedVerb & kHasTexture_DrawPatchExtraMask) { + tex = reader.skipT<SkPoint>(4); + } + SkBlendMode mode = (SkBlendMode)(packedVerb & kModeEnum_DrawPatchExtraMask); + canvas->drawPatch(cubics, colors, tex, mode, read_paint(reader)); +} + +static void drawPaint_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kDrawPaint == unpack_verb(packedVerb)); + canvas->drawPaint(read_paint(reader)); +} + +static void drawRect_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kDrawRect == unpack_verb(packedVerb)); + const SkRect* rect = reader.skipT<SkRect>(); + canvas->drawRect(*rect, read_paint(reader)); +} + +static void drawRegion_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kDrawRegion == unpack_verb(packedVerb)); + size_t size = unpack_verb_extra(packedVerb); + if (0 == size) { + size = reader.read32(); + } + SkRegion region; + region.readFromMemory(reader.skipT<char>(size), size); + canvas->drawRegion(region, read_paint(reader)); +} + +static void drawOval_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kDrawOval == unpack_verb(packedVerb)); + const SkRect* rect = reader.skipT<SkRect>(); + canvas->drawOval(*rect, read_paint(reader)); +} + +static void drawRRect_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kDrawRRect == unpack_verb(packedVerb)); + SkRRect rrect = read_rrect(reader); + canvas->drawRRect(rrect, read_paint(reader)); +} + +static void drawPath_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kDrawPath == unpack_verb(packedVerb)); + SkPath path; + reader.readPath(&path); + canvas->drawPath(path, read_paint(reader)); +} + +static void drawShadowRec_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kDrawShadowRec == unpack_verb(packedVerb)); + SkPath path; + reader.readPath(&path); + SkDrawShadowRec rec; + reader.readPad32(&rec, sizeof(rec)); + canvas->private_draw_shadow_rec(path, rec); +} + +static void drawPoints_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kDrawPoints == unpack_verb(packedVerb)); + SkCanvas::PointMode mode = (SkCanvas::PointMode)unpack_verb_extra(packedVerb); + int count = reader.read32(); + const SkPoint* points = reader.skipT<SkPoint>(count); + canvas->drawPoints(mode, count, points, read_paint(reader)); +} + +static void drawImage_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kDrawImage == unpack_verb(packedVerb)); + sk_sp<SkImage> image(reader.readImage()); + SkScalar x = reader.readScalar(); + SkScalar y = reader.readScalar(); + SkPaint paintStorage, *paint = nullptr; + if (packedVerb & kHasPaint_DrawImageMask) { + paintStorage = read_paint(reader); + paint = &paintStorage; + } + canvas->drawImage(image, x, y, paint); +} + +static void drawImageRect_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kDrawImageRect == unpack_verb(packedVerb)); + sk_sp<SkImage> image(reader.readImage()); + SkCanvas::SrcRectConstraint constraint = + (SkCanvas::SrcRectConstraint)(packedVerb & kConstraint_DrawImageRectMask); + const SkRect* src = (packedVerb & kHasSrcRect_DrawImageRectMask) ? + reader.skipT<SkRect>() : nullptr; + const SkRect* dst = reader.skipT<SkRect>(); + SkPaint paintStorage, *paint = nullptr; + if (packedVerb & kHasPaint_DrawImageRectMask) { + paintStorage = read_paint(reader); + paint = &paintStorage; + } + if (src) { + canvas->drawImageRect(image, *src, *dst, paint, constraint); + } else { + canvas->drawImageRect(image, *dst, paint); + } +} + +static void drawImageNine_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kDrawImageNine == unpack_verb(packedVerb)); + sk_sp<SkImage> image(reader.readImage()); + const SkIRect* center = reader.skipT<SkIRect>(); + const SkRect* dst = reader.skipT<SkRect>(); + SkPaint paintStorage, *paint = nullptr; + if (packedVerb & kHasPaint_DrawImageNineMask) { + paintStorage = read_paint(reader); + paint = &paintStorage; + } + canvas->drawImageNine(image, *center, *dst, paint); +} + +static void drawImageLattice_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kDrawImageLattice == unpack_verb(packedVerb)); + sk_sp<SkImage> image(reader.readImage()); + + SkCanvas::Lattice lattice; + if (!SkCanvasPriv::ReadLattice(reader, &lattice)) { + return; + } + const SkRect* dst = reader.skipT<SkRect>(); + + SkPaint paintStorage, *paint = nullptr; + if (packedVerb & kHasPaint_DrawImageLatticeMask) { + paintStorage = read_paint(reader); + paint = &paintStorage; + } + canvas->drawImageLattice(image.get(), lattice, *dst, paint); +} + +static void drawVertices_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kDrawVertices == unpack_verb(packedVerb)); + SkBlendMode bmode = (SkBlendMode)unpack_verb_extra(packedVerb); + sk_sp<SkVertices> vertices = nullptr; + if (sk_sp<SkData> data = reader.readByteArrayAsData()) { + vertices = SkVertices::Decode(data->data(), data->size()); + } + int boneCount = reader.read32(); + const SkVertices::Bone* bones = boneCount ? reader.skipT<SkVertices::Bone>(boneCount) : nullptr; + if (vertices) { + canvas->drawVertices(vertices, bones, boneCount, bmode, read_paint(reader)); + } +} + +static void drawPicture_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kDrawPicture == unpack_verb(packedVerb)); + unsigned extra = unpack_verb_extra(packedVerb); + int index = extra & kIndex_ObjectDefinitionMask; + SkPicture* pic = reader.getInflator()->getPicture(index); + SkMatrix matrixStorage, *matrix = nullptr; + SkPaint paintStorage, *paint = nullptr; + if (extra & kHasMatrix_DrawPictureExtra) { + reader.readMatrix(&matrixStorage); + matrix = &matrixStorage; + } + if (extra & kHasPaint_DrawPictureExtra) { + paintStorage = read_paint(reader); + paint = &paintStorage; + } + canvas->drawPicture(pic, matrix, paint); +} + +static void drawAnnotation_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kDrawAnnotation == unpack_verb(packedVerb)); + const SkRect* rect = reader.skipT<SkRect>(); + + // len includes the key's trailing 0 + uint32_t len = unpack_verb_extra(packedVerb) >> 1; + if (0 == len) { + len = reader.read32(); + } + const char* key = reader.skipT<char>(len); + sk_sp<SkData> data; + if (packedVerb & 1) { + uint32_t size = reader.read32(); + data = SkData::MakeWithCopy(reader.skip(SkAlign4(size)), size); + } + canvas->drawAnnotation(*rect, key, data); +} + +#if 0 + stream.write("skiacodc", 8); + stream.write32(pmap.width()); + stream.write32(pmap.height()); + stream.write16(pmap.colorType()); + stream.write16(pmap.alphaType()); + stream.write32(0); // no colorspace for now + for (int y = 0; y < pmap.height(); ++y) { + stream.write(pmap.addr8(0, y), pmap.width()); + } +#endif + +sk_sp<SkImage> SkPipeInflator::makeImage(const sk_sp<SkData>& data) { + if (fProcs.fImageProc) { + return fProcs.fImageProc(data->data(), data->size(), fProcs.fImageCtx); + } + return SkImage::MakeFromEncoded(data); +} + + +static void defineImage_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas*) { + SkASSERT(SkPipeVerb::kDefineImage == unpack_verb(packedVerb)); + SkPipeInflator* inflator = (SkPipeInflator*)reader.getInflator(); + uint32_t extra = unpack_verb_extra(packedVerb); + int index = extra & kIndex_ObjectDefinitionMask; + + if (extra & kUndef_ObjectDefinitionMask) { + // zero-index means we are "forgetting" that cache entry + inflator->setImage(index, nullptr); + } else { + // we are defining a new image + sk_sp<SkData> data = reader.readByteArrayAsData(); + sk_sp<SkImage> image = data ? inflator->makeImage(data) : nullptr; + if (!image) { + SkDebugf("-- failed to decode\n"); + } + inflator->setImage(index, std::move(image)); + } +} + +sk_sp<SkTypeface> SkPipeInflator::makeTypeface(const void* data, size_t size) { + if (fProcs.fTypefaceProc) { + return fProcs.fTypefaceProc(data, size, fProcs.fTypefaceCtx); + } + SkMemoryStream stream(data, size, false); + return SkTypeface::MakeDeserialize(&stream); +} + +static void defineTypeface_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kDefineTypeface == unpack_verb(packedVerb)); + SkPipeInflator* inflator = (SkPipeInflator*)reader.getInflator(); + uint32_t extra = unpack_verb_extra(packedVerb); + int index = extra & kIndex_ObjectDefinitionMask; + + if (extra & kUndef_ObjectDefinitionMask) { + // zero-index means we are "forgetting" that cache entry + inflator->setTypeface(index, nullptr); + } else { + // we are defining a new image + sk_sp<SkData> data = reader.readByteArrayAsData(); + // TODO: seems like we could "peek" to see the array, and not need to copy it. + sk_sp<SkTypeface> tf = data ? inflator->makeTypeface(data->data(), data->size()) : nullptr; + inflator->setTypeface(index, std::move(tf)); + } +} + +static void defineFactory_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kDefineFactory == unpack_verb(packedVerb)); + SkPipeInflator* inflator = (SkPipeInflator*)reader.getInflator(); + uint32_t extra = unpack_verb_extra(packedVerb); + int index = extra >> kNameLength_DefineFactoryExtraBits; + size_t len = extra & kNameLength_DefineFactoryExtraMask; + // +1 for the trailing null char + const char* name = (const char*)reader.skip(SkAlign4(len + 1)); + SkFlattenable::Factory factory = reader.findFactory(name); + if (factory) { + inflator->setFactory(index, factory); + } +} + +static void definePicture_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SkASSERT(SkPipeVerb::kDefinePicture == unpack_verb(packedVerb)); + int deleteIndex = unpack_verb_extra(packedVerb); + + SkPipeInflator* inflator = (SkPipeInflator*)reader.getInflator(); + + if (deleteIndex) { + inflator->setPicture(deleteIndex - 1, nullptr); + } else { + SkPictureRecorder recorder; + int pictureIndex = -1; // invalid + const SkRect* cull = reader.skipT<SkRect>(); + if (!cull) { + return; + } + do_playback(reader, recorder.beginRecording(*cull), &pictureIndex); + SkASSERT(pictureIndex > 0); + sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture(); + inflator->setPicture(pictureIndex, std::move(picture)); + } +} + +static void endPicture_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) { + SK_ABORT("not reached"); // never call me +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +struct HandlerRec { + SkPipeHandler fProc; + const char* fName; +}; + +#define HANDLER(name) { name##_handler, #name } +const HandlerRec gPipeHandlers[] = { + HANDLER(save), + HANDLER(saveLayer), + HANDLER(restore), + HANDLER(concat), + + HANDLER(clipRect), + HANDLER(clipRRect), + HANDLER(clipPath), + HANDLER(clipRegion), + + HANDLER(drawArc), + HANDLER(drawAtlas), + HANDLER(drawDRRect), + HANDLER(drawText), + HANDLER(drawPosText), + HANDLER(drawPosTextH), + HANDLER(drawRegion), + HANDLER(drawTextBlob), + HANDLER(drawTextRSXform), + HANDLER(drawPatch), + HANDLER(drawPaint), + HANDLER(drawPoints), + HANDLER(drawRect), + HANDLER(drawPath), + HANDLER(drawShadowRec), + HANDLER(drawOval), + HANDLER(drawRRect), + + HANDLER(drawImage), + HANDLER(drawImageRect), + HANDLER(drawImageNine), + HANDLER(drawImageLattice), + + HANDLER(drawVertices), + + HANDLER(drawPicture), + HANDLER(drawAnnotation), + + HANDLER(defineImage), + HANDLER(defineTypeface), + HANDLER(defineFactory), + HANDLER(definePicture), + HANDLER(endPicture), // handled special -- should never be called +}; +#undef HANDLER + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class SkPipeDeserializer::Impl { +public: + SkRefSet<SkImage> fImages; + SkRefSet<SkPicture> fPictures; + SkRefSet<SkTypeface> fTypefaces; + SkTDArray<SkFlattenable::Factory> fFactories; + SkDeserialProcs fProcs; +}; + +SkPipeDeserializer::SkPipeDeserializer() : fImpl(new Impl) {} +SkPipeDeserializer::~SkPipeDeserializer() {} + +void SkPipeDeserializer::setDeserialProcs(const SkDeserialProcs& procs) { + fImpl->fProcs = procs; +} + +sk_sp<SkImage> SkPipeDeserializer::readImage(const void* data, size_t size) { + if (size < sizeof(uint32_t)) { + SkDebugf("-------- data length too short for readImage %d\n", size); + return nullptr; + } + + const uint32_t* ptr = (const uint32_t*)data; + uint32_t packedVerb = *ptr++; + size -= 4; + + if (SkPipeVerb::kDefineImage == unpack_verb(packedVerb)) { + SkPipeInflator inflator(&fImpl->fImages, &fImpl->fPictures, + &fImpl->fTypefaces, &fImpl->fFactories, + fImpl->fProcs); + SkPipeReader reader(this, ptr, size); + reader.setInflator(&inflator); + defineImage_handler(reader, packedVerb, nullptr); + packedVerb = reader.read32(); // read the next verb + } + if (SkPipeVerb::kWriteImage != unpack_verb(packedVerb)) { + SkDebugf("-------- unexpected verb for readImage %d\n", unpack_verb(packedVerb)); + return nullptr; + } + int index = unpack_verb_extra(packedVerb); + if (0 == index) { + return nullptr; // writer failed + } + return sk_ref_sp(fImpl->fImages.get(index - 1)); +} + +sk_sp<SkPicture> SkPipeDeserializer::readPicture(const void* data, size_t size) { + if (size < sizeof(uint32_t)) { + SkDebugf("-------- data length too short for readPicture %d\n", size); + return nullptr; + } + + const uint32_t* ptr = (const uint32_t*)data; + uint32_t packedVerb = *ptr++; + size -= 4; + + if (SkPipeVerb::kDefinePicture == unpack_verb(packedVerb)) { + SkPipeInflator inflator(&fImpl->fImages, &fImpl->fPictures, + &fImpl->fTypefaces, &fImpl->fFactories, + fImpl->fProcs); + SkPipeReader reader(this, ptr, size); + reader.setInflator(&inflator); + definePicture_handler(reader, packedVerb, nullptr); + packedVerb = reader.read32(); // read the next verb + } + if (SkPipeVerb::kWritePicture != unpack_verb(packedVerb)) { + SkDebugf("-------- unexpected verb for readPicture %d\n", unpack_verb(packedVerb)); + return nullptr; + } + int index = unpack_verb_extra(packedVerb); + if (0 == index) { + return nullptr; // writer failed + } + return sk_ref_sp(fImpl->fPictures.get(index - 1)); +} + +static bool do_playback(SkPipeReader& reader, SkCanvas* canvas, int* endPictureIndex) { + int indent = 0; + + const bool showEachVerb = false; + int counter = 0; + while (!reader.eof()) { + uint32_t prevOffset = reader.offset(); + uint32_t packedVerb = reader.read32(); + SkPipeVerb verb = unpack_verb(packedVerb); + if ((unsigned)verb >= SK_ARRAY_COUNT(gPipeHandlers)) { + SkDebugf("------- bad verb %d\n", verb); + return false; + } + if (SkPipeVerb::kRestore == verb) { + indent -= 1; + SkASSERT(indent >= 0); + } + + if (SkPipeVerb::kEndPicture == verb) { + if (endPictureIndex) { + *endPictureIndex = unpack_verb_extra(packedVerb); + } + return true; + } + HandlerRec rec = gPipeHandlers[(unsigned)verb]; + rec.fProc(reader, packedVerb, canvas); + if (showEachVerb) { + for (int i = 0; i < indent; ++i) { + SkDebugf(" "); + } + SkDebugf("%d [%d] %s %d\n", prevOffset, counter++, rec.fName, reader.offset() - prevOffset); + } + if (!reader.isValid()) { + SkDebugf("-------- bad reader\n"); + return false; + } + + switch (verb) { + case SkPipeVerb::kSave: + case SkPipeVerb::kSaveLayer: + indent += 1; + break; + default: + break; + } + } + return true; +} + +bool SkPipeDeserializer::playback(const void* data, size_t size, SkCanvas* canvas) { + SkPipeInflator inflator(&fImpl->fImages, &fImpl->fPictures, + &fImpl->fTypefaces, &fImpl->fFactories, + fImpl->fProcs); + SkPipeReader reader(this, data, size); + reader.setInflator(&inflator); + return do_playback(reader, canvas); +} + diff --git a/experimental/pipe/SkRefSet.h b/experimental/pipe/SkRefSet.h new file mode 100644 index 0000000000..e556196ced --- /dev/null +++ b/experimental/pipe/SkRefSet.h @@ -0,0 +1,38 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkRefSet_DEFINED +#define SkRefSet_DEFINED + +#include "SkRefCnt.h" +#include "SkTArray.h" + +template <typename T> class SkRefSet { +public: + T* get(int index) const { + SkASSERT((unsigned)index < (unsigned)fArray.count()); + return fArray[index].get(); + } + + bool set(int index, sk_sp<T> value) { + if (index < fArray.count()) { + fArray[index] = std::move(value); + return true; + } + if (fArray.count() == index && value) { + fArray.emplace_back(std::move(value)); + return true; + } + SkDebugf("SkRefSet: index [%d] out of range %d\n", index, fArray.count()); + return false; + } + +private: + SkTArray<sk_sp<T>> fArray; +}; + +#endif |