| // Copyright 2013 The Flutter Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "flutter/flow/layers/offscreen_surface.h" | 
 |  | 
 | #include "third_party/skia/include/core/SkColorSpace.h" | 
 | #include "third_party/skia/include/core/SkData.h" | 
 | #include "third_party/skia/include/core/SkImage.h" | 
 | #include "third_party/skia/include/core/SkImageInfo.h" | 
 | #include "third_party/skia/include/core/SkPixmap.h" | 
 | #include "third_party/skia/include/encode/SkPngEncoder.h" | 
 | #include "third_party/skia/include/gpu/GrDirectContext.h" | 
 | #include "third_party/skia/include/gpu/ganesh/SkSurfaceGanesh.h" | 
 |  | 
 | namespace flutter { | 
 |  | 
 | static sk_sp<SkSurface> CreateSnapshotSurface(GrDirectContext* surface_context, | 
 |                                               const SkISize& size) { | 
 |   const auto image_info = SkImageInfo::MakeN32Premul( | 
 |       size.width(), size.height(), SkColorSpace::MakeSRGB()); | 
 |   if (surface_context) { | 
 |     // There is a rendering surface that may contain textures that are going to | 
 |     // be referenced in the layer tree about to be drawn. | 
 |     return SkSurfaces::RenderTarget(surface_context, skgpu::Budgeted::kNo, | 
 |                                     image_info); | 
 |   } | 
 |  | 
 |   // There is no rendering surface, assume no GPU textures are present and | 
 |   // create a raster surface. | 
 |   return SkSurfaces::Raster(image_info); | 
 | } | 
 |  | 
 | /// Returns a buffer containing a snapshot of the surface. | 
 | /// | 
 | /// If compressed is true the data is encoded as PNG. | 
 | static sk_sp<SkData> GetRasterData(const sk_sp<SkSurface>& offscreen_surface, | 
 |                                    bool compressed) { | 
 |   // Prepare an image from the surface, this image may potentially be on th GPU. | 
 |   auto potentially_gpu_snapshot = offscreen_surface->makeImageSnapshot(); | 
 |   if (!potentially_gpu_snapshot) { | 
 |     FML_LOG(ERROR) << "Screenshot: unable to make image screenshot"; | 
 |     return nullptr; | 
 |   } | 
 |  | 
 |   // Copy the GPU image snapshot into CPU memory. | 
 |   // TODO (https://github.com/flutter/flutter/issues/13498) | 
 |   auto cpu_snapshot = potentially_gpu_snapshot->makeRasterImage(); | 
 |   if (!cpu_snapshot) { | 
 |     FML_LOG(ERROR) << "Screenshot: unable to make raster image"; | 
 |     return nullptr; | 
 |   } | 
 |  | 
 |   // If the caller want the pixels to be compressed, there is a Skia utility to | 
 |   // compress to PNG. Use that. | 
 |   if (compressed) { | 
 |     return SkPngEncoder::Encode(nullptr, cpu_snapshot.get(), {}); | 
 |   } | 
 |  | 
 |   // Copy it into a bitmap and return the same. | 
 |   SkPixmap pixmap; | 
 |   if (!cpu_snapshot->peekPixels(&pixmap)) { | 
 |     FML_LOG(ERROR) << "Screenshot: unable to obtain bitmap pixels"; | 
 |     return nullptr; | 
 |   } | 
 |   return SkData::MakeWithCopy(pixmap.addr32(), pixmap.computeByteSize()); | 
 | } | 
 |  | 
 | OffscreenSurface::OffscreenSurface(GrDirectContext* surface_context, | 
 |                                    const SkISize& size) { | 
 |   offscreen_surface_ = CreateSnapshotSurface(surface_context, size); | 
 |   if (offscreen_surface_) { | 
 |     adapter_.set_canvas(offscreen_surface_->getCanvas()); | 
 |   } | 
 | } | 
 |  | 
 | sk_sp<SkData> OffscreenSurface::GetRasterData(bool compressed) const { | 
 |   return flutter::GetRasterData(offscreen_surface_, compressed); | 
 | } | 
 |  | 
 | DlCanvas* OffscreenSurface::GetCanvas() { | 
 |   return &adapter_; | 
 | } | 
 |  | 
 | bool OffscreenSurface::IsValid() const { | 
 |   return offscreen_surface_ != nullptr; | 
 | } | 
 |  | 
 | }  // namespace flutter |