// found and fixed for webkit: mishandling when we hit recursion limit on // mostly degenerate cubic flatness test DEF_TEST(Paint_regression_cubic, reporter) { SkPath path, stroke; SkPaint paint; path.moveTo(460.2881309415525f, 303.250847066498f); path.cubicTo(463.36378422175284f, 302.1169735073363f, 456.32239330810046f, 304.720354932878f, 453.15255460013304f, 305.788586869862f); SkRect fillR, strokeR; fillR = path.getBounds(); paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(SkIntToScalar(2)); paint.getFillPath(path, &stroke); strokeR = stroke.getBounds(); SkRect maxR = fillR; SkScalar miter = SkMaxScalar(SK_Scalar1, paint.getStrokeMiter()); SkScalar inset = paint.getStrokeJoin() == SkPaint::kMiter_Join ? SkScalarMul(paint.getStrokeWidth(), miter) : paint.getStrokeWidth(); maxR.inset(-inset, -inset); // test that our stroke didn't explode REPORTER_ASSERT(reporter, maxR.contains(strokeR)); }
void SkStrokeRec::init(const SkPaint& paint, SkPaint::Style style) { switch (style) { case SkPaint::kFill_Style: fWidth = kStrokeRec_FillStyleWidth; fStrokeAndFill = false; break; case SkPaint::kStroke_Style: fWidth = paint.getStrokeWidth(); fStrokeAndFill = false; break; case SkPaint::kStrokeAndFill_Style: if (0 == paint.getStrokeWidth()) { // hairline+fill == fill fWidth = kStrokeRec_FillStyleWidth; fStrokeAndFill = false; } else { fWidth = paint.getStrokeWidth(); fStrokeAndFill = true; } break; default: SkDEBUGFAIL("unknown paint style"); // fall back on just fill fWidth = kStrokeRec_FillStyleWidth; fStrokeAndFill = false; break; } // copy these from the paint, regardless of our "style" fMiterLimit = paint.getStrokeMiter(); fCap = paint.getStrokeCap(); fJoin = paint.getStrokeJoin(); }
virtual void handlePath(SkCanvas* canvas, const SkPath& path, const SkPaint& paint, int N) override { SkPoint pts[2]; if (!path.isLine(pts) || pts[0].fY != pts[1].fY) { this->INHERITED::handlePath(canvas, path, paint, N); } else { SkRect rect; rect.fLeft = pts[0].fX; rect.fTop = pts[0].fY - paint.getStrokeWidth() / 2; rect.fRight = rect.fLeft + SkIntToScalar(fWidth); rect.fBottom = rect.fTop + paint.getStrokeWidth(); SkPaint p(paint); p.setStyle(SkPaint::kFill_Style); p.setPathEffect(nullptr); int count = SkScalarRoundToInt((pts[1].fX - pts[0].fX) / (2*fWidth)); SkScalar dx = SkIntToScalar(2 * fWidth); for (int i = 0; i < N*10; ++i) { SkRect r = rect; for (int j = 0; j < count; ++j) { canvas->drawRect(r, p); r.offset(dx, 0); } } } }
void onDraw(SkCanvas* canvas) override { canvas->translate(20, 20); SkRect r = SkRect::MakeWH(1000, 1000); SkPaint paint; paint.setAntiAlias(true); paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(15); const SkScalar inset = paint.getStrokeWidth() + 4; const SkScalar sweepAngle = 345; SkRandom rand; SkScalar sign = 1; while (r.width() > paint.getStrokeWidth() * 3) { paint.setColor(sk_tool_utils::color_to_565(rand.nextU() | (0xFF << 24))); SkScalar startAngle = rand.nextUScalar1() * 360; SkScalar speed = SkScalarSqrt(16 / r.width()) * 0.5f; startAngle += fRotate * 360 * speed * sign; SkPath path; path.addArc(r, startAngle, sweepAngle); canvas->drawPath(path, paint); r.inset(inset, inset); sign = -sign; } }
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); }
SkStroke::SkStroke(const SkPaint& p) { fWidth = p.getStrokeWidth(); fMiterLimit = p.getStrokeMiter(); fCap = (uint8_t)p.getStrokeCap(); fJoin = (uint8_t)p.getStrokeJoin(); fDoFill = SkToU8(p.getStyle() == SkPaint::kStrokeAndFill_Style); }
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 OsmAnd::MapRasterizer_P::rasterizePolylineShadow( const Context& context, SkCanvas& canvas, const SkPath& path, SkPaint& paint, const ColorARGB shadowColor, const float shadowRadius) { if (context.shadowMode == MapPresentationEnvironment::ShadowMode::BlurShadow && shadowRadius > 0.0f) { // simply draw shadow? difference from option 3 ? paint.setLooper(SkBlurDrawLooper::Create( shadowColor.toSkColor(), SkBlurMaskFilter::ConvertRadiusToSigma(shadowRadius), 0, 0))->unref(); canvas.drawPath(path, paint); } else if (context.shadowMode == MapPresentationEnvironment::ShadowMode::SolidShadow && shadowRadius > 0.0f) { paint.setLooper(nullptr); paint.setStrokeWidth(paint.getStrokeWidth() + shadowRadius * 2); paint.setColorFilter(SkColorFilter::CreateModeFilter( shadowColor.toSkColor(), SkXfermode::kSrcIn_Mode))->unref(); canvas.drawPath(path, paint); } }
virtual void onDrawContent(SkCanvas* canvas) { static const char* gStr[] = { "11", "44", "112233", "411327463524", }; SkPaint paint; paint.setStrokeWidth(SkIntToScalar(1)); SkScalar x0 = SkIntToScalar(10); SkScalar y0 = SkIntToScalar(10); SkScalar x1 = x0 + SkIntToScalar(1000); for (size_t i = 0; i < SK_ARRAY_COUNT(gStr); i++) { SkScalar interval[12]; size_t len = SkMin32(strlen(gStr[i]), SK_ARRAY_COUNT(interval)); for (size_t j = 0; j < len; j++) { interval[j] = SkIntToScalar(gStr[i][j] - '0'); } SkDashPathEffect dash(interval, len, 0); paint.setPathEffect(&dash); canvas->drawLine(x0, y0, x1, y0, paint); paint.setPathEffect(NULL); y0 += paint.getStrokeWidth() * 3; } setBitmapDash(&paint, 3); canvas->drawLine(x0, y0, x1, y0, paint); }
static void draw_rect(SkCanvas* canvas, bool showGL, int flags) { SkPaint paint; paint.setAntiAlias(true); SkRect r = SkRect::MakeLTRB(50, 70, 250, 370); setFade(&paint, showGL); canvas->drawRect(r, paint); if (showGL) { show_mesh(canvas, r); } canvas->translate(320, 0); paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(25); canvas->drawRect(r, paint); if (showGL) { SkScalar rad = paint.getStrokeWidth() / 2; SkPoint pts[8]; r.outset(rad, rad); r.toQuad(&pts[0]); r.inset(rad*2, rad*2); r.toQuad(&pts[4]); const uint16_t indices[] = { 0, 4, 1, 5, 2, 6, 3, 7, 0, 4 }; show_mesh(canvas, pts, indices, SK_ARRAY_COUNT(indices)); } }
SkPDFGraphicState::SkPDFGraphicState(const SkPaint& p) : fStrokeWidth(p.getStrokeWidth()) , fStrokeMiter(p.getStrokeMiter()) , fAlpha(p.getAlpha()) , fStrokeCap(SkToU8(p.getStrokeCap())) , fStrokeJoin(SkToU8(p.getStrokeJoin())) , fMode(SkToU8(mode_for_pdf(p.getXfermode()))) {}
static void draw_sweep(SkCanvas* c, int width, int height, SkScalar angle) { SkRect r; SkPaint p; p.setAntiAlias(true); // p.setDither(true); p.setStrokeWidth(SkIntToScalar(width/10)); p.setStyle(SkPaint::kStroke_Style); r.set(0, 0, SkIntToScalar(width), SkIntToScalar(height)); // SkColor colors[] = { SK_ColorRED, SK_ColorBLUE, SK_ColorGREEN, SK_ColorCYAN }; SkColor colors[] = { 0x4c737373, 0x4c737373, 0xffffd300 }; SkShader* s = SkGradientShader::CreateSweep(r.centerX(), r.centerY(), colors, NULL, SK_ARRAY_COUNT(colors)); p.setShader(s)->unref(); SkAutoCanvasRestore acr(c, true); c->translate(r.centerX(), r.centerY()); c->rotate(angle); c->translate(-r.centerX(), -r.centerY()); SkRect bounds = r; r.inset(p.getStrokeWidth(), p.getStrokeWidth()); SkRect innerBounds = r; if (true) { c->drawOval(r, p); } else { SkScalar x = r.centerX(); SkScalar y = r.centerY(); SkScalar radius = r.width() / 2; SkScalar thickness = p.getStrokeWidth(); SkScalar sweep = SkFloatToScalar(360.0f); SkPath path; path.moveTo(x + radius, y); // outer top path.lineTo(x + radius + thickness, y); // outer arc path.arcTo(bounds, 0, sweep, false); // inner arc path.arcTo(innerBounds, sweep, -sweep, false); path.close(); } }
TessellationCache::Description::Description(Type type, const Matrix4& transform, const SkPaint& paint) : type(type) , aa(paint.isAntiAlias()) , cap(paint.getStrokeCap()) , style(paint.getStyle()) , strokeWidth(paint.getStrokeWidth()) { PathTessellator::extractTessellationScales(transform, &scaleX, &scaleY); memset(&shape, 0, sizeof(Shape)); }
virtual void onDrawContent(SkCanvas* canvas) { SkPaint paint; paint.setAntiAlias(true); paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(SkIntToScalar(20)); SkPaint hair; hair.setStyle(SkPaint::kStroke_Style); hair.setColor(SK_ColorRED); static const SkISize gSize[] = { { 100, 50 }, { 100, 0 }, { 0, 50 }, { 0, 0 } }; static const SkPaint::Join gJoin[] = { SkPaint::kMiter_Join, SkPaint::kRound_Join, SkPaint::kBevel_Join }; canvas->translate(paint.getStrokeWidth(), paint.getStrokeWidth()); for (size_t i = 0; i < SK_ARRAY_COUNT(gJoin); ++i) { paint.setStrokeJoin(gJoin[i]); canvas->save(); for (size_t j = 0; j < SK_ARRAY_COUNT(gSize); ++j) { SkRect r = SkRect::MakeWH(SkIntToScalar(gSize[j].fWidth), SkIntToScalar(gSize[j].fHeight)); canvas->drawRect(r, paint); canvas->drawRect(r, hair); canvas->translate(0, SkIntToScalar(100)); } canvas->restore(); canvas->translate(SkIntToScalar(150), 0); } }
void SkPDFDevice::drawPoints(const SkDraw& d, SkCanvas::PointMode mode, size_t count, const SkPoint* points, const SkPaint& paint) { if (count == 0) return; switch (mode) { case SkCanvas::kPolygon_PointMode: updateGSFromPaint(paint, false); SkPDFUtils::MoveTo(points[0].fX, points[0].fY, &fContent); for (size_t i = 1; i < count; i++) { SkPDFUtils::AppendLine(points[i].fX, points[i].fY, &fContent); } SkPDFUtils::StrokePath(&fContent); break; case SkCanvas::kLines_PointMode: updateGSFromPaint(paint, false); for (size_t i = 0; i < count/2; i++) { SkPDFUtils::MoveTo(points[i * 2].fX, points[i * 2].fY, &fContent); SkPDFUtils::AppendLine(points[i * 2 + 1].fX, points[i * 2 + 1].fY, &fContent); SkPDFUtils::StrokePath(&fContent); } break; case SkCanvas::kPoints_PointMode: if (paint.getStrokeCap() == SkPaint::kRound_Cap) { updateGSFromPaint(paint, false); for (size_t i = 0; i < count; i++) { SkPDFUtils::MoveTo(points[i].fX, points[i].fY, &fContent); SkPDFUtils::StrokePath(&fContent); } } else { // PDF won't draw a single point with square/butt caps because // the orientation is ambiguous. Draw a rectangle instead. SkPaint newPaint = paint; newPaint.setStyle(SkPaint::kFill_Style); SkScalar strokeWidth = paint.getStrokeWidth(); SkScalar halfStroke = strokeWidth * SK_ScalarHalf; for (size_t i = 0; i < count; i++) { SkRect r = SkRect::MakeXYWH(points[i].fX, points[i].fY, 0, 0); r.inset(-halfStroke, -halfStroke); drawRect(d, r, newPaint); } } break; default: SkASSERT(false); } }
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 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"); } }
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 SkGLDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) { TRACE_DRAW("coreDrawPoints", this, draw); SkScalar width = paint.getStrokeWidth(); if (width < 0) { return; } /* We should really only use drawverts for hairlines, since gl and skia treat the thickness differently... */ AutoPaintShader shader(this, paint); if (width <= 0) { width = SK_Scalar1; } if (SkCanvas::kPoints_PointMode == mode) { glPointSize(SkScalarToFloat(width)); } else { glLineWidth(SkScalarToFloat(width)); } const SkGLVertex* verts; #if GLSCALAR_IS_SCALAR verts = (const SkGLVertex*)pts; #else SkAutoSTMalloc<32, SkGLVertex> storage(count); SkGLVertex* v = storage.get(); v->setPoints(pts, count); verts = v; #endif const SkGLVertex* texs = shader.useTex() ? verts : NULL; SkGL::DrawVertices(count, gPointMode2GL[mode], verts, texs, NULL, NULL, this->updateMatrixClip()); }
static bool setupForText(SkPaint* paint, GraphicsContext* gc, const SimpleFontData* font) { int mode = gc->textDrawingMode(); if ((mode & (cTextFill | cTextStroke)) == (cTextFill | cTextStroke)) { SkLayerDrawLooper* looper = new SkLayerDrawLooper; paint->setLooper(looper)->unref(); // we clear the looper, in case we have a shadow SkPaint* fillP = NULL; SkPaint* strokeP = NULL; if (gc->willStroke()) { strokeP = setupStroke(looper->addLayer(), gc, font); strokeP->setLooper(NULL); } if (gc->willFill()) { fillP = setupFill(looper->addLayer(), gc, font); fillP->setLooper(NULL); } SkPaint shadowPaint; SkPoint offset; if (gc->setupShadowPaint(&shadowPaint, &offset)) { SkPaint* p = looper->addLayer(offset.fX, offset.fY); *p = shadowPaint; if (strokeP && !fillP) { // stroke the shadow if we have stroke but no fill p->setStyle(SkPaint::kStroke_Style); p->setStrokeWidth(strokeP->getStrokeWidth()); } updateForFont(p, font); } } else if (mode & cTextFill) { (void)setupFill(paint, gc, font); } else if (mode & cTextStroke) { (void)setupStroke(paint, gc, font); } else { return false; } return true; }
void SkBBoxRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) { SkRect bbox; bbox.set(pts, SkToInt(count)); // Small min width value, just to ensure hairline point bounding boxes aren't empty. // Even though we know hairline primitives are drawn one pixel wide, we do not use a // minimum of 1 because the playback scale factor is unknown at record time. Later // outsets will take care of adding additional padding for antialiasing and rounding out // to integer device coordinates, guaranteeing that the rasterized pixels will be included // in the computed bounds. // Note: The device coordinate outset in SkBBoxHierarchyRecord::handleBBox is currently // done in the recording coordinate space, which is wrong. // http://code.google.com/p/skia/issues/detail?id=1021 static const SkScalar kMinWidth = 0.01f; SkScalar halfStrokeWidth = SkMaxScalar(paint.getStrokeWidth(), kMinWidth) / 2; bbox.outset(halfStrokeWidth, halfStrokeWidth); if (this->transformBounds(bbox, &paint)) { INHERITED::drawPoints(mode, count, pts, paint); } }
PassRefPtr<JSONObject> LoggingCanvas::objectForSkPaint(const SkPaint& paint) { RefPtr<JSONObject> paintItem = JSONObject::create(); paintItem->setNumber("textSize", paint.getTextSize()); paintItem->setNumber("textScaleX", paint.getTextScaleX()); paintItem->setNumber("textSkewX", paint.getTextSkewX()); if (SkShader* shader = paint.getShader()) paintItem->setObject("shader", objectForSkShader(*shader)); paintItem->setString("color", stringForSkColor(paint.getColor())); paintItem->setNumber("strokeWidth", paint.getStrokeWidth()); paintItem->setNumber("strokeMiter", paint.getStrokeMiter()); paintItem->setString("flags", stringForSkPaintFlags(paint)); paintItem->setString("filterLevel", filterQualityName(paint.getFilterQuality())); paintItem->setString("textAlign", textAlignName(paint.getTextAlign())); paintItem->setString("strokeCap", strokeCapName(paint.getStrokeCap())); paintItem->setString("strokeJoin", strokeJoinName(paint.getStrokeJoin())); paintItem->setString("styleName", styleName(paint.getStyle())); paintItem->setString("textEncoding", textEncodingName(paint.getTextEncoding())); paintItem->setString("hinting", hintingName(paint.getHinting())); return paintItem.release(); }
sk_sp<SkPDFDict> SkPDFGraphicState::GetGraphicStateForPaint(SkPDFCanon* canon, const SkPaint& p) { SkASSERT(canon); if (SkPaint::kFill_Style == p.getStyle()) { SkPDFFillGraphicState fillKey = {p.getAlpha(), pdf_blend_mode(p.getBlendMode())}; auto& fillMap = canon->fFillGSMap; if (sk_sp<SkPDFDict>* statePtr = fillMap.find(fillKey)) { return *statePtr; } auto state = sk_make_sp<SkPDFDict>(); state->reserve(2); state->insertScalar("ca", fillKey.fAlpha / 255.0f); state->insertName("BM", as_pdf_blend_mode_name((SkBlendMode)fillKey.fBlendMode)); fillMap.set(fillKey, state); return state; } else { SkPDFStrokeGraphicState strokeKey = { p.getStrokeWidth(), p.getStrokeMiter(), SkToU8(p.getStrokeCap()), SkToU8(p.getStrokeJoin()), p.getAlpha(), pdf_blend_mode(p.getBlendMode())}; auto& sMap = canon->fStrokeGSMap; if (sk_sp<SkPDFDict>* statePtr = sMap.find(strokeKey)) { return *statePtr; } auto state = sk_make_sp<SkPDFDict>(); state->reserve(8); state->insertScalar("CA", strokeKey.fAlpha / 255.0f); state->insertScalar("ca", strokeKey.fAlpha / 255.0f); state->insertInt("LC", to_stroke_cap(strokeKey.fStrokeCap)); state->insertInt("LJ", to_stroke_join(strokeKey.fStrokeJoin)); state->insertScalar("LW", strokeKey.fStrokeWidth); state->insertScalar("ML", strokeKey.fStrokeMiter); state->insertBool("SA", true); // SA = Auto stroke adjustment. state->insertName("BM", as_pdf_blend_mode_name((SkBlendMode)strokeKey.fBlendMode)); sMap.set(strokeKey, state); return state; } }
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; }
Json::Value SkJSONCanvas::makePaint(const SkPaint& paint) { Json::Value result(Json::objectValue); store_scalar(&result, SKJSONCANVAS_ATTRIBUTE_STROKEWIDTH, paint.getStrokeWidth(), 0.0f); store_scalar(&result, SKJSONCANVAS_ATTRIBUTE_STROKEMITER, paint.getStrokeMiter(), SkPaintDefaults_MiterLimit); store_bool(&result, SKJSONCANVAS_ATTRIBUTE_ANTIALIAS, paint.isAntiAlias(), false); store_scalar(&result, SKJSONCANVAS_ATTRIBUTE_TEXTSIZE, paint.getTextSize(), SkPaintDefaults_TextSize); store_scalar(&result, SKJSONCANVAS_ATTRIBUTE_TEXTSCALEX, paint.getTextScaleX(), SK_Scalar1); store_scalar(&result, SKJSONCANVAS_ATTRIBUTE_TEXTSCALEX, paint.getTextSkewX(), 0.0f); apply_paint_color(paint, &result); apply_paint_style(paint, &result); apply_paint_cap(paint, &result); apply_paint_textalign(paint, &result); apply_paint_patheffect(paint, &result, fSendBinaries); apply_paint_maskfilter(paint, &result, fSendBinaries); apply_paint_shader(paint, &result, fSendBinaries); apply_paint_xfermode(paint, &result, fSendBinaries); apply_paint_imagefilter(paint, &result, fSendBinaries); apply_paint_colorfilter(paint, &result, fSendBinaries); apply_paint_typeface(paint, &result, fSendBinaries); return result; }
void drawPlatformFocusRing(const PrimitiveType& primitive, SkCanvas* canvas, SkColor color, int width) { SkPaint paint; paint.setAntiAlias(true); paint.setStyle(SkPaint::kStroke_Style); paint.setColor(color); paint.setStrokeWidth(GraphicsContext::focusRingWidth(width)); #if OS(MACOSX) paint.setAlpha(64); const float cornerRadius = (width - 1) * 0.5f; #else const float cornerRadius = 1; #endif drawFocusRingPrimitive(primitive, canvas, paint, cornerRadius); #if OS(MACOSX) // Inner part paint.setAlpha(128); paint.setStrokeWidth(paint.getStrokeWidth() * 0.5f); drawFocusRingPrimitive(primitive, canvas, paint, cornerRadius); #endif }
SkStrokePathEffect::SkStrokePathEffect(const SkPaint& paint) : fWidth(paint.getStrokeWidth()), fMiter(paint.getStrokeMiter()), fStyle(SkToU8(paint.getStyle())), fJoin(SkToU8(paint.getStrokeJoin())), fCap(SkToU8(paint.getStrokeCap())) { }
bool GrAtlasTextBlob::mustRegenerate(const SkPaint& paint, GrColor color, const SkMaskFilter::BlurRec& blurRec, const SkMatrix& viewMatrix, SkScalar x, SkScalar y) { // If we have LCD text then our canonical color will be set to transparent, in this case we have // to regenerate the blob on any color change // We use the grPaint to get any color filter effects if (fKey.fCanonicalColor == SK_ColorTRANSPARENT && fPaintColor != color) { return true; } if (fInitialViewMatrix.hasPerspective() != viewMatrix.hasPerspective()) { return true; } if (fInitialViewMatrix.hasPerspective() && !fInitialViewMatrix.cheapEqualTo(viewMatrix)) { return true; } // We only cache one masked version if (fKey.fHasBlur && (fBlurRec.fSigma != blurRec.fSigma || fBlurRec.fStyle != blurRec.fStyle || fBlurRec.fQuality != blurRec.fQuality)) { return true; } // Similarly, we only cache one version for each style if (fKey.fStyle != SkPaint::kFill_Style && (fStrokeInfo.fFrameWidth != paint.getStrokeWidth() || fStrokeInfo.fMiterLimit != paint.getStrokeMiter() || fStrokeInfo.fJoin != paint.getStrokeJoin())) { return true; } // Mixed blobs must be regenerated. We could probably figure out a way to do integer scrolls // for mixed blobs if this becomes an issue. if (this->hasBitmap() && this->hasDistanceField()) { // Identical viewmatrices and we can reuse in all cases if (fInitialViewMatrix.cheapEqualTo(viewMatrix) && x == fInitialX && y == fInitialY) { return false; } return true; } if (this->hasBitmap()) { if (fInitialViewMatrix.getScaleX() != viewMatrix.getScaleX() || fInitialViewMatrix.getScaleY() != viewMatrix.getScaleY() || fInitialViewMatrix.getSkewX() != viewMatrix.getSkewX() || fInitialViewMatrix.getSkewY() != viewMatrix.getSkewY()) { return true; } // We can update the positions in the cachedtextblobs without regenerating the whole blob, // but only for integer translations. // This cool bit of math will determine the necessary translation to apply to the already // generated vertex coordinates to move them to the correct position SkScalar transX = viewMatrix.getTranslateX() + viewMatrix.getScaleX() * (x - fInitialX) + viewMatrix.getSkewX() * (y - fInitialY) - fInitialViewMatrix.getTranslateX(); SkScalar transY = viewMatrix.getTranslateY() + viewMatrix.getSkewY() * (x - fInitialX) + viewMatrix.getScaleY() * (y - fInitialY) - fInitialViewMatrix.getTranslateY(); if (!SkScalarIsInt(transX) || !SkScalarIsInt(transY)) { return true; } } else if (this->hasDistanceField()) { // A scale outside of [blob.fMaxMinScale, blob.fMinMaxScale] would result in a different // distance field being generated, so we have to regenerate in those cases SkScalar newMaxScale = viewMatrix.getMaxScale(); SkScalar oldMaxScale = fInitialViewMatrix.getMaxScale(); SkScalar scaleAdjust = newMaxScale / oldMaxScale; if (scaleAdjust < fMaxMinScale || scaleAdjust > fMinMaxScale) { return true; } } // It is possible that a blob has neither distanceField nor bitmaptext. This is in the case // when all of the runs inside the blob are drawn as paths. In this case, we always regenerate // the blob anyways at flush time, so no need to regenerate explicitly return false; }
static void draw_oval(SkCanvas* canvas, bool showGL, int flags) { SkPaint paint; paint.setAntiAlias(true); SkRect r = SkRect::MakeLTRB(50, 70, 250, 370); setFade(&paint, showGL); canvas->drawOval(r, paint); if (showGL) { switch (flags) { case 0: { SkPath path; path.addOval(r); show_glframe(canvas, path); } break; case 1: case 3: { SkPath src, dst; src.addOval(r); tesselate(src, &dst); show_fan(canvas, dst, r.centerX(), r.centerY()); } break; case 2: { SkPaint p(paint); show_mesh(canvas, r); setGLFrame(&p); paint.setStyle(SkPaint::kFill_Style); canvas->drawCircle(r.centerX(), r.centerY(), 3, p); } break; } } canvas->translate(320, 0); paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(25); canvas->drawOval(r, paint); if (showGL) { switch (flags) { case 0: { SkPath path; SkScalar rad = paint.getStrokeWidth() / 2; r.outset(rad, rad); path.addOval(r); r.inset(rad*2, rad*2); path.addOval(r); show_glframe(canvas, path); } break; case 1: { SkPath path0, path1; SkScalar rad = paint.getStrokeWidth() / 2; r.outset(rad, rad); path0.addOval(r); r.inset(rad*2, rad*2); path1.addOval(r); show_mesh_between(canvas, path0, path1); } break; case 2: { SkPath path; path.addOval(r); show_glframe(canvas, path); SkScalar rad = paint.getStrokeWidth() / 2; r.outset(rad, rad); show_mesh(canvas, r); } break; case 3: { SkScalar rad = paint.getStrokeWidth() / 2; r.outset(rad, rad); SkPaint paint; paint.setAlpha(0x33); canvas->drawRect(r, paint); show_mesh(canvas, r); } break; } } }