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; }
void GrStencilAndCoverTextContext::drawTextBlob(GrContext* context, GrRenderTargetContext* rtc, const GrClip& clip, const SkPaint& skPaint, const SkMatrix& viewMatrix, const SkSurfaceProps& props, const SkTextBlob* skBlob, SkScalar x, SkScalar y, SkDrawFilter* drawFilter, const SkIRect& clipBounds) { if (context->abandoned()) { return; } if (!this->internalCanDraw(skPaint)) { fFallbackTextContext->drawTextBlob(context, rtc, clip, skPaint, viewMatrix, props, skBlob, x, y, drawFilter, clipBounds); return; } if (drawFilter || skPaint.getPathEffect()) { // This draw can't be cached. this->uncachedDrawTextBlob(context, rtc, clip, skPaint, viewMatrix, props, skBlob, x, y, drawFilter, clipBounds); return; } const TextBlob& blob = this->findOrCreateTextBlob(skBlob, skPaint); TextBlob::Iter iter(blob); for (TextRun *run = iter.get(), *nextRun; run; run = nextRun) { nextRun = iter.next(); run->draw(context, rtc, clip, viewMatrix, props, x, y, clipBounds, fFallbackTextContext, skPaint); run->releaseGlyphCache(); } }
static void apply_paint_patheffect(const SkPaint& paint, Json::Value* target, bool sendBinaries) { SkPathEffect* pathEffect = paint.getPathEffect(); if (pathEffect != nullptr) { SkPathEffect::DashInfo dashInfo; SkPathEffect::DashType dashType = pathEffect->asADash(&dashInfo); if (dashType == SkPathEffect::kDash_DashType) { dashInfo.fIntervals = (SkScalar*) sk_malloc_throw(dashInfo.fCount * sizeof(SkScalar)); pathEffect->asADash(&dashInfo); Json::Value dashing(Json::objectValue); Json::Value intervals(Json::arrayValue); for (int32_t i = 0; i < dashInfo.fCount; i++) { intervals.append(Json::Value(dashInfo.fIntervals[i])); } free(dashInfo.fIntervals); dashing[SKJSONCANVAS_ATTRIBUTE_INTERVALS] = intervals; dashing[SKJSONCANVAS_ATTRIBUTE_PHASE] = dashInfo.fPhase; (*target)[SKJSONCANVAS_ATTRIBUTE_DASHING] = dashing; } else { Json::Value jsonPathEffect; flatten(pathEffect, &jsonPathEffect, sendBinaries); (*target)[SKJSONCANVAS_ATTRIBUTE_PATHEFFECT] = jsonPathEffect; } } }
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; }
void SkBaseDevice::drawArc(const SkDraw& draw, const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool useCenter, const SkPaint& paint) { SkPath path; bool isFillNoPathEffect = SkPaint::kFill_Style == paint.getStyle() && !paint.getPathEffect(); SkPathPriv::CreateDrawArcPath(&path, oval, startAngle, sweepAngle, useCenter, isFillNoPathEffect); this->drawPath(draw, path, paint); }
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(); }
bool SkBitmapDevice::onShouldDisableLCD(const SkPaint& paint) const { if (kN32_SkColorType != fBitmap.colorType() || paint.getRasterizer() || paint.getPathEffect() || paint.isFakeBoldText() || paint.getStyle() != SkPaint::kFill_Style || !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) { return true; } return false; }
void GrTextUtils::DrawPosTextAsPath(GrContext* context, GrDrawContext* dc, const SkSurfaceProps& props, const GrClip& clip, const SkPaint& origPaint, const SkMatrix& viewMatrix, const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset, const SkIRect& clipBounds) { // setup our std paint, in hopes of getting hits in the cache SkPaint paint(origPaint); SkScalar matrixScale = paint.setupForAsPaths(); SkMatrix matrix; matrix.setScale(matrixScale, matrixScale); // Temporarily jam in kFill, so we only ever ask for the raw outline from the cache. paint.setStyle(SkPaint::kFill_Style); paint.setPathEffect(nullptr); SkPaint::GlyphCacheProc glyphCacheProc = paint.getGlyphCacheProc(true); SkAutoGlyphCache autoCache(paint, &props, nullptr); SkGlyphCache* cache = autoCache.getCache(); const char* stop = text + byteLength; SkTextAlignProc alignProc(paint.getTextAlign()); SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); // Now restore the original settings, so we "draw" with whatever style/stroking. paint.setStyle(origPaint.getStyle()); paint.setPathEffect(origPaint.getPathEffect()); while (text < stop) { const SkGlyph& glyph = glyphCacheProc(cache, &text); if (glyph.fWidth) { const SkPath* path = cache->findPath(glyph); if (path) { SkPoint tmsLoc; tmsProc(pos, &tmsLoc); SkPoint loc; alignProc(tmsLoc, glyph, &loc); matrix[SkMatrix::kMTransX] = loc.fX; matrix[SkMatrix::kMTransY] = loc.fY; GrBlurUtils::drawPathWithMaskFilter(context, dc, clip, *path, paint, viewMatrix, &matrix, clipBounds, false); } } pos += scalarsPerPosition; } }
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(); }
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;)
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()); }
void SkPDFDevice::drawPath(const SkDraw& d, const SkPath& path, const SkPaint& paint, const SkMatrix* prePathMatrix, bool pathIsMutable) { NOT_IMPLEMENTED(prePathMatrix != NULL, true); if (paint.getPathEffect()) { // Apply the path effect to path and draw it that way. SkPath noEffectPath; paint.getFillPath(path, &noEffectPath); SkPaint noEffectPaint(paint); SkSafeUnref(noEffectPaint.setPathEffect(NULL)); drawPath(d, noEffectPath, noEffectPaint, NULL, true); return; } updateGSFromPaint(paint, false); SkPDFUtils::EmitPath(path, &fContent); SkPDFUtils::PaintPath(paint.getStyle(), path.getFillType(), &fContent); }
bool SkBitmapDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) { if (!paint.isLCDRenderText() || !paint.isAntiAlias()) { // we're cool with the paint as is return false; } if (kN32_SkColorType != fBitmap.colorType() || paint.getRasterizer() || paint.getPathEffect() || paint.isFakeBoldText() || paint.getStyle() != SkPaint::kFill_Style || !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) { // 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; }
void GrStencilAndCoverTextContext::drawTextBlob(GrContext* context, GrDrawContext* dc, const GrClip& clip, const SkPaint& skPaint, const SkMatrix& viewMatrix, const SkSurfaceProps& props, const SkTextBlob* skBlob, SkScalar x, SkScalar y, SkDrawFilter* drawFilter, const SkIRect& clipBounds) { if (context->abandoned()) { return; } if (!this->internalCanDraw(skPaint)) { fFallbackTextContext->drawTextBlob(context, dc, clip, skPaint, viewMatrix, props, skBlob, x, y, drawFilter, clipBounds); return; } if (drawFilter || skPaint.getPathEffect()) { // This draw can't be cached. this->uncachedDrawTextBlob(context, dc, clip, skPaint, viewMatrix, props, skBlob, x, y, drawFilter, clipBounds); return; } GrPaint paint; if (!SkPaintToGrPaint(context, dc, skPaint, viewMatrix, &paint)) { return; } const TextBlob& blob = this->findOrCreateTextBlob(skBlob, skPaint); TextBlob::Iter iter(blob); for (TextRun* run = iter.get(); run; run = iter.next()) { // The run's "font" overrides the anti-aliasing of the passed in paint! paint.setAntiAlias(run->isAntiAlias()); run->draw(context, dc, paint, clip, viewMatrix, props, x, y, clipBounds, fFallbackTextContext, skPaint); run->releaseGlyphCache(); } }
void SkPDFDevice::drawRect(const SkDraw& d, const SkRect& r, const SkPaint& paint) { if (paint.getPathEffect()) { // Create a path for the rectangle and apply the path effect to it. SkPath path; path.addRect(r); paint.getFillPath(path, &path); SkPaint noEffectPaint(paint); SkSafeUnref(noEffectPaint.setPathEffect(NULL)); drawPath(d, path, noEffectPaint, NULL, true); return; } updateGSFromPaint(paint, false); // Skia has 0,0 at top left, pdf at bottom left. Do the right thing. SkScalar bottom = r.fBottom < r.fTop ? r.fBottom : r.fTop; SkPDFUtils::AppendRectangle(r.fLeft, bottom, r.width(), r.height(), &fContent); SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType, &fContent); }
void GrStencilAndCoverTextContext::drawTextBlob(GrContext* context, GrDrawContext* dc, const GrClip& clip, const SkPaint& skPaint, const SkMatrix& viewMatrix, const SkSurfaceProps& props, const SkTextBlob* skBlob, SkScalar x, SkScalar y, SkDrawFilter* drawFilter, const SkIRect& clipBounds) { if (context->abandoned()) { return; } if (!this->internalCanDraw(skPaint)) { fFallbackTextContext->drawTextBlob(context, dc, clip, skPaint, viewMatrix, props, skBlob, x, y, drawFilter, clipBounds); return; } if (drawFilter || skPaint.getPathEffect()) { // This draw can't be cached. this->uncachedDrawTextBlob(context, dc, clip, skPaint, viewMatrix, props, skBlob, x, y, drawFilter, clipBounds); return; } GrPaint paint; if (!SkPaintToGrPaint(context, skPaint, viewMatrix, dc->isGammaCorrect(), &paint)) { return; } const TextBlob& blob = this->findOrCreateTextBlob(skBlob, skPaint); GrPipelineBuilder pipelineBuilder(paint, dc->accessRenderTarget(), clip); TextBlob::Iter iter(blob); for (TextRun* run = iter.get(); run; run = iter.next()) { run->draw(context, dc, &pipelineBuilder, paint.getColor(), viewMatrix, props, x, y, clipBounds, fFallbackTextContext, skPaint); run->releaseGlyphCache(); } }
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; }
void GrStencilAndCoverTextContext::drawTextBlob(GrDrawContext* dc, GrRenderTarget* rt, const GrClip& clip, const SkPaint& skPaint, const SkMatrix& viewMatrix, const SkTextBlob* skBlob, SkScalar x, SkScalar y, SkDrawFilter* drawFilter, const SkIRect& clipBounds) { if (!this->internalCanDraw(skPaint)) { fFallbackTextContext->drawTextBlob(dc, rt, clip, skPaint, viewMatrix, skBlob, x, y, drawFilter, clipBounds); return; } if (drawFilter || skPaint.getPathEffect()) { // This draw can't be cached. INHERITED::drawTextBlob(dc, rt, clip, skPaint, viewMatrix, skBlob, x, y, drawFilter, clipBounds); return; } if (fContext->abandoned()) { return; } GrPaint paint; if (!SkPaintToGrPaint(fContext, skPaint, viewMatrix, &paint)) { return; } const TextBlob& blob = this->findOrCreateTextBlob(skBlob, skPaint); GrPipelineBuilder pipelineBuilder(paint, rt, clip); TextBlob::Iter iter(blob); for (TextRun* run = iter.get(); run; run = iter.next()) { run->draw(dc, &pipelineBuilder, paint.getColor(), viewMatrix, x, y, clipBounds, fFallbackTextContext, skPaint); } }
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(); } } }
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); }
// 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 }