<commit_before>
/*
 * Copyright 2011 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 "SkPaint.h"
#include "SkGPipe.h"
#include "SkGPipePriv.h"
#include "SkReader32.h"
#include "SkStream.h"

#include "SkColorFilter.h"
#include "SkDrawLooper.h"
#include "SkMaskFilter.h"
#include "SkOrderedReadBuffer.h"
#include "SkPathEffect.h"
#include "SkRasterizer.h"
#include "SkShader.h"
#include "SkTypeface.h"
#include "SkXfermode.h"

static void set_paintflat(SkPaint* paint, SkFlattenable* obj, unsigned paintFlat) {
    SkASSERT(paintFlat < kCount_PaintFlats);
    switch (paintFlat) {
        case kColorFilter_PaintFlat:
            paint->setColorFilter((SkColorFilter*)obj);
            break;
        case kDrawLooper_PaintFlat:
            paint->setLooper((SkDrawLooper*)obj);
            break;
        case kMaskFilter_PaintFlat:
            paint->setMaskFilter((SkMaskFilter*)obj);
            break;
        case kPathEffect_PaintFlat:
            paint->setPathEffect((SkPathEffect*)obj);
            break;
        case kRasterizer_PaintFlat:
            paint->setRasterizer((SkRasterizer*)obj);
            break;
        case kShader_PaintFlat:
            paint->setShader((SkShader*)obj);
            break;
        case kImageFilter_PaintFlat:
            paint->setImageFilter((SkImageFilter*)obj);
            break;
        case kXfermode_PaintFlat:
            paint->setXfermode((SkXfermode*)obj);
            break;
        default:
            SkDEBUGFAIL("never gets here");
    }
}

template <typename T> class SkRefCntTDArray : public SkTDArray<T> {
public:
    ~SkRefCntTDArray() { this->unrefAll(); }
};

class SkGPipeState {
public:
    SkGPipeState();
    ~SkGPipeState();

    void setReader(SkFlattenableReadBuffer* reader) {
        fReader = reader;
        fReader->setFactoryArray(&fFactoryArray);
    }

    const SkPaint& paint() const { return fPaint; }
    SkPaint* editPaint() { return &fPaint; }
    
    SkFlattenable* getFlat(unsigned index) const {
        if (0 == index) {
            return NULL;
        }
        return fFlatArray[index - 1];
    }

    void defFlattenable(PaintFlats pf, int index) {
        SkASSERT(index == fFlatArray.count() + 1);
        SkFlattenable* obj = fReader->readFlattenable();
        *fFlatArray.append() = obj;
    }

    void addBitmap(int index) {
        SkASSERT(fBitmaps.count() == index);
        SkBitmap* bm = new SkBitmap();
        size_t size = fReader->readU32();
        SkOrderedReadBuffer readBuffer(fReader->skip(size), size);
        bm->unflatten(readBuffer);
        *fBitmaps.append() = bm;
    }

    SkBitmap* getBitmap(unsigned index) {
        return fBitmaps[index];
    }

    void addTypeface() {
        size_t size = fReader->readU32();
        const void* data = fReader->skip(SkAlign4(size));
        SkMemoryStream stream(data, size, false);
        *fTypefaces.append() = SkTypeface::Deserialize(&stream);
    }    
    void setTypeface(SkPaint* paint, unsigned id) {
        paint->setTypeface(id ? fTypefaces[id - 1] : NULL);
    }
    
    SkFlattenableReadBuffer* fReader;

private:
    SkPaint                   fPaint;
    SkTDArray<SkFlattenable*> fFlatArray;
    SkTDArray<SkTypeface*>    fTypefaces;
    SkTDArray<SkFlattenable::Factory> fFactoryArray;
    SkTDArray<SkBitmap*>      fBitmaps;
};

///////////////////////////////////////////////////////////////////////////////

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 clipPath_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
                        SkGPipeState* state) {
    SkPath path;
    path.unflatten(*reader);
    canvas->clipPath(path, (SkRegion::Op)DrawOp_unpackData(op32),
                     reader->readBool());
}

static void clipRegion_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
                          SkGPipeState* state) {
    SkRegion rgn;
    reader->readRegion(&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), reader->readBool());
}

///////////////////////////////////////////////////////////////////////////////

static void setMatrix_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
                      SkGPipeState* state) {
    SkMatrix matrix;
    reader->readMatrix(&matrix);
    canvas->setMatrix(matrix);
}

static void concat_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
                      SkGPipeState* state) {
    SkMatrix matrix;
    reader->readMatrix(&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->paint();
    }
    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->paint());
}

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->paint());
}

static void drawRect_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
                        SkGPipeState* state) {
    canvas->drawRect(*skip<SkRect>(reader), state->paint());
}

static void drawPath_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
                        SkGPipeState* state) {
    SkPath path;
    path.unflatten(*reader);
    canvas->drawPath(path, state->paint());
}

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->paint());
}

///////////////////////////////////////////////////////////////////////////////

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->paint());
}

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->paint());
}

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->paint());
}

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) {
        reader->readMatrix(&matrixStorage);
        matrix = &matrixStorage;
    }

    canvas->drawTextOnPath(text, len, path, matrix, state->paint());
}

///////////////////////////////////////////////////////////////////////////////

static void drawBitmap_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
                          SkGPipeState* state) {
    unsigned index = DrawOp_unpackData(op32);
    SkBitmap* bm = state->getBitmap(index);
    bool hasPaint = reader->readBool();
    SkScalar left = reader->readScalar();
    SkScalar top = reader->readScalar();
    canvas->drawBitmap(*bm, left, top, hasPaint ? &state->paint() : NULL);
}

static void drawBitmapMatrix_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
                                SkGPipeState* state) {
    UNIMPLEMENTED
}

static void drawBitmapNine_rp(SkCanvas* canvas, SkReader32* reader,
                              uint32_t op32, SkGPipeState* state) {
    unsigned index = DrawOp_unpackData(op32);
    SkBitmap* bm = state->getBitmap(index);
    bool hasPaint = reader->readBool();
    SkIRect center = SkIRect::MakeLTRB(reader->readInt(), reader->readInt(),
                                       reader->readInt(), reader->readInt());
    const SkRect* dst = skip<SkRect>(reader);
    canvas->drawBitmapNine(*bm, center, *dst,
                           hasPaint ? &state->paint() : NULL);
}

static void drawBitmapRect_rp(SkCanvas* canvas, SkReader32* reader,
                              uint32_t op32, SkGPipeState* state) {
    unsigned index = DrawOp_unpackData(op32);
    SkBitmap* bm = state->getBitmap(index);
    bool hasPaint = reader->readBool();
    bool hasSrc = reader->readBool();
    SkIRect src; 
    if (hasSrc) {
        src = SkIRect::MakeLTRB(reader->readInt(), reader->readInt(),
                                reader->readInt(), reader->readInt());
    }
    const SkRect* dst = skip<SkRect>(reader);
    canvas->drawBitmapRect(*bm, hasSrc ? &src : NULL, *dst,
                           hasPaint ? &state->paint() : NULL);
}

static void drawSprite_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
                          SkGPipeState* state) {
    unsigned index = DrawOp_unpackData(op32);
    SkBitmap* bm = state->getBitmap(index);
    bool hasPaint = reader->readBool();
    canvas->drawSprite(*bm, reader->readInt(), reader->readInt(),
                       hasPaint ? &state->paint() : NULL);
}

///////////////////////////////////////////////////////////////////////////////

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);<commit_msg>Fix an issue where Pipe did not draw correctly on all platforms.<commit_after>
/*
 * Copyright 2011 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 "SkPaint.h"
#include "SkGPipe.h"
#include "SkGPipePriv.h"
#include "SkReader32.h"
#include "SkStream.h"

#include "SkColorFilter.h"
#include "SkDrawLooper.h"
#include "SkMaskFilter.h"
#include "SkOrderedReadBuffer.h"
#include "SkPathEffect.h"
#include "SkRasterizer.h"
#include "SkShader.h"
#include "SkTypeface.h"
#include "SkXfermode.h"

static void set_paintflat(SkPaint* paint, SkFlattenable* obj, unsigned paintFlat) {
    SkASSERT(paintFlat < kCount_PaintFlats);
    switch (paintFlat) {
        case kColorFilter_PaintFlat:
            paint->setColorFilter((SkColorFilter*)obj);
            break;
        case kDrawLooper_PaintFlat:
            paint->setLooper((SkDrawLooper*)obj);
            break;
        case kMaskFilter_PaintFlat:
            paint->setMaskFilter((SkMaskFilter*)obj);
            break;
        case kPathEffect_PaintFlat:
            paint->setPathEffect((SkPathEffect*)obj);
            break;
        case kRasterizer_PaintFlat:
            paint->setRasterizer((SkRasterizer*)obj);
            break;
        case kShader_PaintFlat:
            paint->setShader((SkShader*)obj);
            break;
        case kImageFilter_PaintFlat:
            paint->setImageFilter((SkImageFilter*)obj);
            break;
        case kXfermode_PaintFlat:
            paint->setXfermode((SkXfermode*)obj);
            break;
        default:
            SkDEBUGFAIL("never gets here");
    }
}

template <typename T> class SkRefCntTDArray : public SkTDArray<T> {
public:
    ~SkRefCntTDArray() { this->unrefAll(); }
};

class SkGPipeState {
public:
    SkGPipeState();
    ~SkGPipeState();

    void setReader(SkFlattenableReadBuffer* reader) {
        fReader = reader;
        fReader->setFactoryArray(&fFactoryArray);
    }

    const SkPaint& paint() const { return fPaint; }
    SkPaint* editPaint() { return &fPaint; }
    
    SkFlattenable* getFlat(unsigned index) const {
        if (0 == index) {
            return NULL;
        }
        return fFlatArray[index - 1];
    }

    void defFlattenable(PaintFlats pf, int index) {
        SkASSERT(index == fFlatArray.count() + 1);
        SkFlattenable* obj = fReader->readFlattenable();
        *fFlatArray.append() = obj;
    }

    void addBitmap(int index) {
        SkASSERT(fBitmaps.count() == index);
        SkBitmap* bm = new SkBitmap();
        size_t size = fReader->readU32();
        SkOrderedReadBuffer readBuffer(fReader->skip(size), size);
        bm->unflatten(readBuffer);
        *fBitmaps.append() = bm;
    }

    SkBitmap* getBitmap(unsigned index) {
        return fBitmaps[index];
    }

    void addTypeface() {
        size_t size = fReader->readU32();
        const void* data = fReader->skip(SkAlign4(size));
        SkMemoryStream stream(data, size, false);
        *fTypefaces.append() = SkTypeface::Deserialize(&stream);
    }    
    void setTypeface(SkPaint* paint, unsigned id) {
        paint->setTypeface(id ? fTypefaces[id - 1] : NULL);
    }
    
    SkFlattenableReadBuffer* fReader;

private:
    SkPaint                   fPaint;
    SkTDArray<SkFlattenable*> fFlatArray;
    SkTDArray<SkTypeface*>    fTypefaces;
    SkTDArray<SkFlattenable::Factory> fFactoryArray;
    SkTDArray<SkBitmap*>      fBitmaps;
};

///////////////////////////////////////////////////////////////////////////////

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 clipPath_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
                        SkGPipeState* state) {
    SkPath path;
    path.unflatten(*reader);
    canvas->clipPath(path, (SkRegion::Op)DrawOp_unpackData(op32),
                     reader->readBool());
}

static void clipRegion_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
                          SkGPipeState* state) {
    SkRegion rgn;
    reader->readRegion(&rgn);
    canvas->clipRegion(rgn, (SkRegion::Op)DrawOp_unpackData(op32));
}

static void clipRect_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
                        SkGPipeState* state) {
    const SkRect* rect = skip<SkRect>(reader);
    bool doAA = reader->readBool();
    canvas->clipRect(*rect, (SkRegion::Op)DrawOp_unpackData(op32), doAA);
}

///////////////////////////////////////////////////////////////////////////////

static void setMatrix_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
                      SkGPipeState* state) {
    SkMatrix matrix;
    reader->readMatrix(&matrix);
    canvas->setMatrix(matrix);
}

static void concat_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
                      SkGPipeState* state) {
    SkMatrix matrix;
    reader->readMatrix(&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->paint();
    }
    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->paint());
}

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->paint());
}

static void drawRect_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
                        SkGPipeState* state) {
    canvas->drawRect(*skip<SkRect>(reader), state->paint());
}

static void drawPath_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
                        SkGPipeState* state) {
    SkPath path;
    path.unflatten(*reader);
    canvas->drawPath(path, state->paint());
}

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->paint());
}

///////////////////////////////////////////////////////////////////////////////

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->paint());
}

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->paint());
}

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->paint());
}

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) {
        reader->readMatrix(&matrixStorage);
        matrix = &matrixStorage;
    }

    canvas->drawTextOnPath(text, len, path, matrix, state->paint());
}

///////////////////////////////////////////////////////////////////////////////

static void drawBitmap_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
                          SkGPipeState* state) {
    unsigned index = DrawOp_unpackData(op32);
    SkBitmap* bm = state->getBitmap(index);
    bool hasPaint = reader->readBool();
    SkScalar left = reader->readScalar();
    SkScalar top = reader->readScalar();
    canvas->drawBitmap(*bm, left, top, hasPaint ? &state->paint() : NULL);
}

static void drawBitmapMatrix_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
                                SkGPipeState* state) {
    UNIMPLEMENTED
}

static void drawBitmapNine_rp(SkCanvas* canvas, SkReader32* reader,
                              uint32_t op32, SkGPipeState* state) {
    unsigned index = DrawOp_unpackData(op32);
    SkBitmap* bm = state->getBitmap(index);
    bool hasPaint = reader->readBool();
    const SkIRect* center = skip<SkIRect>(reader);
    const SkRect* dst = skip<SkRect>(reader);
    canvas->drawBitmapNine(*bm, *center, *dst,
                           hasPaint ? &state->paint() : NULL);
}

static void drawBitmapRect_rp(SkCanvas* canvas, SkReader32* reader,
                              uint32_t op32, SkGPipeState* state) {
    unsigned index = DrawOp_unpackData(op32);
    SkBitmap* bm = state->getBitmap(index);
    bool hasPaint = reader->readBool();
    bool hasSrc = reader->readBool();
    const SkIRect* src;
    if (hasSrc) {
        src = skip<SkIRect>(reader);
    } else {
        src = NULL;
    }
    const SkRect* dst = skip<SkRect>(reader);
    canvas->drawBitmapRect(*bm, src, *dst, hasPaint ? &state->paint() : NULL);
}

static void drawSprite_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
                          SkGPipeState* state) {
    unsigned index = DrawOp_unpackData(op32);
    SkBitmap* bm = state->getBitmap(index);
    bool hasPaint = reader->readBool();
    const SkIPoint* point = skip<SkIPoint>(reader);
    canvas->drawSprite(*bm, point->fX, point->fY, hasPaint ? &state->paint() : NULL);
}

///////////////////////////////////////////////////////////////////////////////

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);
{'fraction_non_alphanumeric': 0.16438695960311836, 'fraction_numerical': 0.01920623671155209, 'mean_word_length': 2.413280116110305, 'pattern_counts': {'":': 0, '<': 60, '<?xml version=': 0, '>': 266, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6579320', 'n_tokens_mistral': 8873, 'n_tokens_neox': 8551, 'n_words': 1866}