virtual void onDrawContent(SkCanvas* canvas) { const char* str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; SkPaint paint; SkScalar x = SkIntToScalar(10); SkScalar y = SkIntToScalar(20); paint.setFlags(0x105); paint.setARGB(fByte, 0xFF, 0xFF, 0xFF); paint.setMaskFilter(SkBlurMaskFilter::Create(SkIntToScalar(3), SkBlurMaskFilter::kNormal_BlurStyle)); paint.getMaskFilter()->unref(); SkRandom rand; for (int ps = 6; ps <= 35; ps++) { paint.setColor(rand.nextU() | (0xFF << 24)); paint.setTextSize(SkIntToScalar(ps)); paint.setTextSize(SkIntToScalar(24)); canvas->drawText(str, strlen(str), x, y, paint); y += paint.getFontMetrics(NULL); } if (false) { // avoid bit rot, suppress warning check_for_nonwhite(canvas->getDevice()->accessBitmap(false), fByte); SkDebugf("------ byte %x\n", fByte); } if (false) { fByte += 1; fByte &= 0xFF; this->inval(NULL); } }
static bool Supports(const SkPixmap& dst, const SkPixmap& src, const SkPaint& paint) { if (dst.colorType() != src.colorType()) { return false; } if (dst.info().profileType() != src.info().profileType()) { return false; } if (paint.getMaskFilter() || paint.getColorFilter() || paint.getImageFilter()) { return false; } if (0xFF != paint.getAlpha()) { return false; } SkXfermode::Mode mode; if (!SkXfermode::AsMode(paint.getXfermode(), &mode)) { return false; } if (SkXfermode::kSrc_Mode == mode) { return true; } if (SkXfermode::kSrcOver_Mode == mode && src.isOpaque()) { return true; } return false; }
bool GrDistanceFieldTextContext::canDraw(const SkPaint& paint, const SkMatrix& viewMatrix) { // TODO: support perspective (need getMaxScale replacement) if (viewMatrix.hasPerspective()) { return false; } SkScalar maxScale = viewMatrix.getMaxScale(); SkScalar scaledTextSize = maxScale*paint.getTextSize(); // Scaling up beyond 2x yields undesireable artifacts if (scaledTextSize > 2*kLargeDFFontSize) { return false; } if (!fEnableDFRendering && !paint.isDistanceFieldTextTEMP() && scaledTextSize < kLargeDFFontSize) { return false; } // rasterizers and mask filters modify alpha, which doesn't // translate well to distance if (paint.getRasterizer() || paint.getMaskFilter() || !fContext->getTextTarget()->caps()->shaderDerivativeSupport()) { return false; } // TODO: add some stroking support if (paint.getStyle() != SkPaint::kFill_Style) { return false; } return true; }
bool GrStencilAndCoverTextContext::canDraw(const GrRenderTarget* rt, const GrClip& clip, const GrPaint& paint, const SkPaint& skPaint, const SkMatrix& viewMatrix) { if (skPaint.getRasterizer()) { return false; } if (skPaint.getMaskFilter()) { return false; } if (SkPathEffect* pe = skPaint.getPathEffect()) { if (pe->asADash(NULL) != SkPathEffect::kDash_DashType) { return false; } } // No hairlines unless we can map the 1 px width to the object space. if (skPaint.getStyle() == SkPaint::kStroke_Style && skPaint.getStrokeWidth() == 0 && viewMatrix.hasPerspective()) { return false; } // No color bitmap fonts. SkScalerContext::Rec rec; SkScalerContext::MakeRec(skPaint, &fDeviceProperties, NULL, &rec); return rec.getFormat() != SkMask::kARGB32_Format; }
bool GrDistanceFieldTextContext::canDraw(const SkPaint& paint) { if (!fEnableDFRendering && !paint.isDistanceFieldTextTEMP()) { return false; } // rasterizers and mask filters modify alpha, which doesn't // translate well to distance if (paint.getRasterizer() || paint.getMaskFilter() || !fContext->getTextTarget()->caps()->shaderDerivativeSupport()) { return false; } // TODO: add some stroking support if (paint.getStyle() != SkPaint::kFill_Style) { return false; } // TODO: choose an appropriate maximum scale for distance fields and // enable perspective if (SkDraw::ShouldDrawTextAsPaths(paint, fContext->getMatrix())) { return false; } return true; }
static bool Supports(const SkPixmap& dst, const SkPixmap& src, const SkPaint& paint) { if (dst.colorType() != src.colorType()) { return false; } if (dst.info().gammaCloseToSRGB() != src.info().gammaCloseToSRGB()) { return false; } if (paint.getMaskFilter() || paint.getColorFilter() || paint.getImageFilter()) { return false; } if (0xFF != paint.getAlpha()) { return false; } SkBlendMode mode = paint.getBlendMode(); if (SkBlendMode::kSrc == mode) { return true; } if (SkBlendMode::kSrcOver == mode && src.isOpaque()) { return true; } // At this point memcpy can't be used. The following check for using SrcOver. if (dst.colorType() != kN32_SkColorType || !dst.info().gammaCloseToSRGB()) { return false; } return SkBlendMode::kSrcOver == mode; }
void GrBlurUtils::drawPathWithMaskFilter(GrContext* context, GrDrawContext* drawContext, const GrClip& clip, const SkPath& origPath, const SkPaint& paint, const SkMatrix& origViewMatrix, const SkMatrix* prePathMatrix, const SkIRect& clipBounds, bool pathIsMutable) { SkASSERT(!pathIsMutable || origPath.isVolatile()); GrStyle style(paint); // If we have a prematrix, apply it to the path, optimizing for the case // where the original path can in fact be modified in place (even though // its parameter type is const). const SkPath* path = &origPath; SkTLazy<SkPath> tmpPath; SkMatrix viewMatrix = origViewMatrix; if (prePathMatrix) { // Styling, blurs, and shading are supposed to be applied *after* the prePathMatrix. if (!paint.getMaskFilter() && !paint.getShader() && !style.applies()) { viewMatrix.preConcat(*prePathMatrix); } else { SkPath* result = pathIsMutable ? const_cast<SkPath*>(path) : tmpPath.init(); pathIsMutable = true; path->transform(*prePathMatrix, result); path = result; result->setIsVolatile(true); } } // at this point we're done with prePathMatrix SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
bool GrTextUtils::ShouldDisableLCD(const SkPaint& paint) { return !SkXfermode::AsMode(paint.getXfermode(), nullptr) || paint.getMaskFilter() || paint.getRasterizer() || paint.getPathEffect() || paint.isFakeBoldText() || paint.getStyle() != SkPaint::kFill_Style; }
static inline bool CanApplyDstMatrixAsCTM(const SkMatrix& m, const SkPaint& paint) { if (!paint.getMaskFilter()) { return true; } // Some mask filters parameters (sigma) depend on the CTM/scale. return m.getType() <= SkMatrix::kTranslate_Mask; }
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; }
// 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(); }
static bool HasAnyEffect(const SkPaint& paint) { return paint.getPathEffect() || paint.getShader() || paint.getXfermode() || paint.getMaskFilter() || paint.getColorFilter() || paint.getRasterizer() || paint.getLooper() || paint.getImageFilter(); }
static uint16_t compute_nondef(const SkPaint& paint, PaintUsage usage) { // kRespectsStroke_PaintUsage is only valid if other bits are also set SkASSERT(0 != (usage & ~kRespectsStroke_PaintUsage)); const SkScalar kTextSize_Default = 12; const SkScalar kTextScaleX_Default = 1; const SkScalar kTextSkewX_Default = 0; const SkScalar kStrokeWidth_Default = 0; const SkScalar kStrokeMiter_Default = 4; const SkColor kColor_Default = SK_ColorBLACK; unsigned bits = (paint.getColor() != kColor_Default) ? kColor_NonDef : 0; if (usage & kText_PaintUsage) { bits |= (paint.getTextSize() != kTextSize_Default ? kTextSize_NonDef : 0); bits |= (paint.getTextScaleX() != kTextScaleX_Default ? kTextScaleX_NonDef : 0); bits |= (paint.getTextSkewX() != kTextSkewX_Default ? kTextSkewX_NonDef : 0); bits |= (paint.getTypeface() ? kTypeface_NonDef : 0); } // TODO: kImage_PaintUsage only needs the shader/maskfilter IF its colortype is kAlpha_8 if (usage & (kVertices_PaintUsage | kDrawPaint_PaintUsage | kImage_PaintUsage | kText_PaintUsage | kGeometry_PaintUsage | kTextBlob_PaintUsage)) { bits |= (paint.getShader() ? kShader_NonDef : 0); } if (usage & (kText_PaintUsage | kGeometry_PaintUsage | kTextBlob_PaintUsage)) { bits |= (paint.getPathEffect() ? kPathEffect_NonDef : 0); bits |= (paint.getRasterizer() ? kRasterizer_NonDef : 0); if (paint.getStyle() != SkPaint::kFill_Style || (usage & kRespectsStroke_PaintUsage)) { bits |= (paint.getStrokeWidth() != kStrokeWidth_Default ? kStrokeWidth_NonDef : 0); bits |= (paint.getStrokeMiter() != kStrokeMiter_Default ? kStrokeMiter_NonDef : 0); } } if (usage & (kText_PaintUsage | kGeometry_PaintUsage | kImage_PaintUsage | kTextBlob_PaintUsage)) { bits |= (paint.getMaskFilter() ? kMaskFilter_NonDef : 0); } bits |= (paint.getColorFilter() ? kColorFilter_NonDef : 0); bits |= (paint.getImageFilter() ? kImageFilter_NonDef : 0); bits |= (paint.getDrawLooper() ? kDrawLooper_NonDef : 0); return SkToU16(bits); }
bool GrStencilAndCoverTextContext::internalCanDraw(const SkPaint& skPaint) { if (skPaint.getRasterizer()) { return false; } if (skPaint.getMaskFilter()) { return false; } if (SkPathEffect* pe = skPaint.getPathEffect()) { if (pe->asADash(nullptr) != SkPathEffect::kDash_DashType) { return false; } } // No hairlines. They would require new paths with customized strokes for every new draw matrix. return SkPaint::kStroke_Style != skPaint.getStyle() || 0 != skPaint.getStrokeWidth(); }
bool SkPaintPriv::ShouldDither(const SkPaint& p, SkColorType dstCT) { // The paint dither flag can veto. if (!p.isDither()) { return false; } // We always dither 565 or 4444 when requested. if (dstCT == kRGB_565_SkColorType || dstCT == kARGB_4444_SkColorType) { return true; } // Otherwise, dither is only needed for non-const paints. return p.getImageFilter() || p.getMaskFilter() || !p.getShader() || !as_SB(p.getShader())->isConstant(); }
void GrBlurUtils::drawPathWithMaskFilter(GrContext* context, GrDrawContext* drawContext, const GrClip& clip, const SkPath& origSrcPath, const SkPaint& paint, const SkMatrix& origViewMatrix, const SkMatrix* prePathMatrix, const SkIRect& clipBounds, bool pathIsMutable) { SkASSERT(!pathIsMutable || origSrcPath.isVolatile()); GrStrokeInfo strokeInfo(paint); // comment out the line below to determine if it is the reason that the chrome mac perf bot // has begun crashing // strokeInfo.setResScale(SkDraw::ComputeResScaleForStroking(origViewMatrix)); // If we have a prematrix, apply it to the path, optimizing for the case // where the original path can in fact be modified in place (even though // its parameter type is const). SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath); SkTLazy<SkPath> tmpPath; SkTLazy<SkPath> effectPath; SkPathEffect* pathEffect = paint.getPathEffect(); SkMatrix viewMatrix = origViewMatrix; if (prePathMatrix) { // stroking, path effects, and blurs are supposed to be applied *after* the prePathMatrix. // The pre-path-matrix also should not affect shading. if (!paint.getMaskFilter() && !pathEffect && !paint.getShader() && (strokeInfo.isFillStyle() || strokeInfo.isHairlineStyle())) { viewMatrix.preConcat(*prePathMatrix); } else { SkPath* result = pathPtr; if (!pathIsMutable) { result = tmpPath.init(); result->setIsVolatile(true); pathIsMutable = true; } // should I push prePathMatrix on our MV stack temporarily, instead // of applying it here? See SkDraw.cpp pathPtr->transform(*prePathMatrix, result); pathPtr = result; } } // at this point we're done with prePathMatrix SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
static bool Supports(const SkPixmap& dst, const SkPixmap& src, const SkPaint& paint) { if (dst.colorType() != src.colorType()) { return false; } if (!SkColorSpace::Equals(dst.colorSpace(), src.colorSpace())) { return false; } if (paint.getMaskFilter() || paint.getColorFilter() || paint.getImageFilter()) { return false; } if (0xFF != paint.getAlpha()) { return false; } SkBlendMode mode = paint.getBlendMode(); return SkBlendMode::kSrc == mode || (SkBlendMode::kSrcOver == mode && src.isOpaque()); }
static bool Supports(const SkPixmap& dst, const SkPixmap& src, const SkPaint& paint) { // the caller has already inspected the colorspace on src and dst SkASSERT(!SkColorSpaceXformSteps::Required(src.colorSpace(), dst.colorSpace())); if (dst.colorType() != src.colorType()) { return false; } if (paint.getMaskFilter() || paint.getColorFilter() || paint.getImageFilter()) { return false; } if (0xFF != paint.getAlpha()) { return false; } SkBlendMode mode = paint.getBlendMode(); return SkBlendMode::kSrc == mode || (SkBlendMode::kSrcOver == mode && src.isOpaque()); }
void SkBaseDevice::drawRegion(const SkDraw& draw, const SkRegion& region, const SkPaint& paint) { bool isNonTranslate = draw.fMatrix->getType() & ~(SkMatrix::kTranslate_Mask); bool complexPaint = paint.getStyle() != SkPaint::kFill_Style || paint.getMaskFilter() || paint.getPathEffect(); bool antiAlias = paint.isAntiAlias() && (!is_int(draw.fMatrix->getTranslateX()) || !is_int(draw.fMatrix->getTranslateY())); if (isNonTranslate || complexPaint || antiAlias) { SkPath path; region.getBoundaryPath(&path); return this->drawPath(draw, path, paint, nullptr, false); } SkRegion::Iterator it(region); while (!it.done()) { this->drawRect(draw, SkRect::Make(it.rect()), paint); it.next(); } }
static void paint_write(const SkPaint& paint, SkFlattenableWriteBuffer& buffer) { buffer.writeBool(paint.isAntiAlias()); buffer.write8(paint.getStyle()); buffer.write8(paint.getAlpha()); if (paint.getStyle() != SkPaint::kFill_Style) { buffer.writeScalar(paint.getStrokeWidth()); buffer.writeScalar(paint.getStrokeMiter()); buffer.write8(paint.getStrokeCap()); buffer.write8(paint.getStrokeJoin()); } buffer.writeFlattenable(paint.getMaskFilter()); buffer.writeFlattenable(paint.getPathEffect()); buffer.writeFlattenable(paint.getRasterizer()); buffer.writeFlattenable(paint.getXfermode()); }
static void apply_paint_maskfilter(const SkPaint& paint, Json::Value* target, bool sendBinaries) { SkMaskFilter* maskFilter = paint.getMaskFilter(); if (maskFilter != nullptr) { SkMaskFilter::BlurRec blurRec; if (maskFilter->asABlur(&blurRec)) { Json::Value blur(Json::objectValue); blur[SKJSONCANVAS_ATTRIBUTE_SIGMA] = Json::Value(blurRec.fSigma); switch (blurRec.fStyle) { case SkBlurStyle::kNormal_SkBlurStyle: blur[SKJSONCANVAS_ATTRIBUTE_STYLE] = Json::Value(SKJSONCANVAS_BLURSTYLE_NORMAL); break; case SkBlurStyle::kSolid_SkBlurStyle: blur[SKJSONCANVAS_ATTRIBUTE_STYLE] = Json::Value(SKJSONCANVAS_BLURSTYLE_SOLID); break; case SkBlurStyle::kOuter_SkBlurStyle: blur[SKJSONCANVAS_ATTRIBUTE_STYLE] = Json::Value(SKJSONCANVAS_BLURSTYLE_OUTER); break; case SkBlurStyle::kInner_SkBlurStyle: blur[SKJSONCANVAS_ATTRIBUTE_STYLE] = Json::Value(SKJSONCANVAS_BLURSTYLE_INNER); break; default: SkASSERT(false); } switch (blurRec.fQuality) { case SkBlurQuality::kLow_SkBlurQuality: blur[SKJSONCANVAS_ATTRIBUTE_QUALITY] = Json::Value(SKJSONCANVAS_BLURQUALITY_LOW); break; case SkBlurQuality::kHigh_SkBlurQuality: blur[SKJSONCANVAS_ATTRIBUTE_QUALITY] = Json::Value(SKJSONCANVAS_BLURQUALITY_HIGH); break; default: SkASSERT(false); } (*target)[SKJSONCANVAS_ATTRIBUTE_BLUR] = blur; } else { Json::Value jsonMaskFilter; flatten(maskFilter, &jsonMaskFilter, sendBinaries); (*target)[SKJSONCANVAS_ATTRIBUTE_MASKFILTER] = jsonMaskFilter; } } }
// 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; }
bool GrTextUtils::CanDrawAsDistanceFields(const SkPaint& skPaint, const SkMatrix& viewMatrix, const SkSurfaceProps& props, const GrShaderCaps& caps) { // TODO: support perspective (need getMaxScale replacement) if (viewMatrix.hasPerspective()) { return false; } SkScalar maxScale = viewMatrix.getMaxScale(); SkScalar scaledTextSize = maxScale*skPaint.getTextSize(); // Hinted text looks far better at small resolutions // Scaling up beyond 2x yields undesireable artifacts if (scaledTextSize < kMinDFFontSize || scaledTextSize > kLargeDFFontLimit) { return false; } bool useDFT = props.isUseDeviceIndependentFonts(); #if SK_FORCE_DISTANCE_FIELD_TEXT useDFT = true; #endif if (!useDFT && scaledTextSize < kLargeDFFontSize) { return false; } // rasterizers and mask filters modify alpha, which doesn't // translate well to distance if (skPaint.getRasterizer() || skPaint.getMaskFilter() || !caps.shaderDerivativeSupport()) { return false; } // TODO: add some stroking support if (skPaint.getStyle() != SkPaint::kFill_Style) { return false; } return true; }
bool GrStencilAndCoverTextContext::canDraw(const SkPaint& paint) { if (paint.getRasterizer()) { return false; } if (paint.getMaskFilter()) { return false; } if (paint.getPathEffect()) { return false; } // No hairlines unless we can map the 1 px width to the object space. if (paint.getStyle() == SkPaint::kStroke_Style && paint.getStrokeWidth() == 0 && fContext->getMatrix().hasPerspective()) { return false; } // No color bitmap fonts. SkScalerContext::Rec rec; SkScalerContext::MakeRec(paint, &fDeviceProperties, NULL, &rec); return rec.getFormat() != SkMask::kARGB32_Format; }
bool SkDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) { if (!paint.isLCDRenderText()) { // we're cool with the paint as is return false; } if (SkBitmap::kARGB_8888_Config != fBitmap.config() || paint.getShader() || paint.getXfermode() || // unless its srcover paint.getMaskFilter() || paint.getRasterizer() || paint.getColorFilter() || paint.getPathEffect() || paint.isFakeBoldText() || paint.getStyle() != SkPaint::kFill_Style) { // turn off lcd flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag; flags->fHinting = paint.getHinting(); return true; } // we're cool with the paint as is return false; }
bool GrTextContext::CanDrawAsDistanceFields(const SkPaint& paint, const SkFont& font, const SkMatrix& viewMatrix, const SkSurfaceProps& props, bool contextSupportsDistanceFieldText, const Options& options) { if (!viewMatrix.hasPerspective()) { SkScalar maxScale = viewMatrix.getMaxScale(); SkScalar scaledTextSize = maxScale * font.getSize(); // Hinted text looks far better at small resolutions // Scaling up beyond 2x yields undesireable artifacts if (scaledTextSize < options.fMinDistanceFieldFontSize || scaledTextSize > options.fMaxDistanceFieldFontSize) { return false; } bool useDFT = props.isUseDeviceIndependentFonts(); #if SK_FORCE_DISTANCE_FIELD_TEXT useDFT = true; #endif if (!useDFT && scaledTextSize < kLargeDFFontSize) { return false; } } // mask filters modify alpha, which doesn't translate well to distance if (paint.getMaskFilter() || !contextSupportsDistanceFieldText) { return false; } // TODO: add some stroking support if (paint.getStyle() != SkPaint::kFill_Style) { return false; } return true; }
void onDrawContent(SkCanvas* canvas) override { const char* str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; SkPaint paint; SkScalar x = SkIntToScalar(10); SkScalar y = SkIntToScalar(20); paint.setFlags(0x105); paint.setARGB(fByte, 0xFF, 0xFF, 0xFF); paint.setMaskFilter(SkBlurMaskFilter::Create(kNormal_SkBlurStyle, SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(3)))); paint.getMaskFilter()->unref(); SkRandom rand; for (int ps = 6; ps <= 35; ps++) { paint.setColor(rand.nextU() | (0xFF << 24)); paint.setTextSize(SkIntToScalar(ps)); paint.setTextSize(SkIntToScalar(24)); canvas->drawText(str, strlen(str), x, y, paint); y += paint.getFontMetrics(nullptr); } }
void SkPDFDevice::updateGSFromPaint(const SkPaint& paint, bool forText) { SkASSERT(paint.getPathEffect() == NULL); NOT_IMPLEMENTED(paint.getMaskFilter() != NULL, false); NOT_IMPLEMENTED(paint.getColorFilter() != NULL, false); SkPaint newPaint = paint; // PDF treats a shader as a color, so we only set one or the other. SkRefPtr<SkPDFShader> pdfShader; const SkShader* shader = newPaint.getShader(); if (shader) { // PDF positions patterns relative to the initial transform, so // we need to apply the current transform to the shader parameters. SkMatrix transform = fGraphicStack[fGraphicStackIndex].fTransform; if (fFlipOrigin == kFlip_OriginTransform) { transform.postScale(1, -1); transform.postTranslate(0, fHeight); } // PDF doesn't support kClamp_TileMode, so we simulate it by making // a pattern the size of the drawing service. SkIRect bounds = fGraphicStack[fGraphicStackIndex].fClip.getBounds(); pdfShader = SkPDFShader::getPDFShader(*shader, transform, bounds); SkSafeUnref(pdfShader.get()); // getShader and SkRefPtr both took a ref // A color shader is treated as an invalid shader so we don't have // to set a shader just for a color. if (pdfShader.get() == NULL) { newPaint.setColor(0); // Check for a color shader. SkShader::GradientInfo gradientInfo; SkColor gradientColor; gradientInfo.fColors = &gradientColor; gradientInfo.fColorOffsets = NULL; gradientInfo.fColorCount = 1; if (shader->asAGradient(&gradientInfo) == SkShader::kColor_GradientType) { newPaint.setColor(gradientColor); } } } if (pdfShader) { // pdfShader has been canonicalized so we can directly compare // pointers. if (fGraphicStack[fGraphicStackIndex].fShader != pdfShader.get()) { int resourceIndex = fShaderResources.find(pdfShader.get()); if (resourceIndex < 0) { resourceIndex = fShaderResources.count(); fShaderResources.push(pdfShader.get()); pdfShader->ref(); } fContent.writeText("/Pattern CS /Pattern cs /P"); fContent.writeDecAsText(resourceIndex); fContent.writeText(" SCN /P"); fContent.writeDecAsText(resourceIndex); fContent.writeText(" scn\n"); fGraphicStack[fGraphicStackIndex].fShader = pdfShader.get(); } } else { SkColor newColor = newPaint.getColor(); newColor = SkColorSetA(newColor, 0xFF); if (fGraphicStack[fGraphicStackIndex].fShader || fGraphicStack[fGraphicStackIndex].fColor != newColor) { emitPDFColor(newColor, &fContent); fContent.writeText("RG "); emitPDFColor(newColor, &fContent); fContent.writeText("rg\n"); fGraphicStack[fGraphicStackIndex].fColor = newColor; fGraphicStack[fGraphicStackIndex].fShader = NULL; } } SkRefPtr<SkPDFGraphicState> newGraphicState = SkPDFGraphicState::getGraphicStateForPaint(newPaint); newGraphicState->unref(); // getGraphicState and SkRefPtr both took a ref. // newGraphicState has been canonicalized so we can directly compare // pointers. if (fGraphicStack[fGraphicStackIndex].fGraphicState != newGraphicState.get()) { int resourceIndex = fGraphicStateResources.find(newGraphicState.get()); if (resourceIndex < 0) { resourceIndex = fGraphicStateResources.count(); fGraphicStateResources.push(newGraphicState.get()); newGraphicState->ref(); } fContent.writeText("/G"); fContent.writeDecAsText(resourceIndex); fContent.writeText(" gs\n"); fGraphicStack[fGraphicStackIndex].fGraphicState = newGraphicState.get(); } if (forText) { if (fGraphicStack[fGraphicStackIndex].fTextScaleX != newPaint.getTextScaleX()) { SkScalar scale = newPaint.getTextScaleX(); SkScalar pdfScale = SkScalarMul(scale, SkIntToScalar(100)); SkPDFScalar::Append(pdfScale, &fContent); fContent.writeText(" Tz\n"); fGraphicStack[fGraphicStackIndex].fTextScaleX = scale; } if (fGraphicStack[fGraphicStackIndex].fTextFill != newPaint.getStyle()) { SK_COMPILE_ASSERT(SkPaint::kFill_Style == 0, enum_must_match_value); SK_COMPILE_ASSERT(SkPaint::kStroke_Style == 1, enum_must_match_value); SK_COMPILE_ASSERT(SkPaint::kStrokeAndFill_Style == 2, enum_must_match_value); fContent.writeDecAsText(newPaint.getStyle()); fContent.writeText(" Tr\n"); fGraphicStack[fGraphicStackIndex].fTextFill = newPaint.getStyle(); } } }
// 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 }
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); }