Exemplo n.º 1
0
    void onDraw(SkCanvas* canvas) override {

        static const struct {
            SkFilterQuality fQuality;
            const char* fName;
        } kQualities[] = {
            {kNone_SkFilterQuality, "none"},
            {kLow_SkFilterQuality, "low"},
            {kMedium_SkFilterQuality, "medium"},
            {kHigh_SkFilterQuality, "high"},
        };

        for (size_t q = 0; q < SK_ARRAY_COUNT(kQualities); ++q) {
            SkPaint paint;
            sk_tool_utils::set_portable_typeface(&paint);
            paint.setFilterQuality(kQualities[q].fQuality);
            SkPaint bmpPaint(paint);
            SkMatrix lm = SkMatrix::I();
            lm.setScaleX(2.5);
            lm.setTranslateX(423);
            lm.setTranslateY(330);

            static const SkShader::TileMode kTM = SkShader::kRepeat_TileMode;
            bmpPaint.setShader(SkShader::MakeBitmapShader(fBmp, kTM, kTM, &lm));
            SkRect rect = SkRect::MakeLTRB(20, 60, 220, 210);
            canvas->drawRect(rect, bmpPaint);
            paint.setAntiAlias(true);
            canvas->drawText(kQualities[q].fName, strlen(kQualities[q].fName), 20, 40, paint);
            canvas->translate(250, 0);
        }
    }
sk_sp<GrFragmentProcessor> SkPerlinNoiseShader::asFragmentProcessor(const AsFPArgs& args) const {
    SkASSERT(args.fContext);

    SkMatrix localMatrix = this->getLocalMatrix();
    if (args.fLocalMatrix) {
        localMatrix.preConcat(*args.fLocalMatrix);
    }

    SkMatrix matrix = *args.fViewMatrix;
    matrix.preConcat(localMatrix);

    if (0 == fNumOctaves) {
        if (kFractalNoise_Type == fType) {
            // Extract the incoming alpha and emit rgba = (a/4, a/4, a/4, a/2)
            // TODO: Either treat the output of this shader as sRGB or allow client to specify a
            // color space of the noise. Either way, this case (and the GLSL) need to convert to
            // the destination.
            sk_sp<GrFragmentProcessor> inner(
                GrConstColorProcessor::Make(GrColor4f::FromGrColor(0x80404040),
                                            GrConstColorProcessor::kModulateRGBA_InputMode));
            return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner));
        }
        // Emit zero.
        return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
                                           GrConstColorProcessor::kIgnore_InputMode);
    }

    // Either we don't stitch tiles, either we have a valid tile size
    SkASSERT(!fStitchTiles || !fTileSize.isEmpty());

    SkPerlinNoiseShader::PaintingData* paintingData =
            new PaintingData(fTileSize, fSeed, fBaseFrequencyX, fBaseFrequencyY, matrix);
    sk_sp<GrTextureProxy> permutationsProxy(GrMakeCachedBitmapProxy(
                                                            args.fContext->resourceProvider(),
                                                            paintingData->getPermutationsBitmap()));
    sk_sp<GrTextureProxy> noiseProxy(GrMakeCachedBitmapProxy(args.fContext->resourceProvider(),
                                                             paintingData->getNoiseBitmap()));

    SkMatrix m = *args.fViewMatrix;
    m.setTranslateX(-localMatrix.getTranslateX() + SK_Scalar1);
    m.setTranslateY(-localMatrix.getTranslateY() + SK_Scalar1);
    if (permutationsProxy && noiseProxy) {
        sk_sp<GrFragmentProcessor> inner(
            GrPerlinNoiseEffect::Make(args.fContext->resourceProvider(),
                                      fType,
                                      fNumOctaves,
                                      fStitchTiles,
                                      paintingData,
                                      std::move(permutationsProxy),
                                      std::move(noiseProxy),
                                      m));
        return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner));
    }
    delete paintingData;
    return nullptr;
}
Exemplo n.º 3
0
const GrFragmentProcessor* SkPerlinNoiseShader::asFragmentProcessor(
                                                    GrContext* context,
                                                    const SkMatrix& viewM,
                                                    const SkMatrix* externalLocalMatrix,
                                                    SkFilterQuality) const {
    SkASSERT(context);

    SkMatrix localMatrix = this->getLocalMatrix();
    if (externalLocalMatrix) {
        localMatrix.preConcat(*externalLocalMatrix);
    }

    SkMatrix matrix = viewM;
    matrix.preConcat(localMatrix);

    if (0 == fNumOctaves) {
        if (kFractalNoise_Type == fType) {
            // Extract the incoming alpha and emit rgba = (a/4, a/4, a/4, a/2)
            SkAutoTUnref<const GrFragmentProcessor> inner(
                GrConstColorProcessor::Create(0x80404040,
                                              GrConstColorProcessor::kModulateRGBA_InputMode));
            return GrFragmentProcessor::MulOutputByInputAlpha(inner);
        }
        // Emit zero.
        return GrConstColorProcessor::Create(0x0, GrConstColorProcessor::kIgnore_InputMode);
    }

    // Either we don't stitch tiles, either we have a valid tile size
    SkASSERT(!fStitchTiles || !fTileSize.isEmpty());

    SkPerlinNoiseShader::PaintingData* paintingData =
            new PaintingData(fTileSize, fSeed, fBaseFrequencyX, fBaseFrequencyY, matrix);
    SkAutoTUnref<GrTexture> permutationsTexture(
        GrRefCachedBitmapTexture(context, paintingData->getPermutationsBitmap(),
                                 GrTextureParams::ClampNoFilter()));
    SkAutoTUnref<GrTexture> noiseTexture(
        GrRefCachedBitmapTexture(context, paintingData->getNoiseBitmap(),
                                 GrTextureParams::ClampNoFilter()));

    SkMatrix m = viewM;
    m.setTranslateX(-localMatrix.getTranslateX() + SK_Scalar1);
    m.setTranslateY(-localMatrix.getTranslateY() + SK_Scalar1);
    if ((permutationsTexture) && (noiseTexture)) {
        SkAutoTUnref<GrFragmentProcessor> inner(
            GrPerlinNoiseEffect::Create(fType,
                                        fNumOctaves,
                                        fStitchTiles,
                                        paintingData,
                                        permutationsTexture, noiseTexture,
                                        m));
        return GrFragmentProcessor::MulOutputByInputAlpha(inner);
    }
    delete paintingData;
    return nullptr;
}
AffineTransform::operator SkMatrix() const
{
    SkMatrix result;

    result.setScaleX(WebCoreDoubleToSkScalar(a()));
    result.setSkewX(WebCoreDoubleToSkScalar(c()));
    result.setTranslateX(WebCoreDoubleToSkScalar(e()));

    result.setScaleY(WebCoreDoubleToSkScalar(d()));
    result.setSkewY(WebCoreDoubleToSkScalar(b()));
    result.setTranslateY(WebCoreDoubleToSkScalar(f()));

    // FIXME: Set perspective properly.
    result.setPerspX(0);
    result.setPerspY(0);
    result.set(SkMatrix::kMPersp2, SK_Scalar1);

    return result;
}
Exemplo n.º 5
0
SkMatrix affineTransformToSkMatrix(const AffineTransform& source)
{
    SkMatrix result;

    result.setScaleX(WebCoreDoubleToSkScalar(source.a()));
    result.setSkewX(WebCoreDoubleToSkScalar(source.c()));
    result.setTranslateX(WebCoreDoubleToSkScalar(source.e()));

    result.setScaleY(WebCoreDoubleToSkScalar(source.d()));
    result.setSkewY(WebCoreDoubleToSkScalar(source.b()));
    result.setTranslateY(WebCoreDoubleToSkScalar(source.f()));

    // FIXME: Set perspective properly.
    result.setPerspX(0);
    result.setPerspY(0);
    result.set(SkMatrix::kMPersp2, SK_Scalar1);

    return result;
}
SkLinearBitmapPipeline::SkLinearBitmapPipeline(
    const SkMatrix& inverse,
    SkFilterQuality filterQuality,
    SkShader::TileMode xTile, SkShader::TileMode yTile,
    SkColor paintColor,
    const SkPixmap& srcPixmap)
{
    SkISize dimensions = srcPixmap.info().dimensions();
    const SkImageInfo& srcImageInfo = srcPixmap.info();

    SkMatrix adjustedInverse = inverse;
    if (filterQuality == kNone_SkFilterQuality) {
        if (inverse.getScaleX() >= 0.0f) {
            adjustedInverse.setTranslateX(
                nextafterf(inverse.getTranslateX(), std::floor(inverse.getTranslateX())));
        }
        if (inverse.getScaleY() >= 0.0f) {
            adjustedInverse.setTranslateY(
                nextafterf(inverse.getTranslateY(), std::floor(inverse.getTranslateY())));
        }
    }

    SkScalar dx = adjustedInverse.getScaleX();

    // If it is an index 8 color type, the sampler converts to unpremul for better fidelity.
    SkAlphaType alphaType = srcImageInfo.alphaType();
    if (srcPixmap.colorType() == kIndex_8_SkColorType) {
        alphaType = kUnpremul_SkAlphaType;
    }

    float postAlpha = SkColorGetA(paintColor) * (1.0f / 255.0f);
    // As the stages are built, the chooser function may skip a stage. For example, with the
    // identity matrix, the matrix stage is skipped, and the tilerStage is the first stage.
    auto blenderStage = choose_blender_for_shading(alphaType, postAlpha, &fBlenderStage);
    auto samplerStage = choose_pixel_sampler(
        blenderStage, filterQuality, xTile, yTile,
        srcPixmap, paintColor, &fSampleStage, &fAccessor);
    auto tilerStage   = choose_tiler(samplerStage, dimensions, xTile, yTile,
                                     filterQuality, dx, &fTileStage);
    fFirstStage       = choose_matrix(tilerStage, adjustedInverse, &fMatrixStage);
    fLastStage        = blenderStage;
}
Exemplo n.º 7
0
    void drawAll(SkCanvas* canvas, SkScalar scaleX) const {
        constexpr struct {
            SkFilterQuality fQuality;
            const char* fName;
        } kQualities[] = {
            {kNone_SkFilterQuality, "none"},
            {kLow_SkFilterQuality, "low"},
            {kMedium_SkFilterQuality, "medium"},
            {kHigh_SkFilterQuality, "high"},
        };

        SkRect rect = SkRect::MakeLTRB(20, 60, 220, 210);
        SkMatrix lm = SkMatrix::I();
        lm.setScaleX(scaleX);
        lm.setTranslateX(423);
        lm.setTranslateY(330);

        SkPaint textPaint;
        textPaint.setAntiAlias(true);

        SkPaint bmpPaint(textPaint);

        SkFont font(ToolUtils::create_portable_typeface());

        SkAutoCanvasRestore acr(canvas, true);

        for (size_t q = 0; q < SK_ARRAY_COUNT(kQualities); ++q) {
            constexpr SkTileMode kTM = SkTileMode::kRepeat;
            bmpPaint.setShader(fBmp.makeShader(kTM, kTM, &lm));
            bmpPaint.setFilterQuality(kQualities[q].fQuality);
            canvas->drawRect(rect, bmpPaint);
            canvas->drawString(kQualities[q].fName, 20, 40, font, textPaint);
            canvas->translate(250, 0);
        }

    }
Exemplo n.º 8
0
void
DrawTargetSkia::DrawSurfaceWithShadow(SourceSurface *aSurface,
                                      const Point &aDest,
                                      const Color &aColor,
                                      const Point &aOffset,
                                      Float aSigma,
                                      CompositionOp aOperator)
{
    MarkChanged();
    mCanvas->save(SkCanvas::kMatrix_SaveFlag);
    mCanvas->resetMatrix();

    uint32_t blurFlags = SkBlurMaskFilter::kHighQuality_BlurFlag |
                         SkBlurMaskFilter::kIgnoreTransform_BlurFlag;
    const SkBitmap& bitmap = static_cast<SourceSurfaceSkia*>(aSurface)->GetBitmap();
    SkShader* shader = SkShader::CreateBitmapShader(bitmap, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
    SkMatrix matrix;
    matrix.reset();
    matrix.setTranslateX(SkFloatToScalar(aDest.x));
    matrix.setTranslateY(SkFloatToScalar(aDest.y));
    shader->setLocalMatrix(matrix);
    SkLayerDrawLooper* dl = new SkLayerDrawLooper;
    SkLayerDrawLooper::LayerInfo info;
    info.fPaintBits |= SkLayerDrawLooper::kShader_Bit;
    SkPaint *layerPaint = dl->addLayer(info);
    layerPaint->setShader(shader);

    info.fPaintBits = 0;
    info.fPaintBits |= SkLayerDrawLooper::kMaskFilter_Bit;
    info.fPaintBits |= SkLayerDrawLooper::kColorFilter_Bit;
    info.fColorMode = SkXfermode::kDst_Mode;
    info.fOffset.set(SkFloatToScalar(aOffset.x), SkFloatToScalar(aOffset.y));
    info.fPostTranslate = true;

    SkMaskFilter* mf = SkBlurMaskFilter::Create(aSigma, SkBlurMaskFilter::kNormal_BlurStyle, blurFlags);
    SkColor color = ColorToSkColor(aColor, 1);
    SkColorFilter* cf = SkColorFilter::CreateModeFilter(color, SkXfermode::kSrcIn_Mode);


    layerPaint = dl->addLayer(info);
    SkSafeUnref(layerPaint->setMaskFilter(mf));
    SkSafeUnref(layerPaint->setColorFilter(cf));
    layerPaint->setColor(color);

    // TODO: This is using the rasterizer to calculate an alpha mask
    // on both the shadow and normal layers. We should fix this
    // properly so it only happens for the shadow layer
    SkLayerRasterizer *raster = new SkLayerRasterizer();
    SkPaint maskPaint;
    SkSafeUnref(maskPaint.setShader(shader));
    raster->addLayer(maskPaint, 0, 0);

    SkPaint paint;
    paint.setAntiAlias(true);
    SkSafeUnref(paint.setRasterizer(raster));
    paint.setXfermodeMode(GfxOpToSkiaOp(aOperator));
    SkSafeUnref(paint.setLooper(dl));

    SkRect rect = RectToSkRect(Rect(Float(aDest.x), Float(aDest.y),
                                    Float(bitmap.width()), Float(bitmap.height())));
    mCanvas->drawRect(rect, paint);
    mCanvas->restore();
}
Exemplo n.º 9
0
SkMatrix makeMatrix() {
    SkMatrix matrix;
    matrix.reset();
    RandomSetMatrix setMatrix = (RandomSetMatrix) fRand.nextRangeU(0, kRandomSetMatrix_Last);
    if (fPrintName) {
        SkDebugf("%.*s%s\n", fPathDepth * 3, fTab, gRandomSetMatrixNames[setMatrix]);
    }
    switch (setMatrix) {
        case kSetIdentity:
            break;
        case kSetTranslateX:
            matrix.setTranslateX(makeScalar());
            break;
        case kSetTranslateY:
            matrix.setTranslateY(makeScalar());
            break;
        case kSetTranslate:
            matrix.setTranslate(makeScalar(), makeScalar());
            break;
        case kSetScaleX:
            matrix.setScaleX(makeScalar());
            break;
        case kSetScaleY:
            matrix.setScaleY(makeScalar());
            break;
        case kSetScale:
            matrix.setScale(makeScalar(), makeScalar());
            break;
        case kSetScaleTranslate:
            matrix.setScale(makeScalar(), makeScalar(), makeScalar(), makeScalar());
            break;
        case kSetSkewX:
            matrix.setSkewX(makeScalar());
            break;
        case kSetSkewY:
            matrix.setSkewY(makeScalar());
            break;
        case kSetSkew:
            matrix.setSkew(makeScalar(), makeScalar());
            break;
        case kSetSkewTranslate:
            matrix.setSkew(makeScalar(), makeScalar(), makeScalar(), makeScalar());
            break;
        case kSetRotate:
            matrix.setRotate(makeScalar());
            break;
        case kSetRotateTranslate:
            matrix.setRotate(makeScalar(), makeScalar(), makeScalar());
            break;
        case kSetPerspectiveX:
            matrix.setPerspX(makeScalar());
            break;
        case kSetPerspectiveY:
            matrix.setPerspY(makeScalar());
            break;
        case kSetAll:
            matrix.setAll(makeScalar(), makeScalar(), makeScalar(),
                          makeScalar(), makeScalar(), makeScalar(),
                          makeScalar(), makeScalar(), makeScalar());
            break;
    }
    return matrix;
}
Exemplo n.º 10
0
// Called to test various transforms on a single SkRRect.
static void test_transform_helper(skiatest::Reporter* reporter, const SkRRect& orig) {
    SkRRect dst;
    dst.setEmpty();

    // The identity matrix will duplicate the rrect.
    bool success = orig.transform(SkMatrix::I(), &dst);
    REPORTER_ASSERT(reporter, success);
    REPORTER_ASSERT(reporter, orig == dst);

    // Skew and Perspective make transform fail.
    SkMatrix matrix;
    matrix.reset();
    matrix.setSkewX(SkIntToScalar(2));
    assert_transform_failure(reporter, orig, matrix);

    matrix.reset();
    matrix.setSkewY(SkIntToScalar(3));
    assert_transform_failure(reporter, orig, matrix);

    matrix.reset();
    matrix.setPerspX(4);
    assert_transform_failure(reporter, orig, matrix);

    matrix.reset();
    matrix.setPerspY(5);
    assert_transform_failure(reporter, orig, matrix);

    // Rotation fails.
    matrix.reset();
    matrix.setRotate(SkIntToScalar(90));
    assert_transform_failure(reporter, orig, matrix);
    matrix.setRotate(SkIntToScalar(37));
    assert_transform_failure(reporter, orig, matrix);

    // Translate will keep the rect moved, but otherwise the same.
    matrix.reset();
    SkScalar translateX = SkIntToScalar(32);
    SkScalar translateY = SkIntToScalar(15);
    matrix.setTranslateX(translateX);
    matrix.setTranslateY(translateY);
    dst.setEmpty();
    success = orig.transform(matrix, &dst);
    REPORTER_ASSERT(reporter, success);
    for (int i = 0; i < 4; ++i) {
        REPORTER_ASSERT(reporter,
                orig.radii((SkRRect::Corner) i) == dst.radii((SkRRect::Corner) i));
    }
    REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
    REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
    REPORTER_ASSERT(reporter, dst.rect().left() == orig.rect().left() + translateX);
    REPORTER_ASSERT(reporter, dst.rect().top() == orig.rect().top() + translateY);

    // Keeping the translation, but adding skew will make transform fail.
    matrix.setSkewY(SkIntToScalar(7));
    assert_transform_failure(reporter, orig, matrix);

    // Scaling in -x will flip the round rect horizontally.
    matrix.reset();
    matrix.setScaleX(SkIntToScalar(-1));
    dst.setEmpty();
    success = orig.transform(matrix, &dst);
    REPORTER_ASSERT(reporter, success);
    {
        GET_RADII;
        // Radii have swapped in x.
        REPORTER_ASSERT(reporter, origUL == dstUR);
        REPORTER_ASSERT(reporter, origUR == dstUL);
        REPORTER_ASSERT(reporter, origLR == dstLL);
        REPORTER_ASSERT(reporter, origLL == dstLR);
    }
    // Width and height remain the same.
    REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
    REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
    // Right and left have swapped (sort of)
    REPORTER_ASSERT(reporter, orig.rect().right() == -dst.rect().left());
    // Top has stayed the same.
    REPORTER_ASSERT(reporter, orig.rect().top() == dst.rect().top());

    // Keeping the scale, but adding a persp will make transform fail.
    matrix.setPerspX(7);
    assert_transform_failure(reporter, orig, matrix);

    // Scaling in -y will flip the round rect vertically.
    matrix.reset();
    matrix.setScaleY(SkIntToScalar(-1));
    dst.setEmpty();
    success = orig.transform(matrix, &dst);
    REPORTER_ASSERT(reporter, success);
    {
        GET_RADII;
        // Radii have swapped in y.
        REPORTER_ASSERT(reporter, origUL == dstLL);
        REPORTER_ASSERT(reporter, origUR == dstLR);
        REPORTER_ASSERT(reporter, origLR == dstUR);
        REPORTER_ASSERT(reporter, origLL == dstUL);
    }
    // Width and height remain the same.
    REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
    REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
    // Top and bottom have swapped (sort of)
    REPORTER_ASSERT(reporter, orig.rect().top() == -dst.rect().bottom());
    // Left has stayed the same.
    REPORTER_ASSERT(reporter, orig.rect().left() == dst.rect().left());

    // Scaling in -x and -y will swap in both directions.
    matrix.reset();
    matrix.setScaleY(SkIntToScalar(-1));
    matrix.setScaleX(SkIntToScalar(-1));
    dst.setEmpty();
    success = orig.transform(matrix, &dst);
    REPORTER_ASSERT(reporter, success);
    {
        GET_RADII;
        REPORTER_ASSERT(reporter, origUL == dstLR);
        REPORTER_ASSERT(reporter, origUR == dstLL);
        REPORTER_ASSERT(reporter, origLR == dstUL);
        REPORTER_ASSERT(reporter, origLL == dstUR);
    }
    // Width and height remain the same.
    REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
    REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
    REPORTER_ASSERT(reporter, orig.rect().top() == -dst.rect().bottom());
    REPORTER_ASSERT(reporter, orig.rect().right() == -dst.rect().left());

    // Scale in both directions.
    SkScalar xScale = SkIntToScalar(3);
    SkScalar yScale = 3.2f;
    matrix.reset();
    matrix.setScaleX(xScale);
    matrix.setScaleY(yScale);
    dst.setEmpty();
    success = orig.transform(matrix, &dst);
    REPORTER_ASSERT(reporter, success);
    // Radii are scaled.
    for (int i = 0; i < 4; ++i) {
        REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.radii((SkRRect::Corner) i).fX,
                                    SkScalarMul(orig.radii((SkRRect::Corner) i).fX, xScale)));
        REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.radii((SkRRect::Corner) i).fY,
                                    SkScalarMul(orig.radii((SkRRect::Corner) i).fY, yScale)));
    }
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().width(),
                                                  SkScalarMul(orig.rect().width(), xScale)));
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().height(),
                                                  SkScalarMul(orig.rect().height(), yScale)));
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().left(),
                                                  SkScalarMul(orig.rect().left(), xScale)));
    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().top(),
                                                  SkScalarMul(orig.rect().top(), yScale)));
}
void SkSVGPaint::setSave(SkSVGParser& parser) {
    SkTDArray<SkString*> clips;
    SkSVGPaint* walking = parser.fHead;
    int index;
    SkMatrix sum;
    sum.reset();
    while (walking != NULL) {
        for (index = kInitial + 1; index < kTerminal; index++) {
            SkString* lastAttr = (*walking)[index];
            if (lastAttr->size() == 0)
                continue;
            if (index == kTransform) {
                const char* str = lastAttr->c_str();
                SkASSERT(strncmp(str, "matrix(", 7) == 0);
                str += 6;
                const char* strEnd = strrchr(str, ')');
                SkASSERT(strEnd != NULL);
                SkString mat(str, strEnd - str);
                SkSVGParser::ConvertToArray(mat);
                SkScalar values[6];
                SkParse::FindScalars(mat.c_str() + 1, values, 6);
                SkMatrix matrix;
                matrix.reset();
                matrix.setScaleX(values[0]);
                matrix.setSkewY(values[1]);
                matrix.setSkewX(values[2]);
                matrix.setScaleY(values[3]);
                matrix.setTranslateX(values[4]);
                matrix.setTranslateY(values[5]);
                sum.setConcat(matrix, sum);
                continue;
            }
            if ( index == kClipPath)
                *clips.insert(0) = lastAttr;
        }
        walking = walking->fNext;
    }
    if ((sum == parser.fLastTransform) == false) {
        SkMatrix inverse;
        bool success = parser.fLastTransform.invert(&inverse);
        SkASSERT(success == true);
        SkMatrix output;
        output.setConcat(inverse, sum);
        parser.fLastTransform = sum;
        SkString outputStr;
        outputStr.appendUnichar('[');
        outputStr.appendScalar(output.getScaleX());
        outputStr.appendUnichar(',');
        outputStr.appendScalar(output.getSkewX());
        outputStr.appendUnichar(',');
        outputStr.appendScalar(output.getTranslateX());
        outputStr.appendUnichar(',');
        outputStr.appendScalar(output.getSkewY());
        outputStr.appendUnichar(',');
        outputStr.appendScalar(output.getScaleY());
        outputStr.appendUnichar(',');
        outputStr.appendScalar(output.getTranslateY());
        outputStr.appendUnichar(',');
        outputStr.appendScalar(output.getPerspX());
        outputStr.appendUnichar(',');
        outputStr.appendScalar(output.getPerspY());
        outputStr.append(",1]");
        parser._startElement("matrix");
        parser._addAttributeLen("matrix", outputStr.c_str(), outputStr.size());
        parser._endElement();
    }
#if 0   // incomplete
    if (parser.fTransformClips.size() > 0) {
        // need to reset the clip when the 'g' scope is ended
        parser._startElement("add");
        const char* start = strchr(current->f_clipPath.c_str(), '#') + 1;
        SkASSERT(start);
        parser._addAttributeLen("use", start, strlen(start) - 1);
        parser._endElement();   // clip
    }
#endif
}
Exemplo n.º 12
0
SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END

bool SkImageShader::onAppendStages(const StageRec& rec) const {
    SkRasterPipeline* p = rec.fPipeline;
    SkArenaAlloc* alloc = rec.fAlloc;

    SkMatrix matrix;
    if (!this->computeTotalInverse(rec.fCTM, rec.fLocalM, &matrix)) {
        return false;
    }
    auto quality = rec.fPaint.getFilterQuality();

    SkBitmapProvider provider(fImage.get(), rec.fDstCS);
    SkDefaultBitmapController controller;
    std::unique_ptr<SkBitmapController::State> state {
        controller.requestBitmap(provider, matrix, quality)
    };
    if (!state) {
        return false;
    }

    const SkPixmap& pm = state->pixmap();
    matrix  = state->invMatrix();
    quality = state->quality();
    auto info = pm.info();

    // When the matrix is just an integer translate, bilerp == nearest neighbor.
    if (quality == kLow_SkFilterQuality &&
        matrix.getType() <= SkMatrix::kTranslate_Mask &&
        matrix.getTranslateX() == (int)matrix.getTranslateX() &&
        matrix.getTranslateY() == (int)matrix.getTranslateY()) {
        quality = kNone_SkFilterQuality;
    }

    // See skia:4649 and the GM image_scale_aligned.
    if (quality == kNone_SkFilterQuality) {
        if (matrix.getScaleX() >= 0) {
            matrix.setTranslateX(nextafterf(matrix.getTranslateX(),
                                            floorf(matrix.getTranslateX())));
        }
        if (matrix.getScaleY() >= 0) {
            matrix.setTranslateY(nextafterf(matrix.getTranslateY(),
                                            floorf(matrix.getTranslateY())));
        }
    }

    p->append(SkRasterPipeline::seed_shader);

    struct MiscCtx {
        std::unique_ptr<SkBitmapController::State> state;
        SkColor4f paint_color;
    };
    auto misc = alloc->make<MiscCtx>();
    misc->state       = std::move(state);  // Extend lifetime to match the pipeline's.
    misc->paint_color = SkColor4f_from_SkColor(rec.fPaint.getColor(), rec.fDstCS);
    p->append_matrix(alloc, matrix);

    auto gather = alloc->make<SkJumper_GatherCtx>();
    gather->pixels = pm.addr();
    gather->stride = pm.rowBytesAsPixels();
    gather->width  = pm.width();
    gather->height = pm.height();

    auto limit_x = alloc->make<SkJumper_TileCtx>(),
         limit_y = alloc->make<SkJumper_TileCtx>();
    limit_x->scale = pm.width();
    limit_x->invScale = 1.0f / pm.width();
    limit_y->scale = pm.height();
    limit_y->invScale = 1.0f / pm.height();

    bool is_srgb = rec.fDstCS && (!info.colorSpace() || info.gammaCloseToSRGB());

    SkJumper_DecalTileCtx* decal_ctx = nullptr;
    bool decal_x_and_y = fTileModeX == kDecal_TileMode && fTileModeY == kDecal_TileMode;
    if (fTileModeX == kDecal_TileMode || fTileModeY == kDecal_TileMode) {
        decal_ctx = alloc->make<SkJumper_DecalTileCtx>();
        decal_ctx->limit_x = limit_x->scale;
        decal_ctx->limit_y = limit_y->scale;
    }

    auto append_tiling_and_gather = [&] {
        if (decal_x_and_y) {
            p->append(SkRasterPipeline::decal_x_and_y,  decal_ctx);
        } else {
            switch (fTileModeX) {
                case kClamp_TileMode:  /* The gather_xxx stage will clamp for us. */     break;
                case kMirror_TileMode: p->append(SkRasterPipeline::mirror_x, limit_x);   break;
                case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_x, limit_x);   break;
                case kDecal_TileMode:  p->append(SkRasterPipeline::decal_x,  decal_ctx); break;
            }
            switch (fTileModeY) {
                case kClamp_TileMode:  /* The gather_xxx stage will clamp for us. */     break;
                case kMirror_TileMode: p->append(SkRasterPipeline::mirror_y, limit_y);   break;
                case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_y, limit_y);   break;
                case kDecal_TileMode:  p->append(SkRasterPipeline::decal_y,  decal_ctx); break;
            }
        }

        void* ctx = gather;
        switch (info.colorType()) {
            case kAlpha_8_SkColorType:      p->append(SkRasterPipeline::gather_a8,      ctx); break;
            case kGray_8_SkColorType:       p->append(SkRasterPipeline::gather_g8,      ctx); break;
            case kRGB_565_SkColorType:      p->append(SkRasterPipeline::gather_565,     ctx); break;
            case kARGB_4444_SkColorType:    p->append(SkRasterPipeline::gather_4444,    ctx); break;
            case kBGRA_8888_SkColorType:    p->append(SkRasterPipeline::gather_bgra,    ctx); break;
            case kRGBA_8888_SkColorType:    p->append(SkRasterPipeline::gather_8888,    ctx); break;
            case kRGBA_1010102_SkColorType: p->append(SkRasterPipeline::gather_1010102, ctx); break;
            case kRGBA_F16_SkColorType:     p->append(SkRasterPipeline::gather_f16,     ctx); break;

            case kRGB_888x_SkColorType:     p->append(SkRasterPipeline::gather_8888,    ctx);
                                            p->append(SkRasterPipeline::force_opaque       ); break;
            case kRGB_101010x_SkColorType:  p->append(SkRasterPipeline::gather_1010102, ctx);
                                            p->append(SkRasterPipeline::force_opaque       ); break;

            default: SkASSERT(false);
        }
        if (decal_ctx) {
            p->append(SkRasterPipeline::check_decal_mask, decal_ctx);
        }
        if (is_srgb) {
            p->append(SkRasterPipeline::from_srgb);
        }
    };

    auto append_misc = [&] {
        if (info.colorType() == kAlpha_8_SkColorType) {
            p->append(SkRasterPipeline::set_rgb, &misc->paint_color);
        }
        if (info.colorType() == kAlpha_8_SkColorType ||
            info.alphaType() == kUnpremul_SkAlphaType) {
            p->append(SkRasterPipeline::premul);
        }
        if (quality > kLow_SkFilterQuality) {
            // Bicubic filtering naturally produces out of range values on both sides.
            p->append(SkRasterPipeline::clamp_0);
            p->append(fClampAsIfUnpremul ? SkRasterPipeline::clamp_1
                                         : SkRasterPipeline::clamp_a);
        }
        append_gamut_transform(p, alloc, info.colorSpace(), rec.fDstCS,
                               fClampAsIfUnpremul ? kUnpremul_SkAlphaType : kPremul_SkAlphaType);
        return true;
    };

    // We've got a fast path for 8888 bilinear clamp/clamp non-color-managed sampling.
    auto ct = info.colorType();
    if (true
        && (ct == kRGBA_8888_SkColorType || ct == kBGRA_8888_SkColorType)
        && quality == kLow_SkFilterQuality
        && fTileModeX == SkShader::kClamp_TileMode
        && fTileModeY == SkShader::kClamp_TileMode
        && !is_srgb) {

        p->append(SkRasterPipeline::bilerp_clamp_8888, gather);
        if (ct == kBGRA_8888_SkColorType) {
            p->append(SkRasterPipeline::swap_rb);
        }
        return append_misc();
    }

    SkJumper_SamplerCtx* sampler = nullptr;
    if (quality != kNone_SkFilterQuality) {
        sampler = alloc->make<SkJumper_SamplerCtx>();
    }

    auto sample = [&](SkRasterPipeline::StockStage setup_x,
                      SkRasterPipeline::StockStage setup_y) {
        p->append(setup_x, sampler);
        p->append(setup_y, sampler);
        append_tiling_and_gather();
        p->append(SkRasterPipeline::accumulate, sampler);
    };

    if (quality == kNone_SkFilterQuality) {
        append_tiling_and_gather();

    } else if (quality == kLow_SkFilterQuality) {
        p->append(SkRasterPipeline::save_xy, sampler);

        sample(SkRasterPipeline::bilinear_nx, SkRasterPipeline::bilinear_ny);
        sample(SkRasterPipeline::bilinear_px, SkRasterPipeline::bilinear_ny);
        sample(SkRasterPipeline::bilinear_nx, SkRasterPipeline::bilinear_py);
        sample(SkRasterPipeline::bilinear_px, SkRasterPipeline::bilinear_py);

        p->append(SkRasterPipeline::move_dst_src);

    } else {
        p->append(SkRasterPipeline::save_xy, sampler);

        sample(SkRasterPipeline::bicubic_n3x, SkRasterPipeline::bicubic_n3y);
        sample(SkRasterPipeline::bicubic_n1x, SkRasterPipeline::bicubic_n3y);
        sample(SkRasterPipeline::bicubic_p1x, SkRasterPipeline::bicubic_n3y);
        sample(SkRasterPipeline::bicubic_p3x, SkRasterPipeline::bicubic_n3y);

        sample(SkRasterPipeline::bicubic_n3x, SkRasterPipeline::bicubic_n1y);
        sample(SkRasterPipeline::bicubic_n1x, SkRasterPipeline::bicubic_n1y);
        sample(SkRasterPipeline::bicubic_p1x, SkRasterPipeline::bicubic_n1y);
        sample(SkRasterPipeline::bicubic_p3x, SkRasterPipeline::bicubic_n1y);

        sample(SkRasterPipeline::bicubic_n3x, SkRasterPipeline::bicubic_p1y);
        sample(SkRasterPipeline::bicubic_n1x, SkRasterPipeline::bicubic_p1y);
        sample(SkRasterPipeline::bicubic_p1x, SkRasterPipeline::bicubic_p1y);
        sample(SkRasterPipeline::bicubic_p3x, SkRasterPipeline::bicubic_p1y);

        sample(SkRasterPipeline::bicubic_n3x, SkRasterPipeline::bicubic_p3y);
        sample(SkRasterPipeline::bicubic_n1x, SkRasterPipeline::bicubic_p3y);
        sample(SkRasterPipeline::bicubic_p1x, SkRasterPipeline::bicubic_p3y);
        sample(SkRasterPipeline::bicubic_p3x, SkRasterPipeline::bicubic_p3y);

        p->append(SkRasterPipeline::move_dst_src);
    }

    return append_misc();
}