SkShader::Context* SkBitmapProcShader::MakeContext(const SkShader& shader,
                                                   TileMode tmx, TileMode tmy,
                                                   const SkBitmapProvider& provider,
                                                   const ContextRec& rec, void* storage) {
    SkMatrix totalInverse;
    // Do this first, so we know the matrix can be inverted.
    if (!shader.computeTotalInverse(rec, &totalInverse)) {
        return nullptr;
    }

    // Decide if we can/want to use the new linear pipeline
    bool useLinearPipeline = choose_linear_pipeline(rec, provider.info());

    if (useLinearPipeline) {
        void* infoStorage = (char*)storage + sizeof(LinearPipelineContext);
        SkBitmapProcInfo* info = new (infoStorage) SkBitmapProcInfo(provider, tmx, tmy);
        if (!info->init(totalInverse, *rec.fPaint)) {
            info->~SkBitmapProcInfo();
            return nullptr;
        }

        return new (storage) LinearPipelineContext(shader, rec, info);
    } else {
        void* stateStorage = (char*)storage + sizeof(BitmapProcShaderContext);
        SkBitmapProcState* state = new (stateStorage) SkBitmapProcState(provider, tmx, tmy);
        if (!state->setup(totalInverse, *rec.fPaint)) {
            state->~SkBitmapProcState();
            return nullptr;
        }
        return new (storage) BitmapProcShaderContext(shader, rec, state);
    }
}
SkShader::Context* SkBitmapProcShader::MakeContext(const SkShader& shader,
                                                   TileMode tmx, TileMode tmy,
                                                   const SkBitmapProvider& provider,
                                                   const ContextRec& rec, void* storage) {
    SkMatrix totalInverse;
    // Do this first, so we know the matrix can be inverted.
    if (!shader.computeTotalInverse(rec, &totalInverse)) {
        return nullptr;
    }

    // Decide if we can/want to use the new linear pipeline
    bool useLinearPipeline = choose_linear_pipeline(rec, provider.info());

    //
    // For now, only enable locally since we are hitting some crashers on the test bots
    //
    //useLinearPipeline = false;

    if (useLinearPipeline) {
        void* infoStorage = (char*)storage + sizeof(LinearPipelineContext);
        SkBitmapProcInfo* info = new (infoStorage) SkBitmapProcInfo(provider, tmx, tmy);
        if (!info->init(totalInverse, *rec.fPaint)) {
            info->~SkBitmapProcInfo();
            return nullptr;
        }
        if (info->fPixmap.colorType() != kRGBA_8888_SkColorType
            && info->fPixmap.colorType() != kBGRA_8888_SkColorType
            && info->fPixmap.colorType() != kIndex_8_SkColorType) {
            return nullptr;
        }
        return new (storage) LinearPipelineContext(shader, rec, info);
    } else {
        void* stateStorage = (char*)storage + sizeof(BitmapProcShaderContext);
        SkBitmapProcState* state = new (stateStorage) SkBitmapProcState(provider, tmx, tmy);
        if (!state->setup(totalInverse, *rec.fPaint)) {
            state->~SkBitmapProcState();
            return nullptr;
        }
        return new (storage) BitmapProcShaderContext(shader, rec, state);
    }
}