void draw(SkCanvas* canvas, const SkRect& rect, const SkSize& deviceSize, SkPaint::FilterLevel filterLevel, SkImageFilter* input = NULL) { SkRect dstRect; canvas->getTotalMatrix().mapRect(&dstRect, rect); canvas->save(); SkScalar deviceScaleX = SkScalarDiv(deviceSize.width(), dstRect.width()); SkScalar deviceScaleY = SkScalarDiv(deviceSize.height(), dstRect.height()); canvas->translate(rect.x(), rect.y()); canvas->scale(deviceScaleX, deviceScaleY); canvas->translate(-rect.x(), -rect.y()); SkMatrix matrix; matrix.setScale(SkScalarInvert(deviceScaleX), SkScalarInvert(deviceScaleY)); SkAutoTUnref<SkImageFilter> imageFilter( SkMatrixImageFilter::Create(matrix, filterLevel, input)); SkPaint filteredPaint; filteredPaint.setImageFilter(imageFilter.get()); canvas->saveLayer(&rect, &filteredPaint); SkPaint paint; paint.setColor(0xFF00FF00); SkRect ovalRect = rect; ovalRect.inset(SkIntToScalar(4), SkIntToScalar(4)); canvas->drawOval(ovalRect, paint); canvas->restore(); // for saveLayer canvas->restore(); }
PaintingData(const SkISize& tileSize, SkScalar seed, SkScalar baseFrequencyX, SkScalar baseFrequencyY, const SkMatrix& matrix) { SkVector wavelength = SkVector::Make(SkScalarInvert(baseFrequencyX), SkScalarInvert(baseFrequencyY)); matrix.mapVectors(&wavelength, 1); fBaseFrequency.fX = SkScalarInvert(wavelength.fX); fBaseFrequency.fY = SkScalarInvert(wavelength.fY); SkVector sizeVec = SkVector::Make(SkIntToScalar(tileSize.fWidth), SkIntToScalar(tileSize.fHeight)); matrix.mapVectors(&sizeVec, 1); fTileSize.fWidth = SkScalarRoundToInt(sizeVec.fX); fTileSize.fHeight = SkScalarRoundToInt(sizeVec.fY); this->init(seed); if (!fTileSize.isEmpty()) { this->stitch(); } #if SK_SUPPORT_GPU fPermutationsBitmap.setInfo(SkImageInfo::MakeA8(kBlockSize, 1)); fPermutationsBitmap.setPixels(fLatticeSelector); fNoiseBitmap.setInfo(SkImageInfo::MakeN32Premul(kBlockSize, 4)); fNoiseBitmap.setPixels(fNoise[0][0]); #endif }
PaintingData(const SkISize& tileSize, SkScalar seed, SkScalar baseFrequencyX, SkScalar baseFrequencyY, const SkMatrix& matrix) { SkVector vec[2] = { { SkScalarInvert(baseFrequencyX), SkScalarInvert(baseFrequencyY) }, { SkIntToScalar(tileSize.fWidth), SkIntToScalar(tileSize.fHeight) }, }; matrix.mapVectors(vec, 2); fBaseFrequency.set(SkScalarInvert(vec[0].fX), SkScalarInvert(vec[0].fY)); fTileSize.set(SkScalarRoundToInt(vec[1].fX), SkScalarRoundToInt(vec[1].fY)); this->init(seed); if (!fTileSize.isEmpty()) { this->stitch(); } #if SK_SUPPORT_GPU fPermutationsBitmap.setInfo(SkImageInfo::MakeA8(kBlockSize, 1)); fPermutationsBitmap.setPixels(fLatticeSelector); fNoiseBitmap.setInfo(SkImageInfo::MakeN32Premul(kBlockSize, 4)); fNoiseBitmap.setPixels(fNoise[0][0]); #endif }
SkTileGrid::SkTileGrid(int xTiles, int yTiles, const SkTileGridFactory::TileGridInfo& info) : fXTiles(xTiles) , fYTiles(yTiles) , fInvWidth( SkScalarInvert(info.fTileInterval.width())) , fInvHeight(SkScalarInvert(info.fTileInterval.height())) , fMarginWidth (info.fMargin.fWidth +1) // Margin is offset by 1 as a provision for AA and , fMarginHeight(info.fMargin.fHeight+1) // to cancel the outset applied by getClipDeviceBounds. , fOffset(SkPoint::Make(info.fOffset.fX, info.fOffset.fY)) , fGridBounds(SkRect::MakeWH(xTiles * info.fTileInterval.width(), yTiles * info.fTileInterval.height())) , fTiles(SkNEW_ARRAY(SkTDArray<unsigned>, xTiles * yTiles)) {}
bool SkPathContainsPoint(SkPath* originalPath, const FloatPoint& point, SkPath::FillType ft) { SkRegion rgn; SkRegion clip; SkPath::FillType originalFillType = originalPath->getFillType(); const SkPath* path = originalPath; SkPath scaledPath; int scale = 1; SkRect bounds; // FIXME: This #ifdef can go away once we're firmly using the new Skia. // During the transition, this makes the code compatible with both versions. #ifdef SK_USE_OLD_255_TO_256 bounds = originalPath->getBounds(); #else originalPath->computeBounds(&bounds, SkPath::kFast_BoundsType); #endif // We can immediately return false if the point is outside the bounding rect if (!bounds.contains(SkFloatToScalar(point.x()), SkFloatToScalar(point.y()))) return false; originalPath->setFillType(ft); // Skia has trouble with coordinates close to the max signed 16-bit values // If we have those, we need to scale. // // TODO: remove this code once Skia is patched to work properly with large // values const SkScalar kMaxCoordinate = SkIntToScalar(1<<15); SkScalar biggestCoord = std::max(std::max(std::max(bounds.fRight, bounds.fBottom), -bounds.fLeft), -bounds.fTop); if (biggestCoord > kMaxCoordinate) { scale = SkScalarCeil(SkScalarDiv(biggestCoord, kMaxCoordinate)); SkMatrix m; m.setScale(SkScalarInvert(SkIntToScalar(scale)), SkScalarInvert(SkIntToScalar(scale))); originalPath->transform(m, &scaledPath); path = &scaledPath; } int x = static_cast<int>(floorf(point.x() / scale)); int y = static_cast<int>(floorf(point.y() / scale)); clip.setRect(x, y, x + 1, y + 1); bool contains = rgn.setPath(*path, clip); originalPath->setFillType(originalFillType); return contains; }
/* * Modulo internal errors, this should always succeed *if* the matrix is downscaling * (in this case, we have the inverse, so it succeeds if fInvMatrix is upscaling) */ bool SkDefaultBitmapControllerState::processMediumRequest(const SkBitmapProvider& provider) { SkASSERT(fQuality <= kMedium_SkFilterQuality); if (fQuality != kMedium_SkFilterQuality) { return false; } // Our default return state is to downgrade the request to Low, w/ or w/o setting fBitmap // to a valid bitmap. fQuality = kLow_SkFilterQuality; SkSize invScaleSize; if (!fInvMatrix.decomposeScale(&invScaleSize, nullptr)) { return false; } SkDestinationSurfaceColorMode colorMode = provider.dstColorSpace() ? SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware : SkDestinationSurfaceColorMode::kLegacy; if (invScaleSize.width() > SK_Scalar1 || invScaleSize.height() > SK_Scalar1) { fCurrMip.reset(SkMipMapCache::FindAndRef(provider.makeCacheDesc(), colorMode)); if (nullptr == fCurrMip.get()) { SkBitmap orig; if (!provider.asBitmap(&orig)) { return false; } fCurrMip.reset(SkMipMapCache::AddAndRef(orig, colorMode)); if (nullptr == fCurrMip.get()) { return false; } } // diagnostic for a crasher... SkASSERT_RELEASE(fCurrMip->data()); const SkSize scale = SkSize::Make(SkScalarInvert(invScaleSize.width()), SkScalarInvert(invScaleSize.height())); SkMipMap::Level level; if (fCurrMip->extractLevel(scale, &level)) { const SkSize& invScaleFixup = level.fScale; fInvMatrix.postScale(invScaleFixup.width(), invScaleFixup.height()); // todo: if we could wrap the fCurrMip in a pixelref, then we could just install // that here, and not need to explicitly track it ourselves. return fResultBitmap.installPixels(level.fPixmap); } else { // failed to extract, so release the mipmap fCurrMip.reset(nullptr); } } return false; }
bool SkPathContainsPoint(SkPath* originalPath, const FloatPoint& point, SkPath::FillType ft) { SkRegion rgn; SkRegion clip; SkPath::FillType originalFillType = originalPath->getFillType(); const SkPath* path = originalPath; SkPath scaledPath; int scale = 1; SkRect bounds = originalPath->getBounds(); // We can immediately return false if the point is outside the bounding // rect. We don't use bounds.contains() here, since it would exclude // points on the right and bottom edges of the bounding rect, and we want // to include them. SkScalar fX = SkFloatToScalar(point.x()); SkScalar fY = SkFloatToScalar(point.y()); if (fX < bounds.fLeft || fX > bounds.fRight || fY < bounds.fTop || fY > bounds.fBottom) return false; originalPath->setFillType(ft); // Skia has trouble with coordinates close to the max signed 16-bit values // If we have those, we need to scale. // // TODO: remove this code once Skia is patched to work properly with large // values const SkScalar kMaxCoordinate = SkIntToScalar(1<<15); SkScalar biggestCoord = std::max(std::max(std::max(bounds.fRight, bounds.fBottom), -bounds.fLeft), -bounds.fTop); if (biggestCoord > kMaxCoordinate) { scale = SkScalarCeil(SkScalarDiv(biggestCoord, kMaxCoordinate)); SkMatrix m; m.setScale(SkScalarInvert(SkIntToScalar(scale)), SkScalarInvert(SkIntToScalar(scale))); originalPath->transform(m, &scaledPath); path = &scaledPath; } int x = static_cast<int>(floorf(point.x() / scale)); int y = static_cast<int>(floorf(point.y() / scale)); clip.setRect(x - 1, y - 1, x + 1, y + 1); bool contains = rgn.setPath(*path, clip); originalPath->setFillType(originalFillType); return contains; }
SkPathStroker::SkPathStroker(const SkPath& src, SkScalar radius, SkScalar miterLimit, SkPaint::Cap cap, SkPaint::Join join) : fRadius(radius) { /* This is only used when join is miter_join, but we initialize it here so that it is always defined, to fis valgrind warnings. */ fInvMiterLimit = 0; if (join == SkPaint::kMiter_Join) { if (miterLimit <= SK_Scalar1) { join = SkPaint::kBevel_Join; } else { fInvMiterLimit = SkScalarInvert(miterLimit); } } fCapper = SkStrokerPriv::CapFactory(cap); fJoiner = SkStrokerPriv::JoinFactory(join); fSegmentCount = -1; fPrevIsLine = false; // Need some estimate of how large our final result (fOuter) // and our per-contour temp (fInner) will be, so we don't spend // extra time repeatedly growing these arrays. // // 3x for result == inner + outer + join (swag) // 1x for inner == 'wag' (worst contour length would be better guess) fOuter.incReserve(src.countPoints() * 3); fInner.incReserve(src.countPoints()); }
void GrColorCubeEffect::GLProcessor::setData(const GrGLProgramDataManager& pdman, const GrProcessor& proc) { const GrColorCubeEffect& colorCube = proc.cast<GrColorCubeEffect>(); SkScalar size = SkIntToScalar(colorCube.colorCubeSize()); pdman.set1f(fColorCubeSizeUni, SkScalarToFloat(size)); pdman.set1f(fColorCubeInvSizeUni, SkScalarToFloat(SkScalarInvert(size))); }
bool SkMagnifierImageFilter::asFragmentProcessor(GrFragmentProcessor** fp, GrProcessorDataManager* procDataManager, GrTexture* texture, const SkMatrix&, const SkIRect&bounds) const { if (fp) { SkScalar yOffset = texture->origin() == kTopLeft_GrSurfaceOrigin ? fSrcRect.y() : texture->height() - fSrcRect.height() * texture->height() / bounds.height() - fSrcRect.y(); int boundsY = (texture->origin() == kTopLeft_GrSurfaceOrigin) ? bounds.y() : (texture->height() - bounds.height()); SkRect effectBounds = SkRect::MakeXYWH( SkIntToScalar(bounds.x()) / texture->width(), SkIntToScalar(boundsY) / texture->height(), SkIntToScalar(texture->width()) / bounds.width(), SkIntToScalar(texture->height()) / bounds.height()); SkScalar invInset = fInset > 0 ? SkScalarInvert(fInset) : SK_Scalar1; *fp = GrMagnifierEffect::Create(procDataManager, texture, effectBounds, fSrcRect.x() / texture->width(), yOffset / texture->height(), fSrcRect.width() / bounds.width(), fSrcRect.height() / bounds.height(), bounds.width() * invInset, bounds.height() * invInset); } return true; }
void SkColorCubeFilter::ColorCubeProcesingCache::initProcessingLuts( SkColorCubeFilter::ColorCubeProcesingCache* cache) { static const SkScalar inv8bit = SkScalarInvert(SkIntToScalar(255)); // We need 256 int * 2 for fColorToIndex, so a total of 512 int. // We need 256 SkScalar * 2 for fColorToFactors and 256 SkScalar // for fColorToScalar, so a total of 768 SkScalar. cache->fLutStorage.reset(512 * sizeof(int) + 768 * sizeof(SkScalar)); uint8_t* storage = (uint8_t*)cache->fLutStorage.get(); cache->fColorToIndex[0] = (int*)storage; cache->fColorToIndex[1] = cache->fColorToIndex[0] + 256; cache->fColorToFactors[0] = (SkScalar*)(storage + (512 * sizeof(int))); cache->fColorToFactors[1] = cache->fColorToFactors[0] + 256; cache->fColorToScalar = cache->fColorToFactors[1] + 256; SkScalar size = SkIntToScalar(cache->fCubeDimension); SkScalar scale = (size - SK_Scalar1) * inv8bit; for (int i = 0; i < 256; ++i) { SkScalar index = scale * i; cache->fColorToIndex[0][i] = SkScalarFloorToInt(index); cache->fColorToIndex[1][i] = cache->fColorToIndex[0][i] + 1; cache->fColorToScalar[i] = inv8bit * i; if (cache->fColorToIndex[1][i] < cache->fCubeDimension) { cache->fColorToFactors[1][i] = index - SkIntToScalar(cache->fColorToIndex[0][i]); cache->fColorToFactors[0][i] = SK_Scalar1 - cache->fColorToFactors[1][i]; } else { cache->fColorToIndex[1][i] = cache->fColorToIndex[0][i]; cache->fColorToFactors[0][i] = SK_Scalar1; cache->fColorToFactors[1][i] = 0; } } }
bool SkBoundaryPatch::evalPatch(SkPoint verts[], int rows, int cols) { if (rows < 2 || cols < 2) { return false; } const SkScalar invR = SkScalarInvert(SkIntToScalar(rows - 1)); const SkScalar invC = SkScalarInvert(SkIntToScalar(cols - 1)); for (int y = 0; y < cols; y++) { SkScalar yy = y * invC; for (int x = 0; x < rows; x++) { *verts++ = this->eval(x * invR, yy); } } return true; }
void onSetData(const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& _proc) override { const GrCircleEffect& _outer = _proc.cast<GrCircleEffect>(); auto edgeType = _outer.edgeType; (void)edgeType; auto center = _outer.center; (void)center; auto radius = _outer.radius; (void)radius; UniformHandle& circle = circleVar; (void)circle; if (radius != prevRadius || center != prevCenter) { SkScalar effectiveRadius = radius; if (GrProcessorEdgeTypeIsInverseFill((GrClipEdgeType)edgeType)) { effectiveRadius -= 0.5f; // When the radius is 0.5 effectiveRadius is 0 which causes an inf * 0 in the // shader. effectiveRadius = SkTMax(0.001f, effectiveRadius); } else { effectiveRadius += 0.5f; } pdman.set4f(circle, center.fX, center.fY, effectiveRadius, SkScalarInvert(effectiveRadius)); prevCenter = center; prevRadius = radius; } }
/* Generate Type 4 function code to map t=[0,1) to the passed gradient, clamping at the edges of the range. The generated code will be of the form: if (t < 0) { return colorData[0][r,g,b]; } else { if (t < info.fColorOffsets[1]) { return linearinterpolation(colorData[0][r,g,b], colorData[1][r,g,b]); } else { if (t < info.fColorOffsets[2]) { return linearinterpolation(colorData[1][r,g,b], colorData[2][r,g,b]); } else { ... } else { return colorData[info.fColorCount - 1][r,g,b]; } ... } } */ static void gradientFunctionCode(const SkShader::GradientInfo& info, SkString* result) { /* We want to linearly interpolate from the previous color to the next. Scale the colors from 0..255 to 0..1 and determine the multipliers for interpolation. C{r,g,b}(t, section) = t - offset_(section-1) + t * Multiplier{r,g,b}. */ static const int kColorComponents = 3; typedef SkScalar ColorTuple[kColorComponents]; SkAutoSTMalloc<4, ColorTuple> colorDataAlloc(info.fColorCount); ColorTuple *colorData = colorDataAlloc.get(); const SkScalar scale = SkScalarInvert(SkIntToScalar(255)); for (int i = 0; i < info.fColorCount; i++) { colorData[i][0] = SkScalarMul(SkColorGetR(info.fColors[i]), scale); colorData[i][1] = SkScalarMul(SkColorGetG(info.fColors[i]), scale); colorData[i][2] = SkScalarMul(SkColorGetB(info.fColors[i]), scale); } // Clamp the initial color. result->append("dup 0 le {pop "); result->appendScalar(colorData[0][0]); result->append(" "); result->appendScalar(colorData[0][1]); result->append(" "); result->appendScalar(colorData[0][2]); result->append(" }\n"); // The gradient colors. int gradients = 0; for (int i = 1 ; i < info.fColorCount; i++) { if (info.fColorOffsets[i] == info.fColorOffsets[i - 1]) { continue; } gradients++; result->append("{dup "); result->appendScalar(info.fColorOffsets[i]); result->append(" le {"); if (info.fColorOffsets[i - 1] != 0) { result->appendScalar(info.fColorOffsets[i - 1]); result->append(" sub\n"); } interpolateColorCode(info.fColorOffsets[i] - info.fColorOffsets[i - 1], colorData[i], colorData[i - 1], result); result->append("}\n"); } // Clamp the final color. result->append("{pop "); result->appendScalar(colorData[info.fColorCount - 1][0]); result->append(" "); result->appendScalar(colorData[info.fColorCount - 1][1]); result->append(" "); result->appendScalar(colorData[info.fColorCount - 1][2]); for (int i = 0 ; i < gradients + 1; i++) { result->append("} ifelse\n"); } }
void computeDisplacement(Extractor ex, const SkVector& scale, SkBitmap* dst, const SkBitmap& displ, const SkIPoint& offset, const SkBitmap& src, const SkIRect& bounds) { static const SkScalar Inv8bit = SkScalarInvert(255); const int srcW = src.width(); const int srcH = src.height(); const SkVector scaleForColor = SkVector::Make(scale.fX * Inv8bit, scale.fY * Inv8bit); const SkVector scaleAdj = SkVector::Make(SK_ScalarHalf - scale.fX * SK_ScalarHalf, SK_ScalarHalf - scale.fY * SK_ScalarHalf); SkPMColor* dstPtr = dst->getAddr32(0, 0); for (int y = bounds.top(); y < bounds.bottom(); ++y) { const SkPMColor* displPtr = displ.getAddr32(bounds.left() + offset.fX, y + offset.fY); for (int x = bounds.left(); x < bounds.right(); ++x, ++displPtr) { SkPMColor c = unpremul_pm(*displPtr); SkScalar displX = scaleForColor.fX * ex.getX(c) + scaleAdj.fX; SkScalar displY = scaleForColor.fY * ex.getY(c) + scaleAdj.fY; // Truncate the displacement values const int32_t srcX = Sk32_sat_add(x, SkScalarTruncToInt(displX)); const int32_t srcY = Sk32_sat_add(y, SkScalarTruncToInt(displY)); *dstPtr++ = ((srcX < 0) || (srcX >= srcW) || (srcY < 0) || (srcY >= srcH)) ? 0 : *(src.getAddr32(srcX, srcY)); } } }
void SkGlyphCache::dump() const { const SkTypeface* face = fScalerContext->getTypeface(); const SkScalerContextRec& rec = fScalerContext->getRec(); SkMatrix matrix; rec.getSingleMatrix(&matrix); matrix.preScale(SkScalarInvert(rec.fTextSize), SkScalarInvert(rec.fTextSize)); SkString name; face->getFamilyName(&name); SkString msg; SkFontStyle style = face->fontStyle(); msg.printf("cache typeface:%x %25s:(%d,%d,%d)\n %s glyphs:%3d", face->uniqueID(), name.c_str(), style.weight(), style.width(), style.slant(), rec.dump().c_str(), fGlyphMap.count()); SkDebugf("%s\n", msg.c_str()); }
static void draw_clipped_filter(SkCanvas* canvas, sk_sp<SkImageFilter> filter, size_t i, const SkRect& primBounds, const SkRect& clipBounds) { SkPaint paint; paint.setColor(SK_ColorWHITE); paint.setImageFilter(std::move(filter)); paint.setAntiAlias(true); canvas->save(); canvas->clipRect(clipBounds); if (5 == i) { canvas->translate(SkIntToScalar(16), SkIntToScalar(-32)); } else if (6 == i) { canvas->scale(SkScalarInvert(RESIZE_FACTOR_X), SkScalarInvert(RESIZE_FACTOR_Y)); } canvas->drawCircle(primBounds.centerX(), primBounds.centerY(), primBounds.width() * 2 / 5, paint); canvas->restore(); }
SkScalar SkSRGBLuminance::fromLuma(SkScalar luma) const { //The magic numbers are derived from the sRGB specification. //See http://www.color.org/chardata/rgb/srgb.xalter . if (luma <= SkFloatToScalar(0.0031308f)) { return luma * SkFloatToScalar(12.92f); } return SkFloatToScalar(1.055f) * SkScalarPow(luma, SkScalarInvert(SkFloatToScalar(2.4f))) - SkFloatToScalar(0.055f); }
void SkGlyphCache::dump() const { const SkTypeface* face = fScalerContext->getTypeface(); const SkScalerContextRec& rec = fScalerContext->getRec(); SkMatrix matrix; rec.getSingleMatrix(&matrix); matrix.preScale(SkScalarInvert(rec.fTextSize), SkScalarInvert(rec.fTextSize)); SkString name; face->getFamilyName(&name); SkString msg; msg.printf("cache typeface:%x %25s:%d size:%2g [%g %g %g %g] lum:%02X devG:%d pntG:%d cntr:%d glyphs:%3d", face->uniqueID(), name.c_str(), face->style(), rec.fTextSize, matrix[SkMatrix::kMScaleX], matrix[SkMatrix::kMSkewX], matrix[SkMatrix::kMSkewY], matrix[SkMatrix::kMScaleY], rec.fLumBits & 0xFF, rec.fDeviceGamma, rec.fPaintGamma, rec.fContrast, fGlyphMap.count()); SkDebugf("%s\n", msg.c_str()); }
static void pts_to_unit_matrix(const SkPoint pts[2], SkMatrix* matrix) { SkVector vec = pts[1] - pts[0]; SkScalar mag = vec.length(); SkScalar inv = mag ? SkScalarInvert(mag) : 0; vec.scale(inv); matrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY); matrix->postTranslate(-pts[0].fX, -pts[0].fY); matrix->postScale(inv, inv); }
SkScalar SkPoint::Normalize(SkPoint* pt) { SkScalar mag = SkPoint::Length(pt->fX, pt->fY); if (mag > SK_ScalarNearlyZero) { SkScalar scale = SkScalarInvert(mag); pt->fX = SkScalarMul(pt->fX, scale); pt->fY = SkScalarMul(pt->fY, scale); return mag; } return 0; }
SkScalar fromLuma(SkScalar SkDEBUGCODE(gamma), SkScalar luma) const override { SkASSERT(0 == gamma); //The magic numbers are derived from the sRGB specification. //See http://www.color.org/chardata/rgb/srgb.xalter . if (luma <= 0.0031308f) { return luma * 12.92f; } return 1.055f * SkScalarPow(luma, SkScalarInvert(2.4f)) - 0.055f; }
static void unitToPointsMatrix(const SkPoint pts[2], SkMatrix* matrix) { SkVector vec = pts[1] - pts[0]; SkScalar mag = vec.length(); SkScalar inv = mag ? SkScalarInvert(mag) : 0; vec.scale(inv); matrix->setSinCos(vec.fY, vec.fX); matrix->preTranslate(pts[0].fX, pts[0].fY); matrix->preScale(mag, mag); }
SkScalar SkPoint::Normalize(SkPoint* pt) { Sk64 mag2; if (!isLengthNearlyZero(pt->fX, pt->fY, &mag2)) { SkScalar mag = mag2.getSqrt(); SkScalar scale = SkScalarInvert(mag); pt->fX = SkScalarMul(pt->fX, scale); pt->fY = SkScalarMul(pt->fY, scale); return mag; } return 0; }
static SkMatrix pts_to_unit_matrix(const SkPoint pts[2]) { SkVector vec = pts[1] - pts[0]; SkScalar mag = vec.length(); SkScalar inv = mag ? SkScalarInvert(mag) : 0; vec.scale(inv); SkMatrix matrix; matrix.setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY); matrix.postTranslate(-pts[0].fX, -pts[0].fY); matrix.postScale(inv, inv); return matrix; }
void onDraw(SkCanvas* canvas) override { // There's a black pixel at 40, 40 for reference. canvas->drawPoint(40.0f, 40.0f, SK_ColorBLACK); // Two reference images. canvas->translate(50.0f, 50.0f); drawTestCase(canvas, 1.0f); canvas->translate(0.0f, 50.0f); drawTestCase(canvas, 3.0f); // Uniform scaling test. canvas->translate(0.0f, 100.0f); canvas->save(); canvas->scale(3.0f, 3.0f); drawTestCase(canvas, 1.0f); canvas->restore(); // Non-uniform scaling test. canvas->translate(0.0f, 100.0f); canvas->save(); canvas->scale(3.0f, 6.0f); drawTestCase(canvas, 1.0f); canvas->restore(); // Skew test. canvas->translate(0.0f, 80.0f); canvas->save(); canvas->scale(3.0f, 3.0f); SkMatrix skew; skew.setIdentity(); skew.setSkewX(8.0f / 25.0f); skew.setSkewY(2.0f / 25.0f); canvas->concat(skew); drawTestCase(canvas, 1.0f); canvas->restore(); // Perspective test. canvas->translate(0.0f, 80.0f); canvas->save(); SkMatrix perspective; perspective.setIdentity(); perspective.setPerspX(-SkScalarInvert(340)); perspective.setSkewX(8.0f / 25.0f); perspective.setSkewY(2.0f / 25.0f); canvas->concat(perspective); drawTestCase(canvas, 1.0f); canvas->restore(); }
/* * Modulo internal errors, this should always succeed *if* the matrix is downscaling * (in this case, we have the inverse, so it succeeds if fInvMatrix is upscaling) */ bool SkDefaultBitmapControllerState::processMediumRequest(const SkBitmapProvider& provider) { SkASSERT(fQuality <= kMedium_SkFilterQuality); if (fQuality != kMedium_SkFilterQuality) { return false; } // Our default return state is to downgrade the request to Low, w/ or w/o setting fBitmap // to a valid bitmap. fQuality = kLow_SkFilterQuality; SkSize invScaleSize; if (!fInvMatrix.decomposeScale(&invScaleSize, nullptr)) { return false; } // Use the largest (non-inverse) scale, to ensure anisotropic consistency. SkASSERT(invScaleSize.width() >= 0 && invScaleSize.height() >= 0); const SkScalar invScale = SkTMin(invScaleSize.width(), invScaleSize.height()); if (invScale > SK_Scalar1) { fCurrMip.reset(SkMipMapCache::FindAndRef(provider.makeCacheDesc())); if (nullptr == fCurrMip.get()) { SkBitmap orig; if (!provider.asBitmap(&orig)) { return false; } fCurrMip.reset(SkMipMapCache::AddAndRef(orig)); if (nullptr == fCurrMip.get()) { return false; } } // diagnostic for a crasher... if (nullptr == fCurrMip->data()) { sk_throw(); } SkScalar levelScale = SkScalarInvert(invScale); SkMipMap::Level level; if (fCurrMip->extractLevel(levelScale, &level)) { const SkSize& invScaleFixup = level.fScale; fInvMatrix.postScale(invScaleFixup.width(), invScaleFixup.height()); // todo: if we could wrap the fCurrMip in a pixelref, then we could just install // that here, and not need to explicitly track it ourselves. return fResultBitmap.installPixels(level.fPixmap); } else { // failed to extract, so release the mipmap fCurrMip.reset(nullptr); } } return false; }
// calculates the rotation needed to aligned pts to the x axis with pts[0] < pts[1] // Stores the rotation matrix in rotMatrix, and the mapped points in ptsRot static void align_to_x_axis(const SkPoint pts[2], SkMatrix* rotMatrix, SkPoint ptsRot[2] = NULL) { SkVector vec = pts[1] - pts[0]; SkScalar mag = vec.length(); SkScalar inv = mag ? SkScalarInvert(mag) : 0; vec.scale(inv); rotMatrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY); if (ptsRot) { rotMatrix->mapPoints(ptsRot, pts, 2); // correction for numerical issues if map doesn't make ptsRot exactly horizontal ptsRot[1].fY = pts[0].fY; } }
/* Assumes t + startOffset is on the stack and does a linear interpolation on t between startOffset and endOffset from prevColor to curColor (for each color component), leaving the result in component order on the stack. It assumes there are always 3 components per color. @param range endOffset - startOffset @param curColor[components] The current color components. @param prevColor[components] The previous color components. @param result The result ps function. */ static void interpolate_color_code(SkScalar range, const ColorTuple& curColor, const ColorTuple& prevColor, SkDynamicMemoryWStream* result) { SkASSERT(range != SkIntToScalar(0)); // Figure out how to scale each color component. SkScalar multiplier[kColorComponents]; for (int i = 0; i < kColorComponents; i++) { static const SkScalar kColorScale = SkScalarInvert(255); multiplier[i] = kColorScale * (curColor[i] - prevColor[i]) / range; } // Calculate when we no longer need to keep a copy of the input parameter t. // If the last component to use t is i, then dupInput[0..i - 1] = true // and dupInput[i .. components] = false. bool dupInput[kColorComponents]; dupInput[kColorComponents - 1] = false; for (int i = kColorComponents - 2; i >= 0; i--) { dupInput[i] = dupInput[i + 1] || multiplier[i + 1] != 0; } if (!dupInput[0] && multiplier[0] == 0) { result->writeText("pop "); } for (int i = 0; i < kColorComponents; i++) { // If the next components needs t and this component will consume a // copy, make another copy. if (dupInput[i] && multiplier[i] != 0) { result->writeText("dup "); } if (multiplier[i] == 0) { SkPDFUtils::AppendColorComponent(prevColor[i], result); result->writeText(" "); } else { if (multiplier[i] != 1) { SkPDFUtils::AppendScalar(multiplier[i], result); result->writeText(" mul "); } if (prevColor[i] != 0) { SkPDFUtils::AppendColorComponent(prevColor[i], result); result->writeText(" add "); } } if (dupInput[i]) { result->writeText("exch\n"); } } }
void GLCircleEffect::onSetData(const GrGLProgramDataManager& pdman, const GrProcessor& processor) { const CircleEffect& ce = processor.cast<CircleEffect>(); if (ce.getRadius() != fPrevRadius || ce.getCenter() != fPrevCenter) { SkScalar radius = ce.getRadius(); if (GrProcessorEdgeTypeIsInverseFill(ce.getEdgeType())) { radius -= 0.5f; } else { radius += 0.5f; } pdman.set4f(fCircleUniform, ce.getCenter().fX, ce.getCenter().fY, radius, SkScalarInvert(radius)); fPrevCenter = ce.getCenter(); fPrevRadius = ce.getRadius(); } }