From bb6992a9d6e21b3f28068765de0a41c6f2508dfd Mon Sep 17 00:00:00 2001 From: "reed@google.com" Date: Tue, 26 Apr 2011 17:41:56 +0000 Subject: [PATCH] add experimental canvas pipe git-svn-id: http://skia.googlecode.com/svn/trunk@1187 2bbb7eff-a529-9590-31e7-b0007b416f81 --- include/pipe/SkGPipe.h | 61 +++++ src/pipe/SkGPipePriv.h | 202 ++++++++++++++ src/pipe/SkGPipeRead.cpp | 500 +++++++++++++++++++++++++++++++++++ src/pipe/SkGPipeWrite.cpp | 539 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 1302 insertions(+) create mode 100644 include/pipe/SkGPipe.h create mode 100644 src/pipe/SkGPipePriv.h create mode 100644 src/pipe/SkGPipeRead.cpp create mode 100644 src/pipe/SkGPipeWrite.cpp diff --git a/include/pipe/SkGPipe.h b/include/pipe/SkGPipe.h new file mode 100644 index 000000000..5c729a2ab --- /dev/null +++ b/include/pipe/SkGPipe.h @@ -0,0 +1,61 @@ +/* + Copyright 2011 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +#ifndef SkGPipe_DEFINED +#define SkGPipe_DEFINED + +#include "SkWriter32.h" + +class SkCanvas; + +class SkGPipeReader { +public: + SkGPipeReader(SkCanvas* target); + ~SkGPipeReader(); + + enum Status { + kDone_Status, //!< no more data expected from reader + kEOF_Status, //!< need more data from reader + kError_Status //!< encountered error + }; + + Status playback(const void* data, size_t length); + +private: + SkCanvas* fCanvas; + class SkGPipeState* fState; +}; + +/////////////////////////////////////////////////////////////////////////////// + +class SkGPipeWriter { +public: + SkGPipeWriter(); + ~SkGPipeWriter(); + + bool isRecording() const { return NULL != fCanvas; } + SkCanvas* startRecording(); + void endRecording(); + + size_t flatten(void* buffer); + +private: + class SkGPipeCanvas* fCanvas; + SkWriter32 fWriter; +}; + +#endif diff --git a/src/pipe/SkGPipePriv.h b/src/pipe/SkGPipePriv.h new file mode 100644 index 000000000..ceef2bbd8 --- /dev/null +++ b/src/pipe/SkGPipePriv.h @@ -0,0 +1,202 @@ +/* + Copyright 2011 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +#ifndef SkGPipePriv_DEFINED +#define SkGPipePriv_DEFINED + +#include "SkTypes.h" + +#define UNIMPLEMENTED + +enum DrawOps { + // these match Canvas apis + kClipPath_DrawOp, + kClipRegion_DrawOp, + kClipRect_DrawOp, + kConcat_DrawOp, + kDrawBitmap_DrawOp, + kDrawBitmapMatrix_DrawOp, + kDrawBitmapRect_DrawOp, + kDrawClear_DrawOp, + kDrawData_DrawOp, + kDrawPaint_DrawOp, + kDrawPath_DrawOp, + kDrawPicture_DrawOp, + kDrawPoints_DrawOp, + kDrawPosText_DrawOp, + kDrawPosTextH_DrawOp, + kDrawRect_DrawOp, + kDrawShape_DrawOp, + kDrawSprite_DrawOp, + kDrawText_DrawOp, + kDrawTextOnPath_DrawOp, + kDrawVertices_DrawOp, + kRestore_DrawOp, + kRotate_DrawOp, + kSave_DrawOp, + kSaveLayer_DrawOp, + kScale_DrawOp, + kSetMatrix_DrawOp, + kSkew_DrawOp, + kTranslate_DrawOp, + + // these edit paints + kPaintOp_DrawOp, + + // these are signals to playback, not drawing verbs + kDone_DrawOp, +}; + +/** + * DrawOp packs into a 32bit int as follows + * + * DrawOp:8 - Flags:4 - Data:20 + * + * Flags and Data are called out separately, so we can reuse Data between + * different Ops that might have different Flags. e.g. Data might be a Paint + * index for both drawRect (no flags) and saveLayer (does have flags). + * + * All Ops that take a SkPaint use their Data field to store the index to + * the paint (previously defined with kPaintOp_DrawOp). + */ + +#define DRAWOPS_OP_BITS 8 +#define DRAWOPS_FLAG_BITS 4 +#define DRAWOPS_DATA_BITS 20 + +#define DRAWOPS_OP_MASK ((1 << DRAWOPS_OP_BITS) - 1) +#define DRAWOPS_FLAG_MASK ((1 << DRAWOPS_FLAG_BITS) - 1) +#define DRAWOPS_DATA_MASK ((1 << DRAWOPS_DATA_BITS) - 1) + +static unsigned DrawOp_unpackOp(uint32_t op32) { + return (op32 >> (DRAWOPS_FLAG_BITS + DRAWOPS_DATA_BITS)); +} + +static unsigned DrawOp_unpackFlags(uint32_t op32) { + return (op32 >> DRAWOPS_DATA_BITS) & DRAWOPS_FLAG_MASK; +} + +static unsigned DrawOp_unpackData(uint32_t op32) { + return op32 & DRAWOPS_DATA_MASK; +} + +static uint32_t DrawOp_packOpFlagData(DrawOps op, unsigned flags, unsigned data) { + SkASSERT(0 == (op & ~DRAWOPS_OP_MASK)); + SkASSERT(0 == (flags & ~DRAWOPS_FLAG_MASK)); + SkASSERT(0 == (data & ~DRAWOPS_DATA_MASK)); + + return (op << DRAWOPS_FLAG_BITS + DRAWOPS_DATA_BITS) | + (flags << DRAWOPS_DATA_BITS) | + data; +} + +/** DrawOp specific flag bits + */ + +enum { + kSaveLayer_HasBounds_DrawOpFlag = 1 << 0, + kSaveLayer_HasPaint_DrawOpFlag = 1 << 1, +}; +enum { + kClear_HasColor_DrawOpFlag = 1 << 0 +}; +enum { + kDrawTextOnPath_HasMatrix_DrawOpFlag = 1 << 0 +}; +enum { + kDrawVertices_HasTexs_DrawOpFlag = 1 << 0, + kDrawVertices_HasColors_DrawOpFlag = 1 << 1, + kDrawVertices_HasIndices_DrawOpFlag = 1 << 2, +}; + +/////////////////////////////////////////////////////////////////////////////// + +enum PaintOps { + kReset_PaintOp, // no arg + + kFlags_PaintOp, // arg inline + kColor_PaintOp, // arg 32 + kStyle_PaintOp, // arg inline + kJoin_PaintOp, // arg inline + kCap_PaintOp, // arg inline + kWidth_PaintOp, // arg scalar + kMiter_PaintOp,// arg scalar + + kEncoding_PaintOp, // arg inline - text + kHinting_PaintOp, // arg inline - text + kAlign_PaintOp, // arg inline - text + kTextSize_PaintOp, // arg scalar - text + kTextScaleX_PaintOp,// arg scalar - text + kTextSkewX_PaintOp, // arg scalar - text + + kPathEffect_PaintOp, // arg inline + kShader_PaintOp, + kXfermode_PaintOp, + kMaskFilter_PaintOp, + kColorFilter_PaintOp, + kRasterizer_PaintOp, + kDrawLooper_PaintOp, +}; + +#define PAINTOPS_OP_BITS 8 +#define PAINTOPS_FLAG_BITS 4 +#define PAINTOPS_DATA_BITS 20 + +#define PAINTOPS_OP_MASK ((1 << PAINTOPS_OP_BITS) - 1) +#define PAINTOPS_FLAG_MASK ((1 << PAINTOPS_FLAG_BITS) - 1) +#define PAINTOPS_DATA_MASK ((1 << PAINTOPS_DATA_BITS) - 1) + +static unsigned PaintOp_unpackOp(uint32_t op32) { + return (op32 >> (PAINTOPS_FLAG_BITS + PAINTOPS_DATA_BITS)); +} + +static unsigned PaintOp_unpackFlags(uint32_t op32) { + return (op32 >> PAINTOPS_DATA_BITS) & PAINTOPS_FLAG_MASK; +} + +static unsigned PaintOp_unpackData(uint32_t op32) { + return op32 & PAINTOPS_DATA_MASK; +} + +static uint32_t PaintOp_packOp(PaintOps op) { + SkASSERT(0 == (op & ~PAINTOPS_OP_MASK)); + + return (op << PAINTOPS_FLAG_BITS + PAINTOPS_DATA_BITS); +} + +static uint32_t PaintOp_packOpData(PaintOps op, unsigned data) { + SkASSERT(0 == (op & ~PAINTOPS_OP_MASK)); + SkASSERT(0 == (data & ~PAINTOPS_DATA_MASK)); + + return (op << PAINTOPS_FLAG_BITS + PAINTOPS_DATA_BITS) | data; +} + +static uint32_t PaintOp_packOpFlagData(PaintOps op, unsigned flags, unsigned data) { + SkASSERT(0 == (op & ~PAINTOPS_OP_MASK)); + SkASSERT(0 == (flags & ~PAINTOPS_FLAG_MASK)); + SkASSERT(0 == (data & ~PAINTOPS_DATA_MASK)); + + return (op << PAINTOPS_FLAG_BITS + PAINTOPS_DATA_BITS) | + (flags << PAINTOPS_DATA_BITS) | + data; +} + +enum { + kLastOp_PaintOpFlag = 1 << 0 +}; + +#endif diff --git a/src/pipe/SkGPipeRead.cpp b/src/pipe/SkGPipeRead.cpp new file mode 100644 index 000000000..94f05daee --- /dev/null +++ b/src/pipe/SkGPipeRead.cpp @@ -0,0 +1,500 @@ +/* + Copyright 2011 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkGPipePriv.h" +#include "SkReader32.h" + +class SkGPipeState { +public: + SkGPipeState(); + ~SkGPipeState(); + + const SkPaint& getPaint(uint32_t drawOp32) const; + + // Extracts index from DrawOp_unpackData(). + // Returns the specified paint from our list, or creates a new paint if + // index == count. If index > count, return NULL + SkPaint* editPaint(uint32_t drawOp32); + +private: + SkTDArray fPaints; +}; + +/////////////////////////////////////////////////////////////////////////////// + +template const T* skip(SkReader32* reader, int count = 1) { + SkASSERT(count >= 0); + size_t size = sizeof(T) * count; + SkASSERT(SkAlign4(size) == size); + return reinterpret_cast(reader->skip(size)); +} + +template const T* skipAlign(SkReader32* reader, int count = 1) { + SkASSERT(count >= 0); + size_t size = SkAlign4(sizeof(T) * count); + return reinterpret_cast(reader->skip(size)); +} + +static void readRegion(SkReader32* reader, SkRegion* rgn) { + size_t size = rgn->unflatten(reader->peek()); + SkASSERT(SkAlign4(size) == size); + (void)reader->skip(size); +} + +static void readMatrix(SkReader32* reader, SkMatrix* matrix) { + size_t size = matrix->unflatten(reader->peek()); + SkASSERT(SkAlign4(size) == size); + (void)reader->skip(size); +} + +const SkPaint& SkGPipeState::getPaint(uint32_t op32) const { + unsigned index = DrawOp_unpackData(op32); + if (index >= fPaints.count()) { + SkASSERT(!"paint index out of range"); + index = 0; // we always have at least 1 paint + } + return *fPaints[index]; +} + +SkPaint* SkGPipeState::editPaint(uint32_t op32) { + unsigned index = DrawOp_unpackData(op32); + + if (index > fPaints.count()) { + SkASSERT(!"paint index out of range"); + return NULL; + } + + if (index == fPaints.count()) { + *fPaints.append() = SkNEW(SkPaint); + } + return fPaints[index]; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +static void clipPath_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + SkPath path; + path.unflatten(*reader); + canvas->clipPath(path, (SkRegion::Op)DrawOp_unpackData(op32)); +} + +static void clipRegion_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + SkRegion rgn; + readRegion(reader, &rgn); + canvas->clipRegion(rgn, (SkRegion::Op)DrawOp_unpackData(op32)); +} + +static void clipRect_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + canvas->clipRect(*skip(reader), (SkRegion::Op)DrawOp_unpackData(op32)); +} + +/////////////////////////////////////////////////////////////////////////////// + +static void setMatrix_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + SkMatrix matrix; + readMatrix(reader, &matrix); + canvas->setMatrix(matrix); +} + +static void concat_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + SkMatrix matrix; + readMatrix(reader, &matrix); + canvas->concat(matrix); +} + +static void scale_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + const SkScalar* param = skip(reader, 2); + canvas->scale(param[0], param[1]); +} + +static void skew_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + const SkScalar* param = skip(reader, 2); + canvas->skew(param[0], param[1]); +} + +static void rotate_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + canvas->rotate(reader->readScalar()); +} + +static void translate_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + const SkScalar* param = skip(reader, 2); + canvas->translate(param[0], param[1]); +} + +/////////////////////////////////////////////////////////////////////////////// + +static void save_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + canvas->save((SkCanvas::SaveFlags)DrawOp_unpackData(op32)); +} + +static void saveLayer_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + unsigned flags = DrawOp_unpackData(op32); + + const SkRect* bounds = NULL; + if (flags & kSaveLayer_HasBounds_DrawOpFlag) { + bounds = skip(reader); + } + const SkPaint* paint = NULL; + if (flags & kSaveLayer_HasPaint_DrawOpFlag) { + paint = &state->getPaint(reader->readU32()); + } + canvas->saveLayer(bounds, paint, + (SkCanvas::SaveFlags)DrawOp_unpackFlags(op32)); +} + +static void restore_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + canvas->restore(); +} + +/////////////////////////////////////////////////////////////////////////////// + +static void drawClear_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + SkColor color = 0; + if (DrawOp_unpackFlags(op32) & kClear_HasColor_DrawOpFlag) { + color = reader->readU32(); + } + canvas->clear(color); +} + +static void drawPaint_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + canvas->drawPaint(state->getPaint(op32)); +} + +static void drawPoints_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + SkCanvas::PointMode mode = (SkCanvas::PointMode)DrawOp_unpackFlags(op32); + size_t count = reader->readU32(); + const SkPoint* pts = skip(reader, count); + canvas->drawPoints(mode, count, pts, state->getPaint(op32)); +} + +static void drawRect_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + canvas->drawRect(*skip(reader), state->getPaint(op32)); +} + +static void drawPath_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + SkPath path; + path.unflatten(*reader); + canvas->drawPath(path, state->getPaint(op32)); +} + +static void drawVertices_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + unsigned flags = DrawOp_unpackFlags(op32); + + SkCanvas::VertexMode mode = (SkCanvas::VertexMode)reader->readU32(); + int vertexCount = reader->readU32(); + const SkPoint* verts = skip(reader, vertexCount); + + const SkPoint* texs = NULL; + if (flags & kDrawVertices_HasTexs_DrawOpFlag) { + texs = skip(reader, vertexCount); + } + + const SkColor* colors = NULL; + if (flags & kDrawVertices_HasColors_DrawOpFlag) { + colors = skip(reader, vertexCount); + } + + // TODO: flatten/unflatten xfermodes + SkXfermode* xfer = NULL; + + int indexCount = 0; + const uint16_t* indices = NULL; + if (flags & kDrawVertices_HasIndices_DrawOpFlag) { + indexCount = reader->readU32(); + indices = skipAlign(reader, indexCount); + } + + canvas->drawVertices(mode, vertexCount, verts, texs, colors, xfer, + indices, indexCount, state->getPaint(op32)); +} + +/////////////////////////////////////////////////////////////////////////////// + +static void drawText_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + size_t len = reader->readU32(); + const void* text = reader->skip(SkAlign4(len)); + const SkScalar* xy = skip(reader, 2); + canvas->drawText(text, len, xy[0], xy[1], state->getPaint(op32)); +} + +static void drawPosText_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + size_t len = reader->readU32(); + const void* text = reader->skip(SkAlign4(len)); + size_t posCount = reader->readU32(); // compute by our writer + const SkPoint* pos = skip(reader, posCount); + canvas->drawPosText(text, len, pos, state->getPaint(op32)); +} + +static void drawPosTextH_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + size_t len = reader->readU32(); + const void* text = reader->skip(SkAlign4(len)); + size_t posCount = reader->readU32(); // compute by our writer + const SkScalar* xpos = skip(reader, posCount); + SkScalar constY = reader->readScalar(); + canvas->drawPosTextH(text, len, xpos, constY, state->getPaint(op32)); +} + +static void drawTextOnPath_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + size_t len = reader->readU32(); + const void* text = reader->skip(SkAlign4(len)); + + SkPath path; + path.unflatten(*reader); + + SkMatrix matrixStorage; + const SkMatrix* matrix = NULL; + if (DrawOp_unpackFlags(op32) & kDrawTextOnPath_HasMatrix_DrawOpFlag) { + readMatrix(reader, &matrixStorage); + matrix = &matrixStorage; + } + + canvas->drawTextOnPath(text, len, path, matrix, state->getPaint(op32)); +} + +/////////////////////////////////////////////////////////////////////////////// + +static void drawBitmap_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + UNIMPLEMENTED +} + +static void drawBitmapMatrix_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + UNIMPLEMENTED +} + +static void drawBitmapRect_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + UNIMPLEMENTED +} + +static void drawSprite_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + UNIMPLEMENTED +} + +/////////////////////////////////////////////////////////////////////////////// + +static void drawData_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + // since we don't have a paint, we can use data for our (small) sizes + size_t size = DrawOp_unpackData(op32); + if (0 == size) { + size = reader->readU32(); + } + const void* data = reader->skip(SkAlign4(size)); + canvas->drawData(data, size); +} + +static void drawShape_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + UNIMPLEMENTED +} + +static void drawPicture_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + UNIMPLEMENTED +} + +/////////////////////////////////////////////////////////////////////////////// + +static void inflate_patheffect(SkReader32* reader, SkPaint* paint) { +} + +static void inflate_shader(SkReader32* reader, SkPaint* paint) { +} + +static void inflate_xfermode(SkReader32* reader, SkPaint* paint) { +} + +static void inflate_maskfilter(SkReader32* reader, SkPaint* paint) { +} + +static void inflate_colorfilter(SkReader32* reader, SkPaint* paint) { +} + +static void inflate_rasterizer(SkReader32* reader, SkPaint* paint) { +} + +static void inflate_drawlooper(SkReader32* reader, SkPaint* paint) { +} + +static void paintOp_rp(SkCanvas*, SkReader32* reader, uint32_t op32, + SkGPipeState* state) { + SkPaint* p = state->editPaint(op32); + int done; + + do { + uint32_t p32 = reader->readU32(); + unsigned op = PaintOp_unpackOp(p32); + unsigned data = PaintOp_unpackData(p32); + done = PaintOp_unpackFlags(p32) & kLastOp_PaintOpFlag; + + SkDebugf(" read %08X op=%d flags=%d data=%d\n", p32, op, done, data); + + switch (op) { + case kReset_PaintOp: p->reset(); break; + case kFlags_PaintOp: p->setFlags(data); break; + case kColor_PaintOp: p->setColor(reader->readU32()); break; + case kStyle_PaintOp: p->setStyle((SkPaint::Style)data); break; + case kJoin_PaintOp: p->setStrokeJoin((SkPaint::Join)data); break; + case kCap_PaintOp: p->setStrokeCap((SkPaint::Cap)data); break; + case kWidth_PaintOp: p->setStrokeWidth(reader->readScalar()); break; + case kMiter_PaintOp: p->setStrokeMiter(reader->readScalar()); break; + case kEncoding_PaintOp: + p->setTextEncoding((SkPaint::TextEncoding)data); + break; + case kHinting_PaintOp: p->setHinting((SkPaint::Hinting)data); break; + case kAlign_PaintOp: p->setTextAlign((SkPaint::Align)data); break; + case kTextSize_PaintOp: p->setTextSize(reader->readScalar()); break; + case kTextScaleX_PaintOp: p->setTextScaleX(reader->readScalar()); break; + case kTextSkewX_PaintOp: p->setTextSkewX(reader->readScalar()); break; + + // flag to reference a cached index instead of inflating? + case kPathEffect_PaintOp: inflate_patheffect(reader, p); break; + case kShader_PaintOp: inflate_shader(reader, p); break; + case kXfermode_PaintOp: inflate_xfermode(reader, p); break; + case kMaskFilter_PaintOp: inflate_maskfilter(reader, p); break; + case kColorFilter_PaintOp: inflate_colorfilter(reader, p); break; + case kRasterizer_PaintOp: inflate_rasterizer(reader, p); break; + case kDrawLooper_PaintOp: inflate_drawlooper(reader, p); break; + default: SkASSERT(!"bad paintop"); return; + } + } while (!done); +} + +/////////////////////////////////////////////////////////////////////////////// + +static void done_rp(SkCanvas*, SkReader32*, uint32_t, SkGPipeState*) {} + +typedef void (*ReadProc)(SkCanvas*, SkReader32*, uint32_t op32, SkGPipeState*); + +static const ReadProc gReadTable[] = { + clipPath_rp, + clipRegion_rp, + clipRect_rp, + concat_rp, + drawBitmap_rp, + drawBitmapMatrix_rp, + drawBitmapRect_rp, + drawClear_rp, + drawData_rp, + drawPaint_rp, + drawPath_rp, + drawPicture_rp, + drawPoints_rp, + drawPosText_rp, + drawPosTextH_rp, + drawRect_rp, + drawShape_rp, + drawSprite_rp, + drawText_rp, + drawTextOnPath_rp, + drawVertices_rp, + restore_rp, + rotate_rp, + save_rp, + saveLayer_rp, + scale_rp, + setMatrix_rp, + skew_rp, + translate_rp, + paintOp_rp, + done_rp +}; + +/////////////////////////////////////////////////////////////////////////////// + +SkGPipeState::SkGPipeState() { + // start out with one paint in default state + *fPaints.append() = SkNEW(SkPaint); +} + +SkGPipeState::~SkGPipeState() { + fPaints.deleteAll(); +} + +/////////////////////////////////////////////////////////////////////////////// + +#include "SkGPipe.h" + +SkGPipeReader::SkGPipeReader(SkCanvas* target) { + SkSafeRef(target); + fCanvas = target; + fState = NULL; +} + +SkGPipeReader::~SkGPipeReader() { + SkSafeUnref(fCanvas); + delete fState; +} + +SkGPipeReader::Status SkGPipeReader::playback(const void* data, size_t length) { + if (NULL == fCanvas) { + return kError_Status; + } + + if (NULL == fState) { + fState = new SkGPipeState; + } + + const ReadProc* table = gReadTable; + SkReader32 reader(data, length); + SkCanvas* canvas = fCanvas; + + while (!reader.eof()) { + uint32_t op32 = reader.readU32(); + unsigned op = DrawOp_unpackOp(op32); + + if (op >= SK_ARRAY_COUNT(gReadTable)) { + SkDebugf("---- bad op during GPipeState::playback\n"); + return kError_Status; + } + if (kDone_DrawOp == op) { + return kDone_Status; + } + table[op](canvas, &reader, op32, fState); + } + return kEOF_Status; +} + + diff --git a/src/pipe/SkGPipeWrite.cpp b/src/pipe/SkGPipeWrite.cpp new file mode 100644 index 000000000..a33071377 --- /dev/null +++ b/src/pipe/SkGPipeWrite.cpp @@ -0,0 +1,539 @@ +/* + Copyright 2011 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkGPipePriv.h" +#include "SkGPipeState.h" +#include "SkWriter32.h" + +static void writeRegion(SkWriter32* writer, const SkRegion& rgn) { + size_t size = rgn.flatten(NULL); + SkASSERT(SkAlign4(size) == size); + rgn.flatten(writer->reserve(size)); +} + +static void writeMatrix(SkWriter32* writer, const SkMatrix& matrix) { + size_t size = matrix.flatten(NULL); + SkASSERT(SkAlign4(size) == size); + matrix.flatten(writer->reserve(size)); +} + +/////////////////////////////////////////////////////////////////////////////// + +class SkGPipeCanvas : public SkCanvas { +public: + SkGPipeCanvas(SkWriter32* writer); + virtual ~SkGPipeCanvas(); + + void finish() { + if (!fDone) { + this->writeOp(kDone_DrawOp); + fDone = true; + } + } + + // overrides from SkCanvas + virtual int save(SaveFlags); + virtual int saveLayer(const SkRect* bounds, const SkPaint*, SaveFlags); + virtual void restore(); + virtual bool translate(SkScalar dx, SkScalar dy); + virtual bool scale(SkScalar sx, SkScalar sy); + virtual bool rotate(SkScalar degrees); + virtual bool skew(SkScalar sx, SkScalar sy); + virtual bool concat(const SkMatrix& matrix); + virtual void setMatrix(const SkMatrix& matrix); + virtual bool clipRect(const SkRect& rect, SkRegion::Op op); + virtual bool clipPath(const SkPath& path, SkRegion::Op op); + virtual bool clipRegion(const SkRegion& region, SkRegion::Op op); + virtual void clear(SkColor); + virtual void drawPaint(const SkPaint& paint); + virtual void drawPoints(PointMode, size_t count, const SkPoint pts[], + const SkPaint&); + virtual void drawRect(const SkRect& rect, const SkPaint&); + virtual void drawPath(const SkPath& path, const SkPaint&); + virtual void drawBitmap(const SkBitmap&, SkScalar left, SkScalar top, + const SkPaint*); + virtual void drawBitmapRect(const SkBitmap&, const SkIRect* src, + const SkRect& dst, const SkPaint*); + virtual void drawBitmapMatrix(const SkBitmap&, const SkMatrix&, + const SkPaint*); + virtual void drawSprite(const SkBitmap&, int left, int top, + const SkPaint*); + virtual void drawText(const void* text, size_t byteLength, SkScalar x, + SkScalar y, const SkPaint&); + virtual void drawPosText(const void* text, size_t byteLength, + const SkPoint pos[], const SkPaint&); + virtual void drawPosTextH(const void* text, size_t byteLength, + const SkScalar xpos[], SkScalar constY, const SkPaint&); + virtual void drawTextOnPath(const void* text, size_t byteLength, + const SkPath& path, const SkMatrix* matrix, + const SkPaint&); + virtual void drawPicture(SkPicture& picture); + virtual void drawShape(SkShape*); + virtual void drawVertices(VertexMode, int vertexCount, + const SkPoint vertices[], const SkPoint texs[], + const SkColor colors[], SkXfermode*, + const uint16_t indices[], int indexCount, + const SkPaint&); + virtual void drawData(const void*, size_t); + +private: + SkWriter32& fWriter; + bool fDone; + + void writeOp(DrawOps op, unsigned flags, unsigned data) { + fWriter.write32(DrawOp_packOpFlagData(op, flags, data)); + } + + void writeOp(DrawOps op) { + fWriter.write32(DrawOp_packOpFlagData(op, 0, 0)); + } + + SkTDArray fPaints; + unsigned writePaint(const SkPaint&); + + typedef SkCanvas INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + + +SkGPipeCanvas::SkGPipeCanvas(SkWriter32* writer) : fWriter(*writer) { + fDone = false; + // always begin with 1 default paint + *fPaints.append() = SkNEW(SkPaint); +} + +SkGPipeCanvas::~SkGPipeCanvas() { + this->finish(); + + fPaints.deleteAll(); +} + +/////////////////////////////////////////////////////////////////////////////// + +int SkGPipeCanvas::save(SaveFlags flags) { + this->writeOp(kSave_DrawOp, 0, flags); + return this->INHERITED::save(flags); +} + +int SkGPipeCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, + SaveFlags saveFlags) { + unsigned index = 0; // just to avoid the warning + unsigned opFlags = 0; + + if (bounds) { + opFlags |= kSaveLayer_HasBounds_DrawOpFlag; + } + if (paint) { + opFlags |= kSaveLayer_HasPaint_DrawOpFlag; + index = this->writePaint(*paint); + } + + this->writeOp(kSaveLayer_DrawOp, opFlags, saveFlags); + if (bounds) { + fWriter.writeRect(*bounds); + } + if (paint) { + fWriter.write32(index); + } + + // we just pass on the save, so we don't create a layer + return this->INHERITED::save(saveFlags); +} + +void SkGPipeCanvas::restore() { + this->writeOp(kRestore_DrawOp); + this->INHERITED::restore(); +} + +bool SkGPipeCanvas::translate(SkScalar dx, SkScalar dy) { + if (dx || dy) { + this->writeOp(kTranslate_DrawOp); + fWriter.writeScalar(dx); + fWriter.writeScalar(dy); + } + return this->INHERITED::translate(dx, dy); +} + +bool SkGPipeCanvas::scale(SkScalar sx, SkScalar sy) { + if (sx || sy) { + this->writeOp(kScale_DrawOp); + fWriter.writeScalar(sx); + fWriter.writeScalar(sy); + } + return this->INHERITED::scale(sx, sy); +} + +bool SkGPipeCanvas::rotate(SkScalar degrees) { + if (degrees) { + this->writeOp(kRotate_DrawOp); + fWriter.writeScalar(degrees); + } + return this->INHERITED::rotate(degrees); +} + +bool SkGPipeCanvas::skew(SkScalar sx, SkScalar sy) { + if (sx || sy) { + this->writeOp(kSkew_DrawOp); + fWriter.writeScalar(sx); + fWriter.writeScalar(sy); + } + return this->INHERITED::skew(sx, sy); +} + +bool SkGPipeCanvas::concat(const SkMatrix& matrix) { + if (!matrix.isIdentity()) { + this->writeOp(kConcat_DrawOp); + writeMatrix(&fWriter, matrix); + } + return this->INHERITED::concat(matrix); +} + +void SkGPipeCanvas::setMatrix(const SkMatrix& matrix) { + this->writeOp(kSetMatrix_DrawOp); + writeMatrix(&fWriter, matrix); + this->INHERITED::setMatrix(matrix); +} + +bool SkGPipeCanvas::clipRect(const SkRect& rect, SkRegion::Op rgnOp) { + this->writeOp(kClipRect_DrawOp, 0, rgnOp); + fWriter.writeRect(rect); + return this->INHERITED::clipRect(rect, rgnOp); +} + +bool SkGPipeCanvas::clipPath(const SkPath& path, SkRegion::Op rgnOp) { + this->writeOp(kClipPath_DrawOp, 0, rgnOp); + path.flatten(fWriter); + // we just pass on the bounds of the path + return this->INHERITED::clipRect(path.getBounds(), rgnOp); +} + +bool SkGPipeCanvas::clipRegion(const SkRegion& region, SkRegion::Op rgnOp) { + this->writeOp(kClipRegion_DrawOp, 0, rgnOp); + writeRegion(&fWriter, region); + return this->INHERITED::clipRegion(region, rgnOp); +} + +/////////////////////////////////////////////////////////////////////////////// + +void SkGPipeCanvas::clear(SkColor color) { + unsigned flags = 0; + if (color) { + flags |= kClear_HasColor_DrawOpFlag; + } + this->writeOp(kDrawClear_DrawOp, flags, 0); + if (color) { + fWriter.write32(color); + } +} + +void SkGPipeCanvas::drawPaint(const SkPaint& paint) { + unsigned paintIndex = this->writePaint(paint); + this->writeOp(kDrawPaint_DrawOp, 0, paintIndex); +} + +void SkGPipeCanvas::drawPoints(PointMode mode, size_t count, + const SkPoint pts[], const SkPaint& paint) { + if (count) { + unsigned paintIndex = this->writePaint(paint); + this->writeOp(kDrawPoints_DrawOp, mode, paintIndex); + fWriter.write32(count); + fWriter.write(pts, count * sizeof(SkPoint)); + } +} + +void SkGPipeCanvas::drawRect(const SkRect& rect, const SkPaint& paint) { + unsigned paintIndex = this->writePaint(paint); + this->writeOp(kDrawRect_DrawOp, 0, paintIndex); + fWriter.writeRect(rect); +} + +void SkGPipeCanvas::drawPath(const SkPath& path, const SkPaint& paint) { + unsigned paintIndex = this->writePaint(paint); + this->writeOp(kDrawPath_DrawOp, 0, paintIndex); + path.flatten(fWriter); +} + +void SkGPipeCanvas::drawBitmap(const SkBitmap&, SkScalar left, SkScalar top, + const SkPaint*) { + UNIMPLEMENTED +} + +void SkGPipeCanvas::drawBitmapRect(const SkBitmap&, const SkIRect* src, + const SkRect& dst, const SkPaint*) { + UNIMPLEMENTED +} + +void SkGPipeCanvas::drawBitmapMatrix(const SkBitmap&, const SkMatrix&, + const SkPaint*) { + UNIMPLEMENTED +} + +void SkGPipeCanvas::drawSprite(const SkBitmap&, int left, int top, + const SkPaint*) { + UNIMPLEMENTED +} + +void SkGPipeCanvas::drawText(const void* text, size_t byteLength, SkScalar x, + SkScalar y, const SkPaint& paint) { + if (byteLength) { + unsigned paintIndex = this->writePaint(paint); + this->writeOp(kDrawText_DrawOp, 0, paintIndex); + fWriter.write32(byteLength); + fWriter.writePad(text, byteLength); + fWriter.writeScalar(x); + fWriter.writeScalar(y); + } +} + +void SkGPipeCanvas::drawPosText(const void* text, size_t byteLength, + const SkPoint pos[], const SkPaint& paint) { + if (byteLength) { + unsigned paintIndex = this->writePaint(paint); + this->writeOp(kDrawPosText_DrawOp, 0, paintIndex); + fWriter.write32(byteLength); + fWriter.writePad(text, byteLength); + int count = paint.textToGlyphs(text, byteLength, NULL); + fWriter.write32(count); + fWriter.write(pos, count * sizeof(SkPoint)); + } +} + +void SkGPipeCanvas::drawPosTextH(const void* text, size_t byteLength, + const SkScalar xpos[], SkScalar constY, + const SkPaint& paint) { + if (byteLength) { + unsigned paintIndex = this->writePaint(paint); + this->writeOp(kDrawPosTextH_DrawOp, 0, paintIndex); + fWriter.write32(byteLength); + fWriter.writePad(text, byteLength); + int count = paint.textToGlyphs(text, byteLength, NULL); + fWriter.write32(count); + fWriter.write(xpos, count * sizeof(SkScalar)); + fWriter.writeScalar(constY); + } +} + +void SkGPipeCanvas::drawTextOnPath(const void* text, size_t byteLength, + const SkPath& path, const SkMatrix* matrix, + const SkPaint& paint) { + if (byteLength) { + unsigned flags = 0; + if (matrix) { + flags |= kDrawTextOnPath_HasMatrix_DrawOpFlag; + } + unsigned paintIndex = this->writePaint(paint); + this->writeOp(kDrawTextOnPath_DrawOp, flags, paintIndex); + + fWriter.write32(byteLength); + fWriter.writePad(text, byteLength); + + path.flatten(fWriter); + if (matrix) { + writeMatrix(&fWriter, *matrix); + } + } +} + +void SkGPipeCanvas::drawPicture(SkPicture& picture) { + UNIMPLEMENTED +} + +void SkGPipeCanvas::drawShape(SkShape* shape) { + UNIMPLEMENTED +} + +void SkGPipeCanvas::drawVertices(VertexMode mode, int vertexCount, + const SkPoint vertices[], const SkPoint texs[], + const SkColor colors[], SkXfermode*, + const uint16_t indices[], int indexCount, + const SkPaint& paint) { + if (0 == vertexCount) { + return; + } + + unsigned paintIndex = this->writePaint(paint); + unsigned flags = 0; + if (texs) { + flags |= kDrawVertices_HasTexs_DrawOpFlag; + } + if (colors) { + flags |= kDrawVertices_HasColors_DrawOpFlag; + } + if (indices && indexCount > 0) { + flags |= kDrawVertices_HasIndices_DrawOpFlag; + } + + this->writeOp(kDrawVertices_DrawOp, flags, paintIndex); + fWriter.write32(mode); + fWriter.write32(vertexCount); + fWriter.write(vertices, vertexCount * sizeof(SkPoint)); + if (texs) { + fWriter.write(texs, vertexCount * sizeof(SkPoint)); + } + if (colors) { + fWriter.write(colors, vertexCount * sizeof(SkColor)); + } + + // TODO: flatten xfermode + + if (indices && indexCount > 0) { + fWriter.write32(indexCount); + fWriter.writePad(indices, indexCount * sizeof(uint16_t)); + } +} + +void SkGPipeCanvas::drawData(const void* data, size_t size) { + if (size) { + unsigned data = 0; + if (size < (1 << DRAWOPS_DATA_BITS)) { + data = (unsigned)size; + } + this->writeOp(kDrawData_DrawOp, 0, data); + if (0 == data) { + fWriter.write32(size); + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +template uint32_t castToU32(T value) { + union { + T fSrc; + uint32_t fDst; + } data; + data.fSrc = value; + return data.fDst; +} + +unsigned SkGPipeCanvas::writePaint(const SkPaint& paint) { + const SkPaint& base = *fPaints[0]; + uint32_t storage[32]; + uint32_t* ptr = storage; + uint32_t* last = NULL; + + if (base.getFlags() != paint.getFlags()) { + last = ptr; + *ptr++ = PaintOp_packOpData(kFlags_PaintOp, paint.getFlags()); + } + if (base.getColor() != paint.getColor()) { + last = ptr; + *ptr++ = PaintOp_packOp(kColor_PaintOp); + *ptr++ = paint.getColor(); + } + if (base.getStyle() != paint.getStyle()) { + last = ptr; + *ptr++ = PaintOp_packOpData(kStyle_PaintOp, paint.getStyle()); + } + if (base.getStrokeJoin() != paint.getStrokeJoin()) { + last = ptr; + *ptr++ = PaintOp_packOpData(kJoin_PaintOp, paint.getStrokeJoin()); + } + if (base.getStrokeCap() != paint.getStrokeCap()) { + last = ptr; + *ptr++ = PaintOp_packOpData(kCap_PaintOp, paint.getStrokeCap()); + } + if (base.getStrokeWidth() != paint.getStrokeWidth()) { + last = ptr; + *ptr++ = PaintOp_packOp(kWidth_PaintOp); + *ptr++ = castToU32(paint.getStrokeWidth()); + } + if (base.getStrokeMiter() != paint.getStrokeMiter()) { + last = ptr; + *ptr++ = PaintOp_packOp(kMiter_PaintOp); + *ptr++ = castToU32(paint.getStrokeMiter()); + } + if (base.getTextEncoding() != paint.getTextEncoding()) { + last = ptr; + *ptr++ = PaintOp_packOpData(kEncoding_PaintOp, paint.getTextEncoding()); + } + if (base.getHinting() != paint.getHinting()) { + last = ptr; + *ptr++ = PaintOp_packOpData(kHinting_PaintOp, paint.getHinting()); + } + if (base.getTextAlign() != paint.getTextAlign()) { + last = ptr; + *ptr++ = PaintOp_packOpData(kAlign_PaintOp, paint.getTextAlign()); + } + if (base.getTextSize() != paint.getTextSize()) { + last = ptr; + *ptr++ = PaintOp_packOp(kTextSize_PaintOp); + *ptr++ = castToU32(paint.getTextSize()); + } + if (base.getTextScaleX() != paint.getTextScaleX()) { + last = ptr; + *ptr++ = PaintOp_packOp(kTextScaleX_PaintOp); + *ptr++ = castToU32(paint.getTextScaleX()); + } + if (base.getTextSkewX() != paint.getTextSkewX()) { + last = ptr; + *ptr++ = PaintOp_packOp(kTextSkewX_PaintOp); + *ptr++ = castToU32(paint.getTextSkewX()); + } + *fPaints[0] = paint; + + if (ptr > storage) { + this->writeOp(kPaintOp_DrawOp, 0, 0); + size_t size = (char*)ptr - (char*)storage; + *last |= kLastOp_PaintOpFlag << PAINTOPS_DATA_BITS; + fWriter.write(storage, (char*)ptr - (char*)storage); + for (size_t i = 0; i < size/4; i++) { + SkDebugf("[%d] %08X\n", i, storage[i]); + } + } + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +#include "SkGPipe.h" + +#define MIN_WRITE_BLOCK_SIZE (4 * 1024) + +SkGPipeWriter::SkGPipeWriter() : fWriter(MIN_WRITE_BLOCK_SIZE) { + fCanvas = NULL; +} + +SkGPipeWriter::~SkGPipeWriter() { + SkSafeUnref(fCanvas); +} + +SkCanvas* SkGPipeWriter::startRecording() { + if (NULL == fCanvas) { + fCanvas = SkNEW_ARGS(SkGPipeCanvas, (&fWriter)); + } + return fCanvas; +} + +void SkGPipeWriter::endRecording() { + if (fCanvas) { + fCanvas->finish(); + fCanvas->unref(); + fCanvas = NULL; + } +} + +size_t SkGPipeWriter::flatten(void* buffer) { + if (buffer) { + fWriter.flatten(buffer); + } + return fWriter.size(); +} +