/* * Copyright 2023 Google LLC * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * * This file contains implementations of SkPixmap methods which require the CPU backend. */ #include "include/core/SkAlphaType.h" #include "include/core/SkBitmap.h" #include "include/core/SkBlendMode.h" #include "include/core/SkCanvas.h" #include "include/core/SkColor.h" #include "include/core/SkImageInfo.h" #include "include/core/SkMatrix.h" #include "include/core/SkPaint.h" #include "include/core/SkPixmap.h" #include "include/core/SkRect.h" #include "include/core/SkRefCnt.h" #include "include/core/SkShader.h" #include "include/core/SkSurface.h" #include "include/core/SkTileMode.h" #include "src/core/SkDraw.h" #include "src/core/SkMatrixProvider.h" #include "src/core/SkRasterClip.h" #include "src/shaders/SkImageShader.h" #include class SkColorSpace; struct SkSamplingOptions; bool SkPixmap::erase(SkColor color, const SkIRect& subset) const { return this->erase(SkColor4f::FromColor(color), &subset); } bool SkPixmap::erase(const SkColor4f& color, SkColorSpace* cs, const SkIRect* subset) const { SkPaint paint; paint.setBlendMode(SkBlendMode::kSrc); paint.setColor4f(color, cs); SkIRect clip = this->bounds(); if (subset && !clip.intersect(*subset)) { return false; } SkRasterClip rc{clip}; SkDraw draw; SkMatrixProvider matrixProvider(SkMatrix::I()); draw.fDst = *this; draw.fMatrixProvider = &matrixProvider; draw.fRC = &rc; draw.drawPaint(paint); return true; } bool SkPixmap::scalePixels(const SkPixmap& actualDst, const SkSamplingOptions& sampling) const { // We may need to tweak how we interpret these just a little below, so we make copies. SkPixmap src = *this, dst = actualDst; // Can't do anthing with empty src or dst if (src.width() <= 0 || src.height() <= 0 || dst.width() <= 0 || dst.height() <= 0) { return false; } // no scaling involved? if (src.width() == dst.width() && src.height() == dst.height()) { return src.readPixels(dst); } // If src and dst are both unpremul, we'll fake the source out to appear as if premul, // and mark the destination as opaque. This odd combination allows us to scale unpremul // pixels without ever premultiplying them (perhaps losing information in the color channels). // This is an idiosyncratic feature of scalePixels(), and is tested by scalepixels_unpremul GM. bool clampAsIfUnpremul = false; if (src.alphaType() == kUnpremul_SkAlphaType && dst.alphaType() == kUnpremul_SkAlphaType) { src.reset(src.info().makeAlphaType(kPremul_SkAlphaType), src.addr(), src.rowBytes()); dst.reset(dst.info().makeAlphaType(kOpaque_SkAlphaType), dst.addr(), dst.rowBytes()); // We'll need to tell the image shader to clamp to [0,1] instead of the // usual [0,a] when using a bicubic scaling (kHigh_SkFilterQuality). clampAsIfUnpremul = true; } SkBitmap bitmap; if (!bitmap.installPixels(src)) { return false; } bitmap.setImmutable(); // Don't copy when we create an image. SkMatrix scale = SkMatrix::RectToRect(SkRect::Make(src.bounds()), SkRect::Make(dst.bounds())); sk_sp shader = SkImageShader::Make(bitmap.asImage(), SkTileMode::kClamp, SkTileMode::kClamp, sampling, &scale, clampAsIfUnpremul); sk_sp surface = SkSurface::MakeRasterDirect(dst.info(), dst.writable_addr(), dst.rowBytes()); if (!shader || !surface) { return false; } SkPaint paint; paint.setBlendMode(SkBlendMode::kSrc); paint.setShader(std::move(shader)); surface->getCanvas()->drawPaint(paint); return true; }