blob: 43abf899c578e00dd8371c87bbf80097460d4ab6 [file] [log] [blame]
/*
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 "SkGPipe.h"
#include "SkGPipePriv.h"
#include "SkReader32.h"
#include "SkStream.h"
#include "SkTypeface.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);
SkTypeface* findTypeface(int id) const {
SkASSERT(id <= fTypefaces.count());
return id ? fTypefaces[id - 1] : NULL;
}
void addTypeface(SkReader32* reader) {
size_t size = reader->readU32();
const void* data = reader->skip(SkAlign4(size));
SkMemoryStream stream(data, size, false);
// fTypefaces takes over ownership of the typeface reference
*fTypefaces.append() = SkTypeface::Deserialize(&stream);
}
private:
SkTDArray<SkPaint*> fPaints;
SkTDArray<SkTypeface*> fTypefaces;
};
///////////////////////////////////////////////////////////////////////////////
template <typename T> const T* skip(SkReader32* reader, int count = 1) {
SkASSERT(count >= 0);
size_t size = sizeof(T) * count;
SkASSERT(SkAlign4(size) == size);
return reinterpret_cast<const T*>(reader->skip(size));
}
template <typename T> const T* skipAlign(SkReader32* reader, int count = 1) {
SkASSERT(count >= 0);
size_t size = SkAlign4(sizeof(T) * count);
return reinterpret_cast<const T*>(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<SkRect>(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<SkScalar>(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<SkScalar>(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<SkScalar>(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_unpackFlags(op32);
SkCanvas::SaveFlags saveFlags = (SkCanvas::SaveFlags)DrawOp_unpackData(op32);
const SkRect* bounds = NULL;
if (flags & kSaveLayer_HasBounds_DrawOpFlag) {
bounds = skip<SkRect>(reader);
}
const SkPaint* paint = NULL;
if (flags & kSaveLayer_HasPaint_DrawOpFlag) {
paint = &state->getPaint(reader->readU32());
}
canvas->saveLayer(bounds, paint, saveFlags);
}
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<SkPoint>(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<SkRect>(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<SkPoint>(reader, vertexCount);
const SkPoint* texs = NULL;
if (flags & kDrawVertices_HasTexs_DrawOpFlag) {
texs = skip<SkPoint>(reader, vertexCount);
}
const SkColor* colors = NULL;
if (flags & kDrawVertices_HasColors_DrawOpFlag) {
colors = skip<SkColor>(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<uint16_t>(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<SkScalar>(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<SkPoint>(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<SkScalar>(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;
case kTypeface_PaintOp: p->setTypeface(state->findTypeface(data)); 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 defTypeface_rp(SkCanvas*, SkReader32* reader, uint32_t,
SkGPipeState* state) {
state->addTypeface(reader);
}
///////////////////////////////////////////////////////////////////////////////
static void skip_rp(SkCanvas*, SkReader32* reader, uint32_t op32, SkGPipeState*) {
size_t bytes = DrawOp_unpackData(op32);
(void)reader->skip(bytes);
}
static void done_rp(SkCanvas*, SkReader32*, uint32_t, SkGPipeState*) {}
typedef void (*ReadProc)(SkCanvas*, SkReader32*, uint32_t op32, SkGPipeState*);
static const ReadProc gReadTable[] = {
skip_rp,
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,
defTypeface_rp,
done_rp
};
///////////////////////////////////////////////////////////////////////////////
SkGPipeState::SkGPipeState() {
// start out with one paint in default state
*fPaints.append() = SkNEW(SkPaint);
}
SkGPipeState::~SkGPipeState() {
fTypefaces.unrefAll();
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;
}