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); }
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; }
static bool HasAnyEffect(const SkPaint& paint) { return paint.getPathEffect() || paint.getShader() || paint.getXfermode() || paint.getMaskFilter() || paint.getColorFilter() || paint.getRasterizer() || paint.getLooper() || paint.getImageFilter(); }
// Is the supplied paint simply a color? static bool is_simple(const SkPaint& p) { return NULL == p.getPathEffect() && NULL == p.getShader() && NULL == p.getXfermode() && NULL == p.getMaskFilter() && NULL == p.getColorFilter() && NULL == p.getRasterizer() && NULL == p.getLooper() && NULL == p.getImageFilter(); }
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); } }
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); } }
// Returns true if all pixels painted will be opaque. static inline bool paintIsOpaque(const SkPaint& paint, const SkBitmap* bitmap = 0, bool checkFillOnly = false) { if (paint.getAlpha() < 0xFF) return false; if (!checkFillOnly && paint.getStyle() != SkPaint::kFill_Style && paint.isAntiAlias()) return false; SkShader* shader = paint.getShader(); if (shader && !shader->isOpaque()) return false; if (bitmap && !bitmap->isOpaque()) return false; if (paint.getLooper()) return false; if (paint.getImageFilter()) return false; if (paint.getMaskFilter()) return false; SkColorFilter* colorFilter = paint.getColorFilter(); if (colorFilter && !(colorFilter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag)) return false; return true; }
// Even with kEntirePaint_Bits, we always ensure that the master paint's // text-encoding is respected, since that controls how we interpret the // text/length parameters of a draw[Pos]Text call. void SkLayerDrawLooper::ApplyInfo(SkPaint* dst, const SkPaint& src, const LayerInfo& info) { uint32_t mask = info.fFlagsMask; dst->setFlags((dst->getFlags() & ~mask) | (src.getFlags() & mask)); dst->setColor(xferColor(src.getColor(), dst->getColor(), info.fColorMode)); BitFlags bits = info.fPaintBits; SkPaint::TextEncoding encoding = dst->getTextEncoding(); if (0 == bits) { return; } if (kEntirePaint_Bits == bits) { // we've already computed these, so save it from the assignment uint32_t f = dst->getFlags(); SkColor c = dst->getColor(); *dst = src; dst->setFlags(f); dst->setColor(c); dst->setTextEncoding(encoding); return; } if (bits & kStyle_Bit) { dst->setStyle(src.getStyle()); dst->setStrokeWidth(src.getStrokeWidth()); dst->setStrokeMiter(src.getStrokeMiter()); dst->setStrokeCap(src.getStrokeCap()); dst->setStrokeJoin(src.getStrokeJoin()); } if (bits & kTextSkewX_Bit) { dst->setTextSkewX(src.getTextSkewX()); } if (bits & kPathEffect_Bit) { dst->setPathEffect(src.getPathEffect()); } if (bits & kMaskFilter_Bit) { dst->setMaskFilter(src.getMaskFilter()); } if (bits & kShader_Bit) { dst->setShader(src.getShader()); } if (bits & kColorFilter_Bit) { dst->setColorFilter(src.getColorFilter()); } if (bits & kXfermode_Bit) { dst->setXfermode(src.getXfermode()); } // we don't override these #if 0 dst->setTypeface(src.getTypeface()); dst->setTextSize(src.getTextSize()); dst->setTextScaleX(src.getTextScaleX()); dst->setRasterizer(src.getRasterizer()); dst->setLooper(src.getLooper()); dst->setTextEncoding(src.getTextEncoding()); dst->setHinting(src.getHinting()); #endif }
// Even with kEntirePaint_Bits, we always ensure that the master paint's // text-encoding is respected, since that controls how we interpret the // text/length parameters of a draw[Pos]Text call. void SkLayerDrawLooper::LayerDrawLooperContext::ApplyInfo( SkPaint* dst, const SkPaint& src, const LayerInfo& info) { SkColor4f srcColor = src.getColor4f(); #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK // The framework may respect the alpha value on the original paint. // Match this legacy behavior. if (src.getAlpha() == 255) { srcColor.fA = dst->getColor4f().fA; } #endif dst->setColor4f(xferColor(srcColor, dst->getColor4f(), (SkBlendMode)info.fColorMode), sk_srgb_singleton()); BitFlags bits = info.fPaintBits; SkPaint::TextEncoding encoding = dst->getTextEncoding(); if (0 == bits) { return; } if (kEntirePaint_Bits == bits) { // we've already computed these, so save it from the assignment uint32_t f = dst->getFlags(); SkColor4f c = dst->getColor4f(); *dst = src; dst->setFlags(f); dst->setColor4f(c, sk_srgb_singleton()); dst->setTextEncoding(encoding); return; } if (bits & kStyle_Bit) { dst->setStyle(src.getStyle()); dst->setStrokeWidth(src.getStrokeWidth()); dst->setStrokeMiter(src.getStrokeMiter()); dst->setStrokeCap(src.getStrokeCap()); dst->setStrokeJoin(src.getStrokeJoin()); } if (bits & kTextSkewX_Bit) { dst->setTextSkewX(src.getTextSkewX()); } if (bits & kPathEffect_Bit) { dst->setPathEffect(src.refPathEffect()); } if (bits & kMaskFilter_Bit) { dst->setMaskFilter(src.refMaskFilter()); } if (bits & kShader_Bit) { dst->setShader(src.refShader()); } if (bits & kColorFilter_Bit) { dst->setColorFilter(src.refColorFilter()); } if (bits & kXfermode_Bit) { dst->setBlendMode(src.getBlendMode()); } // we don't override these #if 0 dst->setTypeface(src.getTypeface()); dst->setTextSize(src.getTextSize()); dst->setTextScaleX(src.getTextScaleX()); dst->setRasterizer(src.getRasterizer()); dst->setLooper(src.getLooper()); dst->setTextEncoding(src.getTextEncoding()); dst->setHinting(src.getHinting()); #endif }
void SkFlatPaint::dump() const { SkPaint defaultPaint; SkFlattenableReadBuffer buffer(fPaintData); SkTypeface* typeface = (SkTypeface*) buffer.readPtr(); char pBuffer[DUMP_BUFFER_SIZE]; char* bufferPtr = pBuffer; bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer), "paint: "); if (typeface != defaultPaint.getTypeface()) bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer), "typeface:%p ", typeface); SkScalar textSize = buffer.readScalar(); if (textSize != defaultPaint.getTextSize()) bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer), "textSize:%g ", SkScalarToFloat(textSize)); SkScalar textScaleX = buffer.readScalar(); if (textScaleX != defaultPaint.getTextScaleX()) bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer), "textScaleX:%g ", SkScalarToFloat(textScaleX)); SkScalar textSkewX = buffer.readScalar(); if (textSkewX != defaultPaint.getTextSkewX()) bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer), "textSkewX:%g ", SkScalarToFloat(textSkewX)); const SkPathEffect* pathEffect = (const SkPathEffect*) buffer.readFlattenable(); if (pathEffect != defaultPaint.getPathEffect()) bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer), "pathEffect:%p ", pathEffect); SkDELETE(pathEffect); const SkShader* shader = (const SkShader*) buffer.readFlattenable(); if (shader != defaultPaint.getShader()) bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer), "shader:%p ", shader); SkDELETE(shader); const SkXfermode* xfermode = (const SkXfermode*) buffer.readFlattenable(); if (xfermode != defaultPaint.getXfermode()) bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer), "xfermode:%p ", xfermode); SkDELETE(xfermode); const SkMaskFilter* maskFilter = (const SkMaskFilter*) buffer.readFlattenable(); if (maskFilter != defaultPaint.getMaskFilter()) bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer), "maskFilter:%p ", maskFilter); SkDELETE(maskFilter); const SkColorFilter* colorFilter = (const SkColorFilter*) buffer.readFlattenable(); if (colorFilter != defaultPaint.getColorFilter()) bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer), "colorFilter:%p ", colorFilter); SkDELETE(colorFilter); const SkRasterizer* rasterizer = (const SkRasterizer*) buffer.readFlattenable(); if (rasterizer != defaultPaint.getRasterizer()) bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer), "rasterizer:%p ", rasterizer); SkDELETE(rasterizer); const SkDrawLooper* drawLooper = (const SkDrawLooper*) buffer.readFlattenable(); if (drawLooper != defaultPaint.getLooper()) bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer), "drawLooper:%p ", drawLooper); SkDELETE(drawLooper); unsigned color = buffer.readU32(); if (color != defaultPaint.getColor()) bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer), "color:0x%x ", color); SkScalar strokeWidth = buffer.readScalar(); if (strokeWidth != defaultPaint.getStrokeWidth()) bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer), "strokeWidth:%g ", SkScalarToFloat(strokeWidth)); SkScalar strokeMiter = buffer.readScalar(); if (strokeMiter != defaultPaint.getStrokeMiter()) bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer), "strokeMiter:%g ", SkScalarToFloat(strokeMiter)); unsigned flags = buffer.readU16(); if (flags != defaultPaint.getFlags()) bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer), "flags:0x%x ", flags); int align = buffer.readU8(); if (align != defaultPaint.getTextAlign()) bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer), "align:0x%x ", align); int strokeCap = buffer.readU8(); if (strokeCap != defaultPaint.getStrokeCap()) bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer), "strokeCap:0x%x ", strokeCap); int strokeJoin = buffer.readU8(); if (strokeJoin != defaultPaint.getStrokeJoin()) bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer), "align:0x%x ", strokeJoin); int style = buffer.readU8(); if (style != defaultPaint.getStyle()) bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer), "style:0x%x ", style); int textEncoding = buffer.readU8(); if (textEncoding != defaultPaint.getTextEncoding()) bufferPtr += snprintf(bufferPtr, DUMP_BUFFER_SIZE - (bufferPtr - pBuffer), "textEncoding:0x%x ", textEncoding); SkDebugf("%s\n", pBuffer); }