SkPaint SkColorSpaceXformer::apply(const SkPaint& src) {
    const AutoCachePurge autoPurge(this);

    SkPaint dst = src;

    // All SkColorSpaces have the same black point.
    if (src.getColor() & 0xffffff) {
        dst.setColor(this->apply(src.getColor()));
    }

    if (auto shader = src.getShader()) {
        dst.setShader(this->apply(shader));
    }

    if (auto cf = src.getColorFilter()) {
        dst.setColorFilter(this->apply(cf));
    }

    if (auto looper = src.getDrawLooper()) {
        dst.setDrawLooper(looper->makeColorSpace(this));
    }

    if (auto imageFilter = src.getImageFilter()) {
        dst.setImageFilter(this->apply(imageFilter));
    }

    return dst;
}
Example #2
0
bool SkPaint2GrPaint(GrContext* context, GrRenderTarget* rt, const SkPaint& skPaint,
                     const SkMatrix& viewM, bool constantColor, GrPaint* grPaint) {
    SkShader* shader = skPaint.getShader();
    if (NULL == shader) {
        return SkPaint2GrPaintNoShader(context, rt, skPaint, SkColor2GrColor(skPaint.getColor()),
                                       constantColor, grPaint);
    }

    GrColor paintColor = SkColor2GrColor(skPaint.getColor());

    // Start a new block here in order to preserve our context state after calling
    // asFragmentProcessor(). Since these calls get passed back to the client, we don't really
    // want them messing around with the context.
    {
        // Allow the shader to modify paintColor and also create an effect to be installed as
        // the first color effect on the GrPaint.
        GrFragmentProcessor* fp = NULL;
        if (!shader->asFragmentProcessor(context, skPaint, viewM, NULL, &paintColor,
                                         grPaint->getProcessorDataManager(), &fp)) {
            return false;
        }
        if (fp) {
            grPaint->addColorProcessor(fp)->unref();
            constantColor = false;
        }
    }

    // The grcolor is automatically set when calling asFragmentProcessor.
    // If the shader can be seen as an effect it returns true and adds its effect to the grpaint.
    return SkPaint2GrPaintNoShader(context, rt, skPaint, paintColor, constantColor, grPaint);
}
Example #3
0
    bool onMatch(SkRecord* record, Pattern* pattern, unsigned begin, unsigned end) {
        SaveLayer* saveLayer = pattern->first<SaveLayer>();
        if (saveLayer->bounds != NULL) {
            // SaveLayer with bounds is too tricky for us.
            return false;
        }

        SkPaint* layerPaint = saveLayer->paint;
        if (NULL == layerPaint) {
            // There wasn't really any point to this SaveLayer at all.
            return KillSaveLayerAndRestore(record, begin);
        }

        SkPaint* drawPaint = pattern->second<SkPaint>();
        if (drawPaint == NULL) {
            // We can just give the draw the SaveLayer's paint.
            // TODO(mtklein): figure out how to do this clearly
            return false;
        }

        const uint32_t layerColor = layerPaint->getColor();
        const uint32_t  drawColor =  drawPaint->getColor();
        if (!IsOnlyAlpha(layerColor)  || !IsOpaque(drawColor) ||
            HasAnyEffect(*layerPaint) || HasAnyEffect(*drawPaint)) {
            // Too fancy for us.  Actually, as long as layerColor is just an alpha
            // we can blend it into drawColor's alpha; drawColor doesn't strictly have to be opaque.
            return false;
        }

        drawPaint->setColor(SkColorSetA(drawColor, SkColorGetA(layerColor)));
        return KillSaveLayerAndRestore(record, begin);
    }
bool SkBitmapProcShader::asFragmentProcessor(GrContext* context, const SkPaint& paint,
                                             const SkMatrix& viewM,
                                             const SkMatrix* localMatrix, GrColor* paintColor,
                                             GrProcessorDataManager* procDataManager,
                                             GrFragmentProcessor** fp) const {
    SkMatrix matrix;
    matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height());

    SkMatrix lmInverse;
    if (!this->getLocalMatrix().invert(&lmInverse)) {
        return false;
    }
    if (localMatrix) {
        SkMatrix inv;
        if (!localMatrix->invert(&inv)) {
            return false;
        }
        lmInverse.postConcat(inv);
    }
    matrix.preConcat(lmInverse);

    SkShader::TileMode tm[] = {
        (TileMode)fTileModeX,
        (TileMode)fTileModeY,
    };

    // Must set wrap and filter on the sampler before requesting a texture. In two places below
    // we check the matrix scale factors to determine how to interpret the filter quality setting.
    // This completely ignores the complexity of the drawVertices case where explicit local coords
    // are provided by the caller.
    bool doBicubic;
    GrTextureParams::FilterMode textureFilterMode =
            GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), viewM, this->getLocalMatrix(),
                                            &doBicubic);
    GrTextureParams params(tm, textureFilterMode);
    SkAutoTUnref<GrTexture> texture(GrRefCachedBitmapTexture(context, fRawBitmap, &params));

    if (!texture) {
        SkErrorInternals::SetError( kInternalError_SkError,
                                    "Couldn't convert bitmap to texture.");
        return false;
    }

    *paintColor = (kAlpha_8_SkColorType == fRawBitmap.colorType()) ?
                                                SkColor2GrColor(paint.getColor()) :
                                                SkColor2GrColorJustAlpha(paint.getColor());

    if (doBicubic) {
        *fp = GrBicubicEffect::Create(procDataManager, texture, matrix, tm);
    } else {
        *fp = GrSimpleTextureEffect::Create(procDataManager, texture, matrix, params);
    }

    return true;
}
Example #5
0
SkRGB16_Black_Blitter::SkRGB16_Black_Blitter(const SkPixmap& device, const SkPaint& paint)
    : INHERITED(device, paint) {
    SkASSERT(paint.getShader() == nullptr);
    SkASSERT(paint.getColorFilter() == nullptr);
    SkASSERT(paint.isSrcOver());
    SkASSERT(paint.getColor() == SK_ColorBLACK);
}
Example #6
0
    void setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) override {
        fDst  = dst;
        fLeft = left;
        fTop  = top;

        fPaintColor = SkColor4f_from_SkColor(paint.getColor(), fDst.colorSpace());

        SkRasterPipeline p(fAlloc);
        switch (fSource.colorType()) {
            case kAlpha_8_SkColorType:   p.append(SkRasterPipeline::load_a8,   &fSrcPtr); break;
            case kGray_8_SkColorType:    p.append(SkRasterPipeline::load_g8,   &fSrcPtr); break;
            case kRGB_565_SkColorType:   p.append(SkRasterPipeline::load_565,  &fSrcPtr); break;
            case kARGB_4444_SkColorType: p.append(SkRasterPipeline::load_4444, &fSrcPtr); break;
            case kBGRA_8888_SkColorType: p.append(SkRasterPipeline::load_bgra, &fSrcPtr); break;
            case kRGBA_8888_SkColorType: p.append(SkRasterPipeline::load_8888, &fSrcPtr); break;
            case kRGBA_F16_SkColorType:  p.append(SkRasterPipeline::load_f16,  &fSrcPtr); break;
            default: SkASSERT(false);
        }
        if (fDst.colorSpace() &&
                (!fSource.colorSpace() || fSource.colorSpace()->gammaCloseToSRGB())) {
            p.append_from_srgb(fSource.alphaType());
        }
        if (fSource.colorType() == kAlpha_8_SkColorType) {
            p.append(SkRasterPipeline::set_rgb, &fPaintColor);
            p.append(SkRasterPipeline::premul);
        }
        append_gamut_transform(&p, fAlloc,
                               fSource.colorSpace(), fDst.colorSpace(), kPremul_SkAlphaType);
        if (fPaintColor.fA != 1.0f) {
            p.append(SkRasterPipeline::scale_1_float, &fPaintColor.fA);
        }

        bool is_opaque = fSource.isOpaque() && fPaintColor.fA == 1.0f;
        fBlitter = SkCreateRasterPipelineBlitter(fDst, paint, p, is_opaque, fAlloc);
    }
SkARGB4444_Blitter::SkARGB4444_Blitter(const SkBitmap& device,
                                   const SkPaint& paint) : INHERITED(device) {
    // cache premultiplied versions in 4444
    SkPMColor c = SkPreMultiplyColor(paint.getColor());
    fPMColor16 = SkPixel32ToPixel4444(c);
    if (paint.isDither()) {
        fPMColor16Other = SkDitherPixel32To4444(c);
    } else {
        fPMColor16Other = fPMColor16;
    }

    // cache raw versions in 4444
    fRawColor16 = SkPackARGB4444(0xFF >> 4, SkColorGetR(c) >> 4,
                                 SkColorGetG(c) >> 4, SkColorGetB(c) >> 4);
    if (paint.isDither()) {
        fRawColor16Other = SkDitherARGB32To4444(0xFF, SkColorGetR(c),
                                                SkColorGetG(c), SkColorGetB(c));
    } else {
        fRawColor16Other = fRawColor16;
    }

    fScale16 = SkAlpha15To16(SkGetPackedA4444(fPMColor16Other));
    if (16 == fScale16) {
        // force the original to also be opaque
        fPMColor16 |= (0xF << SK_A4444_SHIFT);
    }
}
Example #8
0
bool SkColorShader::setContext(const SkBitmap& device, const SkPaint& paint,
                               const SkMatrix& matrix) {
    if (!this->INHERITED::setContext(device, paint, matrix)) {
        return false;
    }

    SkColor c;
    unsigned a;
    
    if (fInheritColor) {
        c = paint.getColor();
        a = SkColorGetA(c);
    } else {
        c = fColor;
        a = SkAlphaMul(SkColorGetA(c), SkAlpha255To256(paint.getAlpha()));
    }

    unsigned r = SkColorGetR(c);
    unsigned g = SkColorGetG(c);
    unsigned b = SkColorGetB(c);

    // we want this before we apply any alpha
    fColor16 = SkPack888ToRGB16(r, g, b);

    if (a != 255) {
        a = SkAlpha255To256(a);
        r = SkAlphaMul(r, a);
        g = SkAlphaMul(g, a);
        b = SkAlphaMul(b, a);
    }
    fPMColor = SkPackARGB32(a, r, g, b);

    return true;
}
Example #9
0
void SkOverdrawCanvas::onDrawPaint(const SkPaint& paint) {
    if (0 == paint.getColor() && !paint.getColorFilter() && !paint.getShader()) {
        // This is a clear, ignore it.
    } else {
        fList[0]->onDrawPaint(this->overdrawPaint(paint));
    }
}
Example #10
0
void paintSkiaText(GraphicsContext* context,
                   HFONT hfont,
                   int numGlyphs,
                   const WORD* glyphs,
                   const int* advances,
                   const GOFFSET* offsets,
                   const SkPoint* origin)
{
    HDC dc = GetDC(0);
    HGDIOBJ oldFont = SelectObject(dc, hfont);

    PlatformContextSkia* platformContext = context->platformContext();
    SkCanvas* canvas = platformContext->canvas();
    TextDrawingModeFlags textMode = platformContext->getTextDrawingMode();

    // If platformContext is GPU-backed make its GL context current.
    platformContext->makeGrContextCurrent();

    // Filling (if necessary). This is the common case.
    SkPaint paint;
    platformContext->setupPaintForFilling(&paint);
    paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
    setupPaintForFont(hfont, &paint, platformContext);

    bool didFill = false;

    if ((textMode & TextModeFill) && (SkColorGetA(paint.getColor()) || paint.getLooper())) {
        skiaDrawText(canvas, *origin, &paint, &glyphs[0], &advances[0], &offsets[0], numGlyphs);
        didFill = true;
    }

    // Stroking on top (if necessary).
    if ((textMode & TextModeStroke)
        && platformContext->getStrokeStyle() != NoStroke
        && platformContext->getStrokeThickness() > 0) {

        paint.reset();
        platformContext->setupPaintForStroking(&paint, 0, 0);
        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
        setupPaintForFont(hfont, &paint, platformContext);

        if (didFill) {
            // If there is a shadow and we filled above, there will already be
            // a shadow. We don't want to draw it again or it will be too dark
            // and it will go on top of the fill.
            //
            // Note that this isn't strictly correct, since the stroke could be
            // very thick and the shadow wouldn't account for this. The "right"
            // thing would be to draw to a new layer and then draw that layer
            // with a shadow. But this is a lot of extra work for something
            // that isn't normally an issue.
            paint.setLooper(0);
        }

        skiaDrawText(canvas, *origin, &paint, &glyphs[0], &advances[0], &offsets[0], numGlyphs);
    }

    SelectObject(dc, oldFont);
    ReleaseDC(0, dc);
}
Example #11
0
static void lettersToBitmap2(SkBitmap* dst, const char chars[],
                            const SkPaint& original, SkBitmap::Config config) {
    SkPath path;
    SkScalar x = 0;
    SkScalar width;
    SkPath p;
    for (size_t i = 0; i < strlen(chars); i++) {
        original.getTextPath(&chars[i], 1, x, 0, &p);
        path.addPath(p);
        original.getTextWidths(&chars[i], 1, &width);
        x += width;
    }
    SkRect bounds = path.getBounds();
    SkScalar sw = -original.getStrokeWidth();
    bounds.inset(sw, sw);
    path.offset(-bounds.fLeft, -bounds.fTop);
    bounds.offset(-bounds.fLeft, -bounds.fTop);

    int w = SkScalarRound(bounds.width());
    int h = SkScalarRound(bounds.height());
    SkPaint paint(original);

    paint.setAntiAlias(true);
    paint.setXfermodeMode(SkXfermode::kDstATop_Mode);
    paint.setColor(original.getColor());
    paint.setStyle(SkPaint::kStroke_Style);

    dst->setConfig(config, w, h);
    dst->allocPixels();
    dst->eraseColor(SK_ColorWHITE);

    SkCanvas canvas(*dst);
    canvas.drawPath(path, paint);
}
Example #12
0
SkRGB16_Black_Blitter::SkRGB16_Black_Blitter(const SkBitmap& device, const SkPaint& paint)
    : INHERITED(device, paint) {
    SkASSERT(paint.getShader() == NULL);
    SkASSERT(paint.getColorFilter() == NULL);
    SkASSERT(paint.getXfermode() == NULL);
    SkASSERT(paint.getColor() == SK_ColorBLACK);
}
// Check for:
//    SAVE_LAYER
//        SAVE
//            CLIP_RECT
//            DRAW_BITMAP_RECT_TO_RECT
//        RESTORE
//    RESTORE
// where the saveLayer's color can be moved into the drawBitmapRect
static bool check_1(SkDebugCanvas* canvas, int curCommand) {
    if (SAVE_LAYER != canvas->getDrawCommandAt(curCommand)->getType() ||
        canvas->getSize() <= curCommand+5 ||
        SAVE != canvas->getDrawCommandAt(curCommand+1)->getType() ||
        CLIP_RECT != canvas->getDrawCommandAt(curCommand+2)->getType() ||
        DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+3)->getType() ||
        RESTORE != canvas->getDrawCommandAt(curCommand+4)->getType() ||
        RESTORE != canvas->getDrawCommandAt(curCommand+5)->getType()) {
        return false;
    }

    SkSaveLayerCommand* saveLayer =
        (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand);
    SkDrawBitmapRectCommand* dbmr =
        (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+3);

    const SkPaint* saveLayerPaint = saveLayer->paint();
    SkPaint* dbmrPaint = dbmr->paint();

    // For this optimization we only fold the saveLayer and drawBitmapRect
    // together if the saveLayer's draw is simple (i.e., no fancy effects) and
    // and the only difference in the colors is that the saveLayer's can have
    // an alpha while the drawBitmapRect's is opaque.
    // TODO: it should be possible to fold them together even if they both
    // have different non-255 alphas but this is low priority since we have
    // never seen that case
    // If either operation lacks a paint then the collapse is trivial
    SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque

    return NULL == saveLayerPaint ||
           NULL == dbmrPaint ||
           (is_simple(*saveLayerPaint) && dbmrPaint->getColor() == layerColor);
}
    void drawShadowedPath(SkCanvas* canvas, const SkPath& path,
                          const SkPoint3& zPlaneParams,
                          const SkPaint& paint, SkScalar ambientAlpha,
                          const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
        if (!fShowAmbient) {
            ambientAlpha = 0;
        }
        if (!fShowSpot) {
            spotAlpha = 0;
        }
        uint32_t flags = 0;
        if (fUseAlt) {
            flags |= SkShadowFlags::kGeometricOnly_ShadowFlag;
        }
        SkShadowUtils::DrawShadow(canvas, path, zPlaneParams,
                                  lightPos, lightWidth,
                                  ambientAlpha, spotAlpha, SK_ColorBLACK, flags);

        if (fShowObject) {
            canvas->drawPath(path, paint);
        } else {
            SkPaint strokePaint;

            strokePaint.setColor(paint.getColor());
            strokePaint.setStyle(SkPaint::kStroke_Style);

            canvas->drawPath(path, strokePaint);
        }
    }
    virtual void onDraw(SkCanvas* canvas) {
        const SkIPoint dim = this->getSize();
        SkRandom rand;

        SkPaint paint(fPaint);
        this->setupPaint(&paint);
        // explicitly need these
        paint.setColor(fPaint.getColor());
        paint.setAntiAlias(kBW != fFQ);
        paint.setLCDRenderText(kLCD == fFQ);

        const SkScalar x0 = SkIntToScalar(-10);
        const SkScalar y0 = SkIntToScalar(-10);

        if (fDoPos) {
            // realistically, the matrix is often at least translated, so we
            // do that since it exercises different code in drawPosText.
            canvas->translate(SK_Scalar1, SK_Scalar1);
        }

        for (int i = 0; i < N; i++) {
            if (fDoPos) {
                canvas->drawPosText(fText.c_str(), fText.size(), fPos, paint);
            } else {
                SkScalar x = x0 + rand.nextUScalar1() * dim.fX;
                SkScalar y = y0 + rand.nextUScalar1() * dim.fY;
                canvas->drawText(fText.c_str(), fText.size(), x, y, paint);
            }
        }
    }
// Fold the saveLayer's alpha into the drawBitmapRect and remove the saveLayer
// and restore
static void apply_0(SkDebugCanvas* canvas, int curCommand) {
    SkSaveLayerCommand* saveLayer =
        (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand);
    const SkPaint* saveLayerPaint = saveLayer->paint();

    // if (NULL == saveLayerPaint) the dbmr's paint doesn't need to be changed
    if (NULL != saveLayerPaint) {
        SkDrawBitmapRectCommand* dbmr =
            (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+1);
        SkPaint* dbmrPaint = dbmr->paint();

        if (NULL == dbmrPaint) {
            // if the DBMR doesn't have a paint just use the saveLayer's
            dbmr->setPaint(*saveLayerPaint);
        } else if (NULL != saveLayerPaint) {
            // Both paints are present so their alphas need to be combined
            SkColor color = saveLayerPaint->getColor();
            int a0 = SkColorGetA(color);

            color = dbmrPaint->getColor();
            int a1 = SkColorGetA(color);

            int newA = SkMulDiv255Round(a0, a1);
            SkASSERT(newA <= 0xFF);

            SkColor newColor = SkColorSetA(color, newA);
            dbmrPaint->setColor(newColor);
        }
    }

    canvas->deleteDrawCommandAt(curCommand+2);  // restore
    canvas->deleteDrawCommandAt(curCommand);    // saveLayer
}
Example #17
0
void SkGL::SetPaint(const SkPaint& paint, bool isPremul, bool justAlpha) {
    if (justAlpha) {
        SkGL::SetAlpha(paint.getAlpha());
    } else {
        SkGL::SetColor(paint.getColor());
    }

    GLenum sm = GL_ONE;
    GLenum dm = GL_ONE_MINUS_SRC_ALPHA;

    SkXfermode* mode = paint.getXfermode();
    SkXfermode::Coeff sc, dc;
    if (mode && mode->asCoeff(&sc, &dc)) {
        sm = gXfermodeCoeff2Blend[sc];
        dm = gXfermodeCoeff2Blend[dc];
    }

    // hack for text, which is not-premul (afaik)
    if (!isPremul) {
        if (GL_ONE == sm) {
            sm = GL_SRC_ALPHA;
        }
    }

    glEnable(GL_BLEND);
    glBlendFunc(sm, dm);

    if (paint.isDither()) {
        glEnable(GL_DITHER);
    } else {
        glDisable(GL_DITHER);
    }
}
// Check for:
//    SAVE_LAYER
//        DRAW_BITMAP_RECT_TO_RECT
//    RESTORE
// where the saveLayer's color can be moved into the drawBitmapRect
static bool check_0(SkDebugCanvas* canvas, int curCommand) {
    if (SAVE_LAYER != canvas->getDrawCommandAt(curCommand)->getType() ||
        canvas->getSize() <= curCommand+2 ||
        DRAW_BITMAP_RECT_TO_RECT != canvas->getDrawCommandAt(curCommand+1)->getType() ||
        RESTORE != canvas->getDrawCommandAt(curCommand+2)->getType()) {
        return false;
    }

    SkSaveLayerCommand* saveLayer =
        (SkSaveLayerCommand*) canvas->getDrawCommandAt(curCommand);
    SkDrawBitmapRectCommand* dbmr =
        (SkDrawBitmapRectCommand*) canvas->getDrawCommandAt(curCommand+1);

    const SkPaint* saveLayerPaint = saveLayer->paint();
    SkPaint* dbmrPaint = dbmr->paint();

    // For this optimization we only fold the saveLayer and drawBitmapRect
    // together if the saveLayer's draw is simple (i.e., no fancy effects)
    // and the only difference in the colors is their alpha value
    SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
    SkColor dbmrColor = dbmrPaint->getColor() | 0xFF000000;       // force opaque

    // If either operation lacks a paint then the collapse is trivial
    return NULL == saveLayerPaint ||
           NULL == dbmrPaint ||
           (is_simple(*saveLayerPaint) && dbmrColor == layerColor);
}
Example #19
0
SkARGB4444_Blitter::SkARGB4444_Blitter(const SkBitmap& device, const SkPaint& paint)
    : INHERITED(device)
{
    // cache premultiplied versions in 4444
    SkPMColor c = SkPreMultiplyColor(paint.getColor());
    fPMColor16 = SkPixel32ToPixel4444(c);
    if (paint.isDither()) {
        fPMColor16Other = SkDitherPixel32To4444(c);
    } else {
        fPMColor16Other = fPMColor16;
    }

    // cache raw versions in 4444
    fRawColor16 = SkPackARGB4444(0xFF >> 4, SkColorGetR(c) >> 4,
                                 SkColorGetG(c) >> 4, SkColorGetB(c) >> 4);
    if (paint.isDither()) {
        fRawColor16Other = SkDitherARGB32To4444(0xFF, SkColorGetR(c),
                                                SkColorGetG(c), SkColorGetB(c));
    } else {
        fRawColor16Other = fRawColor16;
    }
    
#if 0 /// don't think this assertion is true, but need it be?

    // our dithered color will be the same or more opaque than the original
    // so use dithered to compute our scale
    SkASSERT(SkGetPackedA4444(fPMColor16Other) >= SkGetPackedA4444(fPMColor16));
#endif

    fScale16 = SkAlpha15To16(SkGetPackedA4444(fPMColor16Other));
    if (16 == fScale16) {
        // force the original to also be opaque
        fPMColor16 |= (0xF << SK_A4444_SHIFT);
    }
}
Example #20
0
 State4f(const SkImageInfo& info, const SkPaint& paint, const SkShader::Context* shaderContext) {
     fXfer = paint.getXfermode();
     if (shaderContext) {
         fBuffer.reset(info.width());
     } else {
         fPM4f = SkColor4f::FromColor(paint.getColor()).premul();
     }
     fFlags = 0;
 }
Example #21
0
void SkSVGDevice::AutoElement::addPaint(const SkPaint& paint, const Resources& resources) {
    SkPaint::Style style = paint.getStyle();
    if (style == SkPaint::kFill_Style || style == SkPaint::kStrokeAndFill_Style) {
        this->addAttribute("fill", resources.fPaintServer);

        if (SK_AlphaOPAQUE != SkColorGetA(paint.getColor())) {
            this->addAttribute("fill-opacity", svg_opacity(paint.getColor()));
        }
    } else {
        SkASSERT(style == SkPaint::kStroke_Style);
        this->addAttribute("fill", "none");
    }

    if (style == SkPaint::kStroke_Style || style == SkPaint::kStrokeAndFill_Style) {
        this->addAttribute("stroke", resources.fPaintServer);

        SkScalar strokeWidth = paint.getStrokeWidth();
        if (strokeWidth == 0) {
            // Hairline stroke
            strokeWidth = 1;
            this->addAttribute("vector-effect", "non-scaling-stroke");
        }
        this->addAttribute("stroke-width", strokeWidth);

        if (const char* cap = svg_cap(paint.getStrokeCap())) {
            this->addAttribute("stroke-linecap", cap);
        }

        if (const char* join = svg_join(paint.getStrokeJoin())) {
            this->addAttribute("stroke-linejoin", join);
        }

        if (paint.getStrokeJoin() == SkPaint::kMiter_Join) {
            this->addAttribute("stroke-miterlimit", paint.getStrokeMiter());
        }

        if (SK_AlphaOPAQUE != SkColorGetA(paint.getColor())) {
            this->addAttribute("stroke-opacity", svg_opacity(paint.getColor()));
        }
    } else {
        SkASSERT(style == SkPaint::kFill_Style);
        this->addAttribute("stroke", "none");
    }
}
Example #22
0
static bool fold_opacity_layer_color_to_paint(const SkPaint& layerPaint,
                                              bool isSaveLayer,
                                              SkPaint* paint) {
    // We assume layerPaint is always from a saveLayer.  If isSaveLayer is
    // true, we assume paint is too.

    // The alpha folding can proceed if the filter layer paint does not have properties which cause
    // the resulting filter layer to be "blended" in complex ways to the parent layer. For example,
    // looper drawing unmodulated filter layer twice and then modulating the result produces
    // different image to drawing modulated filter layer twice.
    // TODO: most likely the looper and only some xfer modes are the hard constraints
    if (paint->getXfermode() || paint->getLooper()) {
        return false;
    }

    if (!isSaveLayer && paint->getImageFilter()) {
        // For normal draws, the paint color is used as one input for the color for the draw. Image
        // filter will operate on the result, and thus we can not change the input.
        // For layer saves, the image filter is applied to the layer contents. The layer is then
        // modulated with the paint color, so it's fine to proceed with the fold for saveLayer
        // paints with image filters.
        return false;
    }

    if (paint->getColorFilter()) {
        // Filter input depends on the paint color.

        // Here we could filter the color if we knew the draw is going to be uniform color.  This
        // should be detectable as drawPath/drawRect/.. without a shader being uniform, while
        // drawBitmap/drawSprite or a shader being non-uniform. However, current matchers don't
        // give the type out easily, so just do not optimize that at the moment.
        return false;
    }

    const uint32_t layerColor = layerPaint.getColor();
    // The layer paint color must have only alpha component.
    if (SK_ColorTRANSPARENT != SkColorSetA(layerColor, SK_AlphaTRANSPARENT)) {
        return false;
    }

    // The layer paint can not have any effects.
    if (layerPaint.getPathEffect() ||
        layerPaint.getShader()      ||
        layerPaint.getXfermode()    ||
        layerPaint.getMaskFilter()  ||
        layerPaint.getColorFilter() ||
        layerPaint.getRasterizer()  ||
        layerPaint.getLooper()      ||
        layerPaint.getImageFilter()) {
        return false;
    }

    paint->setAlpha(SkMulDiv255Round(paint->getAlpha(), SkColorGetA(layerColor)));

    return true;
}
    const char* onGetName() override {
        fName.printf("text_%g", SkScalarToFloat(fPaint.getTextSize()));
        if (fDoPos) {
            fName.append("_pos");
        }
        fName.appendf("_%s", fontQualityName(fPaint));
        if (SK_ColorBLACK == fPaint.getColor()) {
            fName.append("_BK");
        } else if (SK_ColorWHITE == fPaint.getColor()) {
            fName.append("_WT");
        } else {
            fName.appendf("_%02X", fPaint.getAlpha());
        }

        if (fDoColorEmoji) {
            fName.append("_ColorEmoji");
        }

        return fName.c_str();
    }
Example #24
0
static void apply_paint_color(const SkPaint& paint, Json::Value* target) {
    SkColor color = paint.getColor();
    if (color != SK_ColorBLACK) {
        Json::Value colorValue(Json::arrayValue);
        colorValue.append(Json::Value(SkColorGetA(color)));
        colorValue.append(Json::Value(SkColorGetR(color)));
        colorValue.append(Json::Value(SkColorGetG(color)));
        colorValue.append(Json::Value(SkColorGetB(color)));
        (*target)[SKJSONCANVAS_ATTRIBUTE_COLOR] = colorValue;;
    }
}
Example #25
0
void paintSkiaText(GraphicsContext* context,
                   HFONT hfont,
                   int numGlyphs,
                   const WORD* glyphs,
                   const int* advances,
                   const GOFFSET* offsets,
                   const SkPoint* origin)
{
    PlatformContextSkia* platformContext = context->platformContext();
    SkCanvas* canvas = platformContext->canvas();
    TextDrawingModeFlags textMode = platformContext->getTextDrawingMode();
    // Ensure font load for printing, because PDF device needs it.
    if (canvas->getTopDevice()->getDeviceCapabilities() & SkDevice::kVector_Capability)
        PlatformSupport::ensureFontLoaded(hfont);

    // Filling (if necessary). This is the common case.
    SkPaint paint;
    platformContext->setupPaintForFilling(&paint);
    paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
    setupPaintForFont(hfont, &paint, platformContext);

    bool didFill = false;

    if ((textMode & TextModeFill) && (SkColorGetA(paint.getColor()) || paint.getLooper())) {
        skiaDrawText(canvas, *origin, &paint, &glyphs[0], &advances[0], &offsets[0], numGlyphs);
        didFill = true;
    }

    // Stroking on top (if necessary).
    if ((textMode & TextModeStroke)
        && platformContext->getStrokeStyle() != NoStroke
        && platformContext->getStrokeThickness() > 0) {

        paint.reset();
        platformContext->setupPaintForStroking(&paint, 0, 0);
        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
        setupPaintForFont(hfont, &paint, platformContext);

        if (didFill) {
            // If there is a shadow and we filled above, there will already be
            // a shadow. We don't want to draw it again or it will be too dark
            // and it will go on top of the fill.
            //
            // Note that this isn't strictly correct, since the stroke could be
            // very thick and the shadow wouldn't account for this. The "right"
            // thing would be to draw to a new layer and then draw that layer
            // with a shadow. But this is a lot of extra work for something
            // that isn't normally an issue.
            paint.setLooper(0);
        }

        skiaDrawText(canvas, *origin, &paint, &glyphs[0], &advances[0], &offsets[0], numGlyphs);
    }
}
Example #26
0
// This is only used to draw borders.
void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
{
    if (paintingDisabled())
        return;

    StrokeStyle penStyle = strokeStyle();
    if (penStyle == NoStroke)
        return;

    SkPaint paint;
    if (!isPointSkiaSafe(getCTM(), point1) || !isPointSkiaSafe(getCTM(), point2))
        return;

    platformContext()->prepareForSoftwareDraw();

    FloatPoint p1 = point1;
    FloatPoint p2 = point2;
    bool isVerticalLine = (p1.x() == p2.x());
    int width = roundf(strokeThickness());

    // We know these are vertical or horizontal lines, so the length will just
    // be the sum of the displacement component vectors give or take 1 -
    // probably worth the speed up of no square root, which also won't be exact.
    FloatSize disp = p2 - p1;
    int length = SkScalarRound(disp.width() + disp.height());
    platformContext()->setupPaintForStroking(&paint, 0, length);

    if (strokeStyle() == DottedStroke || strokeStyle() == DashedStroke) {
        // Do a rect fill of our endpoints.  This ensures we always have the
        // appearance of being a border.  We then draw the actual dotted/dashed line.

        SkRect r1, r2;
        r1.set(p1.x(), p1.y(), p1.x() + width, p1.y() + width);
        r2.set(p2.x(), p2.y(), p2.x() + width, p2.y() + width);

        if (isVerticalLine) {
            r1.offset(-width / 2, 0);
            r2.offset(-width / 2, -width);
        } else {
            r1.offset(0, -width / 2);
            r2.offset(-width, -width / 2);
        }
        SkPaint fillPaint;
        fillPaint.setColor(paint.getColor());
        platformContext()->canvas()->drawRect(r1, fillPaint);
        platformContext()->canvas()->drawRect(r2, fillPaint);
    }

    adjustLineToPixelBoundaries(p1, p2, width, penStyle);
    SkPoint pts[2] = { (SkPoint)p1, (SkPoint)p2 };

    platformContext()->canvas()->drawPoints(SkCanvas::kLines_PointMode, 2, pts, paint);
}
Example #27
0
SkARGB32_Blitter::SkARGB32_Blitter(const SkBitmap& device, const SkPaint& paint)
        : INHERITED(device) {
    uint32_t color = paint.getColor();

    fSrcA = SkColorGetA(color);
    unsigned scale = SkAlpha255To256(fSrcA);
    fSrcR = SkAlphaMul(SkColorGetR(color), scale);
    fSrcG = SkAlphaMul(SkColorGetG(color), scale);
    fSrcB = SkAlphaMul(SkColorGetB(color), scale);

    fPMColor = SkPackARGB32(fSrcA, fSrcR, fSrcG, fSrcB);
}
static void paintSkiaText(GraphicsContext* context, HFONT hfont,
                          SkTypeface* face, float size, uint32_t textFlags,
                          int numGlyphs,
                          const WORD* glyphs,
                          const int* advances,
                          const GOFFSET* offsets,
                          const SkPoint& origin,
                          const SkRect& textRect)
{
    TextDrawingModeFlags textMode = context->textDrawingMode();
    // Ensure font load for printing, because PDF device needs it.
    if (context->isPrintingDevice())
        FontPlatformData::ensureFontLoaded(hfont);

    // Filling (if necessary). This is the common case.
    SkPaint paint;
    context->setupPaintForFilling(&paint);
    paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
    setupPaintForFont(&paint, context, face, size, textFlags);

    bool didFill = false;

    if ((textMode & TextModeFill) && (SkColorGetA(paint.getColor()) || paint.getLooper())) {
        skiaDrawText(context, origin, textRect, &paint, &glyphs[0], &advances[0], &offsets[0], numGlyphs);
        didFill = true;
    }

    // Stroking on top (if necessary).
    if ((textMode & TextModeStroke)
        && context->strokeStyle() != NoStroke
        && context->strokeThickness() > 0) {

        paint.reset();
        context->setupPaintForStroking(&paint);
        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
        setupPaintForFont(&paint, context, face, size, textFlags);

        if (didFill) {
            // If there is a shadow and we filled above, there will already be
            // a shadow. We don't want to draw it again or it will be too dark
            // and it will go on top of the fill.
            //
            // Note that this isn't strictly correct, since the stroke could be
            // very thick and the shadow wouldn't account for this. The "right"
            // thing would be to draw to a new layer and then draw that layer
            // with a shadow. But this is a lot of extra work for something
            // that isn't normally an issue.
            paint.setLooper(0);
        }

        skiaDrawText(context, origin, textRect, &paint, &glyphs[0], &advances[0], &offsets[0], numGlyphs);
    }
}
 virtual const char* onGetName() {
     fName.printf("text_%g", SkScalarToFloat(fPaint.getTextSize()));
     if (fDoPos) {
         fName.append("_pos");
     }
     fName.appendf("_%s", fontQualityName(fPaint));
     if (SK_ColorBLACK != fPaint.getColor()) {
         fName.appendf("_%02X", fPaint.getAlpha());
     } else {
         fName.append("_BK");
     }
     return fName.c_str();
 }
Example #30
0
static bool drawNeedsLayer(const SkPaint& paint)
{
    if (SkColorGetA(paint.getColor()) < 255)
        return true;

    SkXfermode::Mode xfermode;
    if (SkXfermode::AsMode(paint.getXfermode(), &xfermode)) {
        if (xfermode != SkXfermode::kSrcOver_Mode)
            return true;
    }

    return false;
}