| /* | |
| * Copyright 2023 Google LLC | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "src/image/SkImage_Picture.h" | |
| #include "include/core/SkCanvas.h" | |
| #include "include/core/SkColor.h" | |
| #include "include/core/SkColorSpace.h" | |
| #include "include/core/SkColorType.h" | |
| #include "include/core/SkImage.h" | |
| #include "include/core/SkImageGenerator.h" | |
| #include "include/core/SkImageInfo.h" | |
| #include "include/core/SkMatrix.h" | |
| #include "include/core/SkPicture.h" | |
| #include "include/core/SkRect.h" | |
| #include "include/core/SkSurfaceProps.h" | |
| #include "include/private/SkAssert.h" | |
| #include "include/private/SkMutex.h" | |
| #include "include/private/SkTFitsIn.h" | |
| #include "src/core/SkTLazy.h" | |
| #include "src/image/SkImageGeneratorPriv.h" | |
| #include "src/image/SkImage_Lazy.h" | |
| #include "src/image/SkPictureImageGenerator.h" | |
| #include <cstring> | |
| #include <memory> | |
| #include <utility> | |
| class SkPaint; | |
| struct SkISize; | |
| sk_sp<SkImage> SkImage_Picture::Make(sk_sp<SkPicture> picture, const SkISize& dimensions, | |
| const SkMatrix* matrix, const SkPaint* paint, | |
| SkImages::BitDepth bitDepth, sk_sp<SkColorSpace> colorSpace, | |
| SkSurfaceProps props) { | |
| auto gen = SkImageGenerators::MakeFromPicture(dimensions, std::move(picture), matrix, paint, | |
| bitDepth, std::move(colorSpace), props); | |
| SkImage_Lazy::Validator validator( | |
| SharedGenerator::Make(std::move(gen)), nullptr, nullptr); | |
| return validator ? sk_make_sp<SkImage_Picture>(&validator) : nullptr; | |
| } | |
| const SkSurfaceProps* SkImage_Picture::props() const { | |
| auto pictureIG = static_cast<SkPictureImageGenerator*>(this->generator()->fGenerator.get()); | |
| return &pictureIG->fProps; | |
| } | |
| void SkImage_Picture::replay(SkCanvas* canvas) const { | |
| auto sharedGenerator = this->generator(); | |
| SkAutoMutexExclusive mutex(sharedGenerator->fMutex); | |
| auto pictureIG = static_cast<SkPictureImageGenerator*>(sharedGenerator->fGenerator.get()); | |
| canvas->clear(SkColors::kTransparent); | |
| canvas->drawPicture(pictureIG->fPicture, | |
| &pictureIG->fMatrix, | |
| SkOptAddressOrNull(pictureIG->fPaint)); | |
| } | |
| sk_sp<SkImage> SkImage_Picture::onMakeSubset(SkRecorder*, | |
| const SkIRect& subset, | |
| RequiredProperties) const { | |
| auto sharedGenerator = this->generator(); | |
| auto pictureIG = static_cast<SkPictureImageGenerator*>(sharedGenerator->fGenerator.get()); | |
| SkMatrix matrix = pictureIG->fMatrix; | |
| matrix.postTranslate(-subset.left(), -subset.top()); | |
| SkImages::BitDepth bitDepth = | |
| this->colorType() == kRGBA_F16_SkColorType ? SkImages::BitDepth::kF16 | |
| : SkImages::BitDepth::kU8; | |
| return SkImage_Picture::Make(pictureIG->fPicture, subset.size(), | |
| &matrix, SkOptAddressOrNull(pictureIG->fPaint), | |
| bitDepth, this->refColorSpace(), pictureIG->fProps); | |
| } | |
| bool SkImage_Picture::getImageKeyValues( | |
| uint32_t keyValues[SkTiledImageUtils::kNumImageKeyValues]) const { | |
| auto sharedGenerator = this->generator(); | |
| SkAutoMutexExclusive mutex(sharedGenerator->fMutex); | |
| auto pictureIG = static_cast<SkPictureImageGenerator*>(sharedGenerator->fGenerator.get()); | |
| if (pictureIG->fPaint.has_value()) { | |
| // A full paint complicates the potential key too much. | |
| return false; | |
| } | |
| const SkImageInfo& ii = sharedGenerator->getInfo(); | |
| if (!ii.colorSpace()->isSRGB()) { | |
| // We only return key values if the colorSpace is sRGB. | |
| return false; | |
| } | |
| const SkMatrix& m = pictureIG->fMatrix; | |
| if (!m.isIdentity() && !m.isTranslate()) { | |
| // To keep the key small we only cache simple (<= translation) matrices | |
| return false; | |
| } | |
| bool isU8 = ii.colorType() != kRGBA_F16_SkColorType; | |
| uint32_t pixelGeometry = this->props()->pixelGeometry(); | |
| uint32_t surfacePropFlags = this->props()->flags(); | |
| int width = ii.width(); | |
| int height = ii.height(); | |
| float transX = m.getTranslateX(); | |
| float transY = m.getTranslateY(); | |
| SkASSERT(pixelGeometry <= 4); | |
| SkASSERT(surfacePropFlags < 8); | |
| SkASSERT(SkTFitsIn<uint32_t>(width)); | |
| SkASSERT(SkTFitsIn<uint32_t>(height)); | |
| SkASSERT(sizeof(float) == sizeof(uint32_t)); | |
| // The 0th slot usually holds either the SkBitmap's ID or the image's. In those two cases | |
| // slot #1 is zero so we can reuse the 0th slot here. | |
| keyValues[0] = (isU8 ? 0x1 : 0x0) | // 1 bit | |
| (pixelGeometry << 1) | // 3 bits | |
| (surfacePropFlags << 4); // 3 bits | |
| keyValues[1] = pictureIG->fPicture->uniqueID(); | |
| SkASSERT(keyValues[1] != 0); // Double check we don't collide w/ bitmap or image keys | |
| keyValues[2] = width; | |
| keyValues[3] = height; | |
| memcpy(&keyValues[4], &transX, sizeof(uint32_t)); | |
| memcpy(&keyValues[5], &transY, sizeof(uint32_t)); | |
| return true; | |
| } |