virtual void onDraw(SkCanvas* canvas) { const char* lcd_text = "LCD"; const char* gray_text = "GRAY"; SkPaint paint; paint.setAntiAlias(true); paint.setLCDRenderText(true); const struct { SkPoint fLoc; SkScalar fTextSize; SkScalar fScale; const char* fText; } rec[] = { { { 10, 50 }, kLCDTextSizeLimit - 1, 1, lcd_text }, { { 160, 50 }, kLCDTextSizeLimit + 1, 1, gray_text }, { { 10, 100 }, kLCDTextSizeLimit / 2, 1.99f, lcd_text }, { { 160, 100 }, kLCDTextSizeLimit / 2, 2.01f, gray_text }, }; for (size_t i = 0; i < SK_ARRAY_COUNT(rec); ++i) { const SkPoint loc = rec[i].fLoc; SkAutoCanvasRestore acr(canvas, true); paint.setTextSize(rec[i].fTextSize); ScaleAbout(canvas, rec[i].fScale, rec[i].fScale, loc.x(), loc.y()); canvas->drawString(rec[i].fText, loc.x(), loc.y(), paint); } }
void drawSceneColumn(SkCanvas* canvas, const SkPoint& pos, SkScalar scale, SkScalar localScale, unsigned tileMode) { SkMatrix ctm, localMatrix; ctm.setTranslate(pos.x(), pos.y()); ctm.preScale(scale, scale); localMatrix.setScale(localScale, localScale); this->drawScene(canvas, ctm, localMatrix, tileMode); ctm.setTranslate(pos.x(), pos.y() + fSceneSize * 1.2f * scale); ctm.preScale(scale, scale); localMatrix.setTranslate(fTileSize / 4, fTileSize / 4); localMatrix.preScale(localScale, localScale); this->drawScene(canvas, ctm, localMatrix, tileMode); ctm.setTranslate(pos.x(), pos.y() + fSceneSize * 2.4f * scale); ctm.preScale(scale, scale); localMatrix.setRotate(45); localMatrix.preScale(localScale, localScale); this->drawScene(canvas, ctm, localMatrix, tileMode); ctm.setTranslate(pos.x(), pos.y() + fSceneSize * 3.6f * scale); ctm.preScale(scale, scale); localMatrix.setSkew(1, 0); localMatrix.preScale(localScale, localScale); this->drawScene(canvas, ctm, localMatrix, tileMode); ctm.setTranslate(pos.x(), pos.y() + fSceneSize * 4.8f * scale); ctm.preScale(scale, scale); localMatrix.setTranslate(fTileSize / 4, fTileSize / 4); localMatrix.preRotate(45); localMatrix.preScale(localScale, localScale); this->drawScene(canvas, ctm, localMatrix, tileMode); }
/** * Called on a background thread. Here we can only modify fBackPaths. */ void runAnimationTask(double t, double dt, int w, int h) override { const float tsec = static_cast<float>(t); this->INHERITED::runAnimationTask(t, 0.5 * dt, w, h); for (int i = 0; i < kNumPaths; ++i) { const Glyph& glyph = fGlyphs[i]; const SkMatrix& backMatrix = fBackMatrices[i]; const Sk2f matrix[3] = { Sk2f(backMatrix.getScaleX(), backMatrix.getSkewY()), Sk2f(backMatrix.getSkewX(), backMatrix.getScaleY()), Sk2f(backMatrix.getTranslateX(), backMatrix.getTranslateY()) }; SkPath* backpath = &fBackPaths[i]; backpath->reset(); backpath->setFillType(SkPath::kEvenOdd_FillType); SkPath::RawIter iter(glyph.fPath); SkPath::Verb verb; SkPoint pts[4]; while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { switch (verb) { case SkPath::kMove_Verb: { SkPoint pt = fWaves.apply(tsec, matrix, pts[0]); backpath->moveTo(pt.x(), pt.y()); break; } case SkPath::kLine_Verb: { SkPoint endpt = fWaves.apply(tsec, matrix, pts[1]); backpath->lineTo(endpt.x(), endpt.y()); break; } case SkPath::kQuad_Verb: { SkPoint controlPt = fWaves.apply(tsec, matrix, pts[1]); SkPoint endpt = fWaves.apply(tsec, matrix, pts[2]); backpath->quadTo(controlPt.x(), controlPt.y(), endpt.x(), endpt.y()); break; } case SkPath::kClose_Verb: { backpath->close(); break; } case SkPath::kCubic_Verb: case SkPath::kConic_Verb: case SkPath::kDone_Verb: SK_ABORT("Unexpected path verb"); break; } } } }
void updateDom() { const SkPoint corner = pos - SkPoint::Make(size.width() / 2, size.height() / 2); objectNode->setX(SkSVGLength(corner.x())); objectNode->setY(SkSVGLength(corner.y())); // Simulate parallax shadow for a centered light source. SkPoint shadowOffset = pos - SkPoint::Make(kBounds.centerX(), kBounds.centerY()); shadowOffset.scale(kShadowParallax); const SkPoint shadowCorner = corner + shadowOffset; shadowNode->setX(SkSVGLength(shadowCorner.x())); shadowNode->setY(SkSVGLength(shadowCorner.y())); }
SkPath cubicPath(SkPoint p1, SkPoint p2) { SkASSERT(p1.y() == p2.y()); SkPath path; path.moveTo(p1); SkPoint p3 = SkPoint::Make((p1.x() + p2.x()) / 3.0f, p1.y() * 0.7f); SkPoint p4 = SkPoint::Make(2.0f*(p1.x() + p2.x()) / 3.0f, p1.y() * 1.5f); path.cubicTo(p3, p4, p2); return path; }
SkPath quadPath(SkPoint p1, SkPoint p2) { SkASSERT(p1.y() == p2.y()); SkPath path; path.moveTo(p1); path.lineTo(p2); SkPoint p3 = SkPoint::Make((p1.x() + p2.x()) / 2.0f, p1.y() * 0.7f); path.quadTo(p3, p1); return path; }
bool RRect::onContains(const SkPoint& p) const { if (!fRRect.rect().contains(p.x(), p.y())) { return false; } if (fRRect.isRect()) { return true; } // TODO: no SkRRect::contains(x, y) return fRRect.contains(SkRect::MakeLTRB(p.x() - SK_ScalarNearlyZero, p.y() - SK_ScalarNearlyZero, p.x() + SK_ScalarNearlyZero, p.y() + SK_ScalarNearlyZero)); }
static void AddRun(const SkFont& font, int count, SkTextBlobRunIterator::GlyphPositioning pos, const SkPoint& offset, SkTextBlobBuilder& builder, const SkRect* bounds = nullptr) { switch (pos) { case SkTextBlobRunIterator::kDefault_Positioning: { const SkTextBlobBuilder::RunBuffer& rb = builder.allocRun(font, count, offset.x(), offset.y(), bounds); for (int i = 0; i < count; ++i) { rb.glyphs[i] = i; } } break; case SkTextBlobRunIterator::kHorizontal_Positioning: { const SkTextBlobBuilder::RunBuffer& rb = builder.allocRunPosH(font, count, offset.y(), bounds); for (int i = 0; i < count; ++i) { rb.glyphs[i] = i; rb.pos[i] = SkIntToScalar(i); } } break; case SkTextBlobRunIterator::kFull_Positioning: { const SkTextBlobBuilder::RunBuffer& rb = builder.allocRunPos(font, count, bounds); for (int i = 0; i < count; ++i) { rb.glyphs[i] = i; rb.pos[i * 2] = SkIntToScalar(i); rb.pos[i * 2 + 1] = -SkIntToScalar(i); } } break; default: SK_ABORT("unhandled positioning value"); } }
static void convolve_gaussian_2d(GrDrawContext* drawContext, const GrClip& clip, const SkRect& dstRect, const SkPoint& srcOffset, GrTexture* texture, int radiusX, int radiusY, SkScalar sigmaX, SkScalar sigmaY, const SkRect* srcBounds) { SkMatrix localMatrix = SkMatrix::MakeTrans(-srcOffset.x(), -srcOffset.y()); SkISize size = SkISize::Make(2 * radiusX + 1, 2 * radiusY + 1); SkIPoint kernelOffset = SkIPoint::Make(radiusX, radiusY); GrPaint paint; SkIRect bounds; if (srcBounds) { srcBounds->roundOut(&bounds); } else { bounds.setEmpty(); } SkAutoTUnref<GrFragmentProcessor> conv(GrMatrixConvolutionEffect::CreateGaussian( texture, bounds, size, 1.0, 0.0, kernelOffset, srcBounds ? GrTextureDomain::kDecal_Mode : GrTextureDomain::kIgnore_Mode, true, sigmaX, sigmaY)); paint.addColorFragmentProcessor(conv); paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); drawContext->fillRectWithLocalMatrix(clip, paint, SkMatrix::I(), dstRect, localMatrix); }
void drawSets(SkCanvas* canvas) const { SkAutoCanvasRestore acr(canvas, true); const SkFilterQuality filters[] = { kNone_SkFilterQuality, kLow_SkFilterQuality, kMedium_SkFilterQuality, kHigh_SkFilterQuality }; const bool AAs[] = { false, true }; SkPaint paint; for (int i = 0; i < fSets.count(); ++i) { auto& set = fSets[i]; SkPoint lastPt; for (size_t j = 0; j < SK_ARRAY_COUNT(AAs); ++j) { paint.setAntiAlias(AAs[j]); for (size_t k = 0; k < SK_ARRAY_COUNT(filters); ++k) { paint.setFilterQuality(filters[k]); lastPt = drawSet(canvas, set, paint); canvas->translate((kSegLen + 4) * set.fVector.y(), (kSegLen + 4) * set.fVector.x()); } } canvas->translate(lastPt.x() + kSegLen, - SkIntToScalar(kSegLen + 4) * SK_ARRAY_COUNT(filters) * SK_ARRAY_COUNT(AAs)); } }
PassRefPtr<JSONObject> LoggingCanvas::objectForSkPoint(const SkPoint& point) { RefPtr<JSONObject> pointItem = JSONObject::create(); pointItem->setNumber("x", point.x()); pointItem->setNumber("y", point.y()); return pointItem.release(); }
void SkAnnotateNamedDestination(SkCanvas* canvas, const SkPoint& point, SkData* name) { if (nullptr == name) { return; } const SkRect rect = SkRect::MakeXYWH(point.x(), point.y(), 0, 0); canvas->drawAnnotation(rect, SkAnnotationKeys::Define_Named_Dest_Key(), name); }
inline void GrStencilAndCoverTextContext::appendGlyph(const SkGlyph& glyph, const SkPoint& pos) { // Stick the glyphs we can't draw into the fallback arrays. if (SkMask::kARGB32_Format == glyph.fMaskFormat) { fFallbackIndices.push_back(glyph.getGlyphID()); fFallbackPositions.push_back().set(fTextInverseRatio * pos.x(), -fTextInverseRatio * pos.y()); } else { // TODO: infer the reserve count from the text length. if (!fDraw) { fDraw = GrPathRangeDraw::Create(fGlyphs, GrPathRendering::kTranslate_PathTransformType, 64); } float translate[] = { fTextInverseRatio * pos.x(), -fTextInverseRatio * pos.y() }; fDraw->append(glyph.getGlyphID(), translate); } }
void SkAnnotateNamedDestination(SkCanvas* canvas, const SkPoint& point, SkData* name) { if (NULL == name) { return; } SkPaint paint; annotate_paint(paint, SkAnnotationKeys::Define_Named_Dest_Key(), name); canvas->drawPoint(point.x(), point.y(), paint); }
static void draw_label(SkCanvas* canvas, const char* label, const SkPoint& offset) { SkPaint paint; size_t len = strlen(label); SkScalar width = paint.measureText(label, len); canvas->drawText(label, len, offset.x() - width / 2, offset.y(), paint); }
SkScalar SkPerlinNoiseShader::PerlinNoiseShaderContext::noise2D( int channel, const StitchData& stitchData, const SkPoint& noiseVector) const { struct Noise { int noisePositionIntegerValue; int nextNoisePositionIntegerValue; SkScalar noisePositionFractionValue; Noise(SkScalar component) { SkScalar position = component + kPerlinNoise; noisePositionIntegerValue = SkScalarFloorToInt(position); noisePositionFractionValue = position - SkIntToScalar(noisePositionIntegerValue); nextNoisePositionIntegerValue = noisePositionIntegerValue + 1; } }; Noise noiseX(noiseVector.x()); Noise noiseY(noiseVector.y()); SkScalar u, v; const SkPerlinNoiseShader& perlinNoiseShader = static_cast<const SkPerlinNoiseShader&>(fShader); // If stitching, adjust lattice points accordingly. if (perlinNoiseShader.fStitchTiles) { noiseX.noisePositionIntegerValue = checkNoise(noiseX.noisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth); noiseY.noisePositionIntegerValue = checkNoise(noiseY.noisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight); noiseX.nextNoisePositionIntegerValue = checkNoise(noiseX.nextNoisePositionIntegerValue, stitchData.fWrapX, stitchData.fWidth); noiseY.nextNoisePositionIntegerValue = checkNoise(noiseY.nextNoisePositionIntegerValue, stitchData.fWrapY, stitchData.fHeight); } noiseX.noisePositionIntegerValue &= kBlockMask; noiseY.noisePositionIntegerValue &= kBlockMask; noiseX.nextNoisePositionIntegerValue &= kBlockMask; noiseY.nextNoisePositionIntegerValue &= kBlockMask; int i = fPaintingData->fLatticeSelector[noiseX.noisePositionIntegerValue]; int j = fPaintingData->fLatticeSelector[noiseX.nextNoisePositionIntegerValue]; int b00 = (i + noiseY.noisePositionIntegerValue) & kBlockMask; int b10 = (j + noiseY.noisePositionIntegerValue) & kBlockMask; int b01 = (i + noiseY.nextNoisePositionIntegerValue) & kBlockMask; int b11 = (j + noiseY.nextNoisePositionIntegerValue) & kBlockMask; SkScalar sx = smoothCurve(noiseX.noisePositionFractionValue); SkScalar sy = smoothCurve(noiseY.noisePositionFractionValue); // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement SkPoint fractionValue = SkPoint::Make(noiseX.noisePositionFractionValue, noiseY.noisePositionFractionValue); // Offset (0,0) u = fPaintingData->fGradient[channel][b00].dot(fractionValue); fractionValue.fX -= SK_Scalar1; // Offset (-1,0) v = fPaintingData->fGradient[channel][b10].dot(fractionValue); SkScalar a = SkScalarInterp(u, v, sx); fractionValue.fY -= SK_Scalar1; // Offset (-1,-1) v = fPaintingData->fGradient[channel][b11].dot(fractionValue); fractionValue.fX = noiseX.noisePositionFractionValue; // Offset (0,-1) u = fPaintingData->fGradient[channel][b01].dot(fractionValue); SkScalar b = SkScalarInterp(u, v, sx); return SkScalarInterp(a, b, sy); }
SkFlattenable* SkSweepGradient::CreateProc(SkReadBuffer& buffer) { DescriptorScope desc; if (!desc.unflatten(buffer)) { return NULL; } const SkPoint center = buffer.readPoint(); return SkGradientShader::CreateSweep(center.x(), center.y(), desc.fColors, desc.fPos, desc.fCount, desc.fGradFlags, desc.fLocalMatrix); }
void onDrawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) override { if (!paint.getAnnotation()) return; ASSERT_EQ(1u, count); // Only called from drawPoint(). SkPoint point = getTotalMatrix().mapXY(pts[0].x(), pts[0].y()); Operation operation = { DrawPoint, SkRect::MakeXYWH(point.x(), point.y(), 0, 0) }; m_recordedOperations.append(operation); }
void SkLinearGradient:: LinearGradient4fContext::mapTs(int x, int y, SkScalar ts[], int count) const { SkASSERT(count > 0); SkASSERT(fDstToPosClass != kLinear_MatrixClass); SkScalar sx = x + SK_ScalarHalf; const SkScalar sy = y + SK_ScalarHalf; SkPoint pt; if (fDstToPosClass != kPerspective_MatrixClass) { // kLinear_MatrixClass, kFixedStepInX_MatrixClass => fixed dt per scanline const SkScalar dtdx = fDstToPos.fixedStepInX(sy).x(); fDstToPosProc(fDstToPos, sx, sy, &pt); const Sk4f dtdx4 = Sk4f(4 * dtdx); Sk4f t4 = Sk4f(pt.x() + 0 * dtdx, pt.x() + 1 * dtdx, pt.x() + 2 * dtdx, pt.x() + 3 * dtdx); while (count >= 4) { t4.store(ts); t4 = t4 + dtdx4; ts += 4; count -= 4; } if (count & 2) { *ts++ = t4[0]; *ts++ = t4[1]; t4 = SkNx_shuffle<2, 0, 1, 3>(t4); } if (count & 1) { *ts++ = t4[0]; } } else { for (int i = 0; i < count; ++i) { fDstToPosProc(fDstToPos, sx, sy, &pt); ts[i] = pt.x(); sx += SK_Scalar1; } } }
SkShader* SkPictureShader::refBitmapShader(const SkMatrix& matrix, const SkMatrix* localM) const { SkASSERT(fPicture && fPicture->width() > 0 && fPicture->height() > 0); SkMatrix m; m.setConcat(matrix, this->getLocalMatrix()); if (localM) { m.preConcat(*localM); } // Use a rotation-invariant scale SkPoint scale; if (!SkDecomposeUpper2x2(m, NULL, &scale, NULL)) { // Decomposition failed, use an approximation. scale.set(SkScalarSqrt(m.getScaleX() * m.getScaleX() + m.getSkewX() * m.getSkewX()), SkScalarSqrt(m.getScaleY() * m.getScaleY() + m.getSkewY() * m.getSkewY())); } SkSize scaledSize = SkSize::Make(scale.x() * fPicture->width(), scale.y() * fPicture->height()); SkISize tileSize = scaledSize.toRound(); if (tileSize.isEmpty()) { return NULL; } // The actual scale, compensating for rounding. SkSize tileScale = SkSize::Make(SkIntToScalar(tileSize.width()) / fPicture->width(), SkIntToScalar(tileSize.height()) / fPicture->height()); SkAutoMutexAcquire ama(fCachedBitmapShaderMutex); if (!fCachedBitmapShader || tileScale != fCachedTileScale) { SkBitmap bm; if (!bm.allocN32Pixels(tileSize.width(), tileSize.height())) { return NULL; } bm.eraseColor(SK_ColorTRANSPARENT); SkCanvas canvas(bm); canvas.scale(tileScale.width(), tileScale.height()); canvas.drawPicture(fPicture); fCachedTileScale = tileScale; SkMatrix shaderMatrix = this->getLocalMatrix(); shaderMatrix.preScale(1 / tileScale.width(), 1 / tileScale.height()); fCachedBitmapShader.reset(CreateBitmapShader(bm, fTmx, fTmy, &shaderMatrix)); } // Increment the ref counter inside the mutex to ensure the returned pointer is still valid. // Otherwise, the pointer may have been overwritten on a different thread before the object's // ref count was incremented. fCachedBitmapShader.get()->ref(); return fCachedBitmapShader; }
void onOnceBeforeDraw() override { SkPictureRecorder recorder; SkCanvas* pictureCanvas = recorder.beginRecording(kPictureSize, kPictureSize); draw_scene(pictureCanvas, kPictureSize); SkAutoTUnref<SkPicture> picture(recorder.endRecording()); SkPoint offset = SkPoint::Make(100, 100); pictureCanvas = recorder.beginRecording(SkRect::MakeXYWH(offset.x(), offset.y(), kPictureSize, kPictureSize)); pictureCanvas->translate(offset.x(), offset.y()); draw_scene(pictureCanvas, kPictureSize); SkAutoTUnref<SkPicture> offsetPicture(recorder.endRecording()); for (unsigned i = 0; i < SK_ARRAY_COUNT(tiles); ++i) { SkRect tile = SkRect::MakeXYWH(tiles[i].x * kPictureSize, tiles[i].y * kPictureSize, tiles[i].w * kPictureSize, tiles[i].h * kPictureSize); SkMatrix localMatrix; localMatrix.setTranslate(tiles[i].offsetX * kPictureSize, tiles[i].offsetY * kPictureSize); localMatrix.postScale(kFillSize / (2 * kPictureSize), kFillSize / (2 * kPictureSize)); SkPicture* picturePtr = picture.get(); SkRect* tilePtr = &tile; if (tile == SkRect::MakeWH(kPictureSize, kPictureSize)) { // When the tile == picture bounds, exercise the picture + offset path. picturePtr = offsetPicture.get(); tilePtr = NULL; } fShaders[i].reset(SkShader::CreatePictureShader(picturePtr, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix, tilePtr)); } }
static IntersectionType intersection(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3, const SkPoint& p4, SkPoint& res) { // Store the values for fast access and easy // equations-to-code conversion SkScalar x1 = p1.x(), x2 = p2.x(), x3 = p3.x(), x4 = p4.x(); SkScalar y1 = p1.y(), y2 = p2.y(), y3 = p3.y(), y4 = p4.y(); SkScalar d = SkScalarMul(x1 - x2, y3 - y4) - SkScalarMul(y1 - y2, x3 - x4); // If d is zero, there is no intersection if (SkScalarNearlyZero(d)) { return kNone_IntersectionType; } // Get the x and y SkScalar pre = SkScalarMul(x1, y2) - SkScalarMul(y1, x2), post = SkScalarMul(x3, y4) - SkScalarMul(y3, x4); // Compute the point of intersection res.set(SkScalarDiv(SkScalarMul(pre, x3 - x4) - SkScalarMul(x1 - x2, post), d), SkScalarDiv(SkScalarMul(pre, y3 - y4) - SkScalarMul(y1 - y2, post), d)); // Check if the x and y coordinates are within both lines return (res.x() < GrMin(x1, x2) || res.x() > GrMax(x1, x2) || res.x() < GrMin(x3, x4) || res.x() > GrMax(x3, x4) || res.y() < GrMin(y1, y2) || res.y() > GrMax(y1, y2) || res.y() < GrMin(y3, y4) || res.y() > GrMax(y3, y4)) ? kOut_IntersectionType : kIn_IntersectionType; }
void onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) override { if (rect.width() == 0 && rect.height() == 0) { SkPoint point = getTotalMatrix().mapXY(rect.x(), rect.y()); Operation operation = { DrawPoint, SkRect::MakeXYWH(point.x(), point.y(), 0, 0) }; m_recordedOperations.append(operation); } else { Operation operation = { DrawRect, rect }; getTotalMatrix().mapRect(&operation.rect); m_recordedOperations.append(operation); } }
inline void GrStencilAndCoverTextContext::appendGlyph(const SkGlyph& glyph, const SkPoint& pos) { if (fQueuedGlyphCount >= fFallbackGlyphsIdx) { SkASSERT(fQueuedGlyphCount == fFallbackGlyphsIdx); this->flush(); } // Stick the glyphs we can't draw at the end of the buffer, growing backwards. int index = (SkMask::kARGB32_Format == glyph.fMaskFormat) ? --fFallbackGlyphsIdx : fQueuedGlyphCount++; fGlyphIndices[index] = glyph.getGlyphID(); fGlyphPositions[index].set(fTextInverseRatio * pos.x(), -fTextInverseRatio * pos.y()); }
static sk_sp<SkImage> MakeImage(const SkVector& vec, SkColor color) { const SkPoint start = SkPoint::Make(vec.y() * kSegLen / 2, vec.x() * kSegLen / 2); const SkPoint end = SkPoint::Make(start.x() + vec.x() * (kSegLen - 1), start.y() + vec.y() * (kSegLen - 1)); SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterN32Premul(kSegLen, kSegLen)); surface->getCanvas()->clear(SK_ColorTRANSPARENT); SkPaint paint; paint.setAntiAlias(true); const SkRect border = SkRect::MakeIWH(kSegLen, kSegLen).makeInset(.5f, .5f); paint.setColor(SK_ColorBLUE); paint.setStyle(SkPaint::kStroke_Style); surface->getCanvas()->drawRect(border, paint); paint.setColor(SK_ColorBLACK); surface->getCanvas()->drawLine(start.x(), start.y(), end.x(), end.y(), paint); surface->getCanvas()->drawPoint(start.x(), start.y(), color); surface->getCanvas()->drawPoint(end.x(), end.y(), color); return surface->makeImageSnapshot(); }
inline void GrStencilAndCoverTextContext::TextRun::appendGlyph(const SkGlyph& glyph, const SkPoint& pos, FallbackBlobBuilder* fallback) { // Stick the glyphs we can't draw into the fallback text blob. if (SkMask::kARGB32_Format == glyph.fMaskFormat) { if (!fallback->isInitialized()) { fallback->init(fFont, fTextRatio); } fallback->appendGlyph(glyph.getGlyphID(), pos); } else { fInstanceData->append(glyph.getGlyphID(), fTextInverseRatio * pos.x(), fTextInverseRatio * pos.y()); } }
void SkLinearGradient:: LinearGradient4fContext::shadeSpanInternal(int x, int y, dstType dst[], int count, float bias0, float bias1) const { SkPoint pt; fDstToPosProc(fDstToPos, x + SK_ScalarHalf, y + SK_ScalarHalf, &pt); const SkScalar fx = pinFx<tileMode>(pt.x()); const SkScalar dx = fDstToPos.getScaleX(); LinearIntervalProcessor<dstType, premul, tileMode> proc(fIntervals->begin(), fIntervals->end() - 1, this->findInterval(fx), fx, dx, SkScalarNearlyZero(dx * count)); Sk4f bias4f0(bias0), bias4f1(bias1); while (count > 0) { // What we really want here is SkTPin(advance, 1, count) // but that's a significant perf hit for >> stops; investigate. const int n = SkScalarTruncToInt( SkTMin<SkScalar>(proc.currentAdvance() + 1, SkIntToScalar(count))); // The current interval advance can be +inf (e.g. when reaching // the clamp mode end intervals) - when that happens, we expect to // a) consume all remaining count in one swoop // b) return a zero color gradient SkASSERT(SkScalarIsFinite(proc.currentAdvance()) || (n == count && proc.currentRampIsZero())); if (proc.currentRampIsZero()) { DstTraits<dstType, premul>::store(proc.currentColor(), dst, n); } else { ramp<dstType, premul>(proc.currentColor(), proc.currentColorGrad(), dst, n, bias4f0, bias4f1); } proc.advance(SkIntToScalar(n)); count -= n; dst += n; if (n & 1) { SkTSwap(bias4f0, bias4f1); } } }
SkPoint WavyPathText::Waves::apply(float tsec, const Sk2f matrix[3], const SkPoint& pt) const { constexpr static int kTablePeriod = 1 << 12; static float sin2table[kTablePeriod + 1]; static SkOnce initTable; initTable([]() { for (int i = 0; i <= kTablePeriod; ++i) { const double sintheta = sin(i * (SK_ScalarPI / kTablePeriod)); sin2table[i] = static_cast<float>(sintheta * sintheta - 0.5); } }); const Sk4f amplitudes = Sk4f::Load(fAmplitudes); const Sk4f frequencies = Sk4f::Load(fFrequencies); const Sk4f dirsX = Sk4f::Load(fDirsX); const Sk4f dirsY = Sk4f::Load(fDirsY); const Sk4f speeds = Sk4f::Load(fSpeeds); const Sk4f offsets = Sk4f::Load(fOffsets); float devicePt[2]; (matrix[0] * pt.x() + matrix[1] * pt.y() + matrix[2]).store(devicePt); const Sk4f t = (frequencies * (dirsX * devicePt[0] + dirsY * devicePt[1]) + speeds * tsec + offsets).abs() * (float(kTablePeriod) / float(SK_ScalarPI)); const Sk4i ipart = SkNx_cast<int>(t); const Sk4f fpart = t - SkNx_cast<float>(ipart); int32_t indices[4]; (ipart & (kTablePeriod-1)).store(indices); const Sk4f left(sin2table[indices[0]], sin2table[indices[1]], sin2table[indices[2]], sin2table[indices[3]]); const Sk4f right(sin2table[indices[0] + 1], sin2table[indices[1] + 1], sin2table[indices[2] + 1], sin2table[indices[3] + 1]); const Sk4f height = amplitudes * (left * (1.f - fpart) + right * fpart); Sk4f dy = height * dirsY; Sk4f dx = height * dirsX; float offsetY[4], offsetX[4]; (dy + SkNx_shuffle<2,3,0,1>(dy)).store(offsetY); // accumulate. (dx + SkNx_shuffle<2,3,0,1>(dx)).store(offsetX);; return {devicePt[0] + offsetY[0] + offsetY[1], devicePt[1] - offsetX[0] - offsetX[1]}; }
virtual void onDraw(SkCanvas* canvas) { SkAutoTUnref<SkData> name(SkData::NewWithCString("target-a")); canvas->save(); canvas->translate(SkIntToScalar(100), SkIntToScalar(100)); drawLabeledRect(canvas, "Link to A", 0, 0); SkRect rect = SkRect::MakeXYWH(0, 0, SkIntToScalar(50), SkIntToScalar(20)); SkAnnotateLinkToDestination(canvas, rect, name.get()); canvas->restore(); canvas->save(); canvas->translate(SkIntToScalar(200), SkIntToScalar(200)); SkPoint point = SkPoint::Make(SkIntToScalar(100), SkIntToScalar(50)); drawLabeledRect(canvas, "Target A", point.x(), point.y()); SkAnnotateNamedDestination(canvas, point, name.get()); canvas->restore(); }
SkPoint drawSet(SkCanvas* canvas, const ImageSet& set, const SkPaint& paint) const { SkASSERT(set.fImages.count() == set.fScales.count()); SkPoint pt = SkPoint::Make(0, 0); for (int i = 0; i < set.fImages.count(); ++i) { auto& img = set.fImages[i]; const SkRect dst = SkRect::MakeXYWH(pt.x(), pt.y(), img->width() * (1 + (set.fScales[i] - 1) * set.fVector.x()), img->height() * (1 + (set.fScales[i] - 1) * set.fVector.y())); canvas->drawImageRect(img.get(), dst, &paint); pt.offset(dst.width() * set.fVector.x(), dst.height() * set.fVector.y()); } return pt; }